summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/ABI/stable/sysfs-class-ubi212
-rw-r--r--Documentation/DocBook/Makefile5
-rw-r--r--Documentation/DocBook/kernel-api.tmpl56
-rw-r--r--Documentation/HOWTO30
-rw-r--r--Documentation/arm/Samsung-S3C24XX/NAND.txt30
-rw-r--r--Documentation/arm/Samsung-S3C24XX/Overview.txt2
-rw-r--r--Documentation/device-mapper/dm-crypt.txt52
-rw-r--r--Documentation/dontdiff2
-rw-r--r--Documentation/fb/gxfb.txt52
-rw-r--r--Documentation/fb/intelfb.txt2
-rw-r--r--Documentation/fb/lxfb.txt52
-rw-r--r--Documentation/fb/metronomefb.txt16
-rw-r--r--Documentation/fb/modedb.txt4
-rw-r--r--Documentation/feature-removal-schedule.txt9
-rw-r--r--Documentation/filesystems/Locking3
-rw-r--r--Documentation/filesystems/nfs-rdma.txt14
-rw-r--r--Documentation/filesystems/seq_file.txt19
-rw-r--r--Documentation/filesystems/tmpfs.txt12
-rw-r--r--Documentation/filesystems/vfat.txt15
-rw-r--r--Documentation/gpio.txt10
-rw-r--r--Documentation/i386/boot.txt26
-rw-r--r--Documentation/ia64/kvm.txt82
-rw-r--r--Documentation/ide/ide-tape.txt211
-rw-r--r--Documentation/ide/ide.txt107
-rw-r--r--Documentation/ioctl-number.txt2
-rw-r--r--Documentation/kbuild/kconfig-language.txt17
-rw-r--r--Documentation/kbuild/modules.txt9
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--Documentation/kprobes.txt51
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt139
-rw-r--r--Documentation/leds-class.txt12
-rw-r--r--Documentation/md.txt6
-rw-r--r--Documentation/mips/AU1xxx_IDE.README46
-rw-r--r--Documentation/networking/phy.txt38
-rw-r--r--Documentation/powerpc/booting-without-of.txt44
-rw-r--r--Documentation/powerpc/kvm_440.txt41
-rw-r--r--Documentation/s390/kvm.txt125
-rw-r--r--Documentation/smart-config.txt98
-rw-r--r--Documentation/spi/spidev168
-rw-r--r--Documentation/spi/spidev_fdx.c158
-rw-r--r--Documentation/thermal/sysfs-api.txt33
-rw-r--r--Documentation/usb/anchors.txt50
-rw-r--r--Documentation/usb/callbacks.txt132
-rw-r--r--Documentation/usb/persist.txt43
-rw-r--r--Documentation/usb/usb-serial.txt7
-rw-r--r--Documentation/vm/numa_memory_policy.txt281
-rw-r--r--Documentation/vm/slabinfo.c27
-rw-r--r--Kbuild62
-rw-r--r--MAINTAINERS59
-rw-r--r--Makefile36
-rw-r--r--arch/alpha/kernel/core_marvel.c6
-rw-r--r--arch/alpha/kernel/core_t2.c24
-rw-r--r--arch/alpha/kernel/core_titan.c34
-rw-r--r--arch/alpha/kernel/core_tsunami.c28
-rw-r--r--arch/alpha/kernel/module.c6
-rw-r--r--arch/alpha/kernel/pci.c2
-rw-r--r--arch/alpha/kernel/pci_iommu.c34
-rw-r--r--arch/alpha/kernel/smp.c4
-rw-r--r--arch/alpha/kernel/srm_env.c2
-rw-r--r--arch/alpha/kernel/sys_alcor.c2
-rw-r--r--arch/alpha/kernel/sys_marvel.c12
-rw-r--r--arch/alpha/kernel/sys_sable.c6
-rw-r--r--arch/alpha/kernel/sys_sio.c2
-rw-r--r--arch/alpha/kernel/traps.c5
-rw-r--r--arch/arm/Kconfig15
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c11
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c14
-rw-r--r--arch/avr32/kernel/setup.c2
-rw-r--r--arch/cris/mm/init.c1
-rw-r--r--arch/frv/kernel/pm.c8
-rw-r--r--arch/frv/kernel/traps.c31
-rw-r--r--arch/ia64/Kconfig3
-rw-r--r--arch/ia64/Makefile1
-rw-r--r--arch/ia64/kvm/Kconfig49
-rw-r--r--arch/ia64/kvm/Makefile58
-rw-r--r--arch/ia64/kvm/asm-offsets.c251
-rw-r--r--arch/ia64/kvm/kvm-ia64.c1806
-rw-r--r--arch/ia64/kvm/kvm_fw.c500
-rw-r--r--arch/ia64/kvm/kvm_minstate.h273
-rw-r--r--arch/ia64/kvm/lapic.h25
-rw-r--r--arch/ia64/kvm/misc.h93
-rw-r--r--arch/ia64/kvm/mmio.c341
-rw-r--r--arch/ia64/kvm/optvfault.S918
-rw-r--r--arch/ia64/kvm/process.c970
-rw-r--r--arch/ia64/kvm/trampoline.S1038
-rw-r--r--arch/ia64/kvm/vcpu.c2163
-rw-r--r--arch/ia64/kvm/vcpu.h740
-rw-r--r--arch/ia64/kvm/vmm.c66
-rw-r--r--arch/ia64/kvm/vmm_ivt.S1424
-rw-r--r--arch/ia64/kvm/vti.h290
-rw-r--r--arch/ia64/kvm/vtlb.c636
-rw-r--r--arch/ia64/mm/init.c9
-rw-r--r--arch/m68k/kernel/ints.c10
-rw-r--r--arch/m68k/mac/oss.c4
-rw-r--r--arch/m68k/mm/init.c1
-rw-r--r--arch/m68k/q40/q40ints.c2
-rw-r--r--arch/mips/Kconfig38
-rw-r--r--arch/mips/Kconfig.debug10
-rw-r--r--arch/mips/Makefile12
-rw-r--r--arch/mips/au1000/common/cputable.c5
-rw-r--r--arch/mips/au1000/common/dbdma.c6
-rw-r--r--arch/mips/au1000/common/dbg_io.c6
-rw-r--r--arch/mips/au1000/common/dma.c5
-rw-r--r--arch/mips/au1000/common/gpio.c5
-rw-r--r--arch/mips/au1000/common/irq.c8
-rw-r--r--arch/mips/au1000/common/pci.c2
-rw-r--r--arch/mips/au1000/common/platform.c117
-rw-r--r--arch/mips/au1000/common/power.c46
-rw-r--r--arch/mips/au1000/common/prom.c2
-rw-r--r--arch/mips/au1000/common/puts.c1
-rw-r--r--arch/mips/au1000/common/reset.c8
-rw-r--r--arch/mips/au1000/common/setup.c11
-rw-r--r--arch/mips/au1000/common/sleeper.S2
-rw-r--r--arch/mips/au1000/common/time.c35
-rw-r--r--arch/mips/au1000/db1x00/board_setup.c15
-rw-r--r--arch/mips/au1000/db1x00/init.c5
-rw-r--r--arch/mips/au1000/db1x00/irqmap.c19
-rw-r--r--arch/mips/au1000/mtx-1/board_setup.c12
-rw-r--r--arch/mips/au1000/mtx-1/init.c6
-rw-r--r--arch/mips/au1000/mtx-1/irqmap.c19
-rw-r--r--arch/mips/au1000/mtx-1/platform.c1
-rw-r--r--arch/mips/au1000/pb1000/board_setup.c11
-rw-r--r--arch/mips/au1000/pb1000/init.c6
-rw-r--r--arch/mips/au1000/pb1000/irqmap.c18
-rw-r--r--arch/mips/au1000/pb1100/board_setup.c11
-rw-r--r--arch/mips/au1000/pb1100/init.c6
-rw-r--r--arch/mips/au1000/pb1100/irqmap.c19
-rw-r--r--arch/mips/au1000/pb1200/Makefile1
-rw-r--r--arch/mips/au1000/pb1200/board_setup.c20
-rw-r--r--arch/mips/au1000/pb1200/init.c6
-rw-r--r--arch/mips/au1000/pb1200/irqmap.c20
-rw-r--r--arch/mips/au1000/pb1200/platform.c84
-rw-r--r--arch/mips/au1000/pb1500/board_setup.c11
-rw-r--r--arch/mips/au1000/pb1500/init.c6
-rw-r--r--arch/mips/au1000/pb1500/irqmap.c19
-rw-r--r--arch/mips/au1000/pb1550/board_setup.c13
-rw-r--r--arch/mips/au1000/pb1550/init.c6
-rw-r--r--arch/mips/au1000/pb1550/irqmap.c19
-rw-r--r--arch/mips/au1000/xxs1500/board_setup.c11
-rw-r--r--arch/mips/au1000/xxs1500/init.c6
-rw-r--r--arch/mips/au1000/xxs1500/irqmap.c19
-rw-r--r--arch/mips/configs/mipssim_defconfig1
-rw-r--r--arch/mips/configs/pnx8550-jbs_defconfig1
-rw-r--r--arch/mips/configs/pnx8550-stb810_defconfig1
-rw-r--r--arch/mips/dec/time.c71
-rw-r--r--arch/mips/jmr3927/rbhma3100/setup.c11
-rw-r--r--arch/mips/kernel/Makefile8
-rw-r--r--arch/mips/kernel/asm-offsets.c404
-rw-r--r--arch/mips/kernel/cevt-ds1287.c129
-rw-r--r--arch/mips/kernel/cevt-gt641xx.c2
-rw-r--r--arch/mips/kernel/cpu-probe.c21
-rw-r--r--arch/mips/kernel/csrc-ioasic.c65
-rw-r--r--arch/mips/kernel/gpio_txx9.c87
-rw-r--r--arch/mips/kernel/irq-gic.c295
-rw-r--r--arch/mips/kernel/irq-msc01.c10
-rw-r--r--arch/mips/kernel/signal-common.h2
-rw-r--r--arch/mips/kernel/smp-cmp.c265
-rw-r--r--arch/mips/kernel/smp-mt.c143
-rw-r--r--arch/mips/kernel/smp.c4
-rw-r--r--arch/mips/kernel/smtc.c11
-rw-r--r--arch/mips/kernel/spram.c221
-rw-r--r--arch/mips/kernel/sync-r4k.c159
-rw-r--r--arch/mips/kernel/time.c5
-rw-r--r--arch/mips/kernel/traps.c213
-rw-r--r--arch/mips/math-emu/ieee754dp.h2
-rw-r--r--arch/mips/math-emu/ieee754sp.h2
-rw-r--r--arch/mips/mips-boards/generic/Makefile1
-rw-r--r--arch/mips/mips-boards/generic/amon.c80
-rw-r--r--arch/mips/mips-boards/generic/init.c23
-rw-r--r--arch/mips/mips-boards/generic/memory.c4
-rw-r--r--arch/mips/mips-boards/generic/time.c31
-rw-r--r--arch/mips/mips-boards/malta/Makefile1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c354
-rw-r--r--arch/mips/mips-boards/malta/malta_setup.c10
-rw-r--r--arch/mips/mipssim/sim_setup.c6
-rw-r--r--arch/mips/mm/Makefile37
-rw-r--r--arch/mips/mm/c-r4k.c62
-rw-r--r--arch/mips/mm/cache.c31
-rw-r--r--arch/mips/mm/init.c11
-rw-r--r--arch/mips/mm/page.c684
-rw-r--r--arch/mips/mm/pg-r4k.c534
-rw-r--r--arch/mips/mm/pg-sb1.c302
-rw-r--r--arch/mips/mm/pgtable.c1
-rw-r--r--arch/mips/mm/tlb-r4k.c2
-rw-r--r--arch/mips/mm/uasm.c26
-rw-r--r--arch/mips/mm/uasm.h4
-rw-r--r--arch/mips/nxp/pnx8550/common/Makefile (renamed from arch/mips/philips/pnx8550/common/Makefile)0
-rw-r--r--arch/mips/nxp/pnx8550/common/gdb_hook.c (renamed from arch/mips/philips/pnx8550/common/gdb_hook.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/int.c (renamed from arch/mips/philips/pnx8550/common/int.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/pci.c (renamed from arch/mips/philips/pnx8550/common/pci.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/platform.c (renamed from arch/mips/philips/pnx8550/common/platform.c)2
-rw-r--r--arch/mips/nxp/pnx8550/common/proc.c (renamed from arch/mips/philips/pnx8550/common/proc.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/prom.c (renamed from arch/mips/philips/pnx8550/common/prom.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/reset.c (renamed from arch/mips/philips/pnx8550/common/reset.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/setup.c (renamed from arch/mips/philips/pnx8550/common/setup.c)0
-rw-r--r--arch/mips/nxp/pnx8550/common/time.c (renamed from arch/mips/philips/pnx8550/common/time.c)0
-rw-r--r--arch/mips/nxp/pnx8550/jbs/Makefile (renamed from arch/mips/philips/pnx8550/jbs/Makefile)2
-rw-r--r--arch/mips/nxp/pnx8550/jbs/board_setup.c (renamed from arch/mips/philips/pnx8550/jbs/board_setup.c)0
-rw-r--r--arch/mips/nxp/pnx8550/jbs/init.c (renamed from arch/mips/philips/pnx8550/jbs/init.c)2
-rw-r--r--arch/mips/nxp/pnx8550/jbs/irqmap.c (renamed from arch/mips/philips/pnx8550/jbs/irqmap.c)3
-rw-r--r--arch/mips/nxp/pnx8550/stb810/Makefile (renamed from arch/mips/philips/pnx8550/stb810/Makefile)2
-rw-r--r--arch/mips/nxp/pnx8550/stb810/board_setup.c (renamed from arch/mips/philips/pnx8550/stb810/board_setup.c)2
-rw-r--r--arch/mips/nxp/pnx8550/stb810/irqmap.c (renamed from arch/mips/philips/pnx8550/stb810/irqmap.c)3
-rw-r--r--arch/mips/nxp/pnx8550/stb810/prom_init.c (renamed from arch/mips/philips/pnx8550/stb810/prom_init.c)2
-rw-r--r--arch/mips/oprofile/common.c1
-rw-r--r--arch/mips/oprofile/op_impl.h1
-rw-r--r--arch/mips/oprofile/op_model_mipsxx.c39
-rw-r--r--arch/mips/pci/fixup-au1000.c5
-rw-r--r--arch/mips/pci/ops-pnx8550.c4
-rw-r--r--arch/mips/sgi-ip32/ip32-reset.c2
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c2
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c2
-rw-r--r--arch/mips/tx4938/common/dbgio.c4
-rw-r--r--arch/mips/tx4938/common/prom.c11
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/irq.c46
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/setup.c199
-rw-r--r--arch/mips/vr41xx/common/init.c4
-rw-r--r--arch/mips/vr41xx/common/siu.c36
-rw-r--r--arch/parisc/mm/init.c11
-rw-r--r--arch/powerpc/Kconfig84
-rw-r--r--arch/powerpc/Kconfig.debug3
-rw-r--r--arch/powerpc/Makefile1
-rw-r--r--arch/powerpc/boot/.gitignore1
-rw-r--r--arch/powerpc/boot/Makefile2
-rw-r--r--arch/powerpc/boot/dts/canyonlands.dts37
-rw-r--r--arch/powerpc/boot/dts/glacier.dts37
-rw-r--r--arch/powerpc/boot/dts/mpc8610_hpcd.dts12
-rw-r--r--arch/powerpc/boot/ns16550.c5
-rw-r--r--arch/powerpc/kernel/Makefile9
-rw-r--r--arch/powerpc/kernel/asm-offsets.c39
-rw-r--r--arch/powerpc/kernel/cpu_setup_44x.S1
-rw-r--r--arch/powerpc/kernel/cpu_setup_6xx.S8
-rw-r--r--arch/powerpc/kernel/cputable.c4
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S11
-rw-r--r--arch/powerpc/kernel/misc_32.S6
-rw-r--r--arch/powerpc/kernel/misc_64.S20
-rw-r--r--arch/powerpc/kernel/of_platform.c2
-rw-r--r--arch/powerpc/kernel/paca.c87
-rw-r--r--arch/powerpc/kernel/ppc32.h2
-rw-r--r--arch/powerpc/kernel/process.c31
-rw-r--r--arch/powerpc/kernel/prom.c4
-rw-r--r--arch/powerpc/kernel/prom_init_check.sh58
-rw-r--r--arch/powerpc/kernel/ptrace32.c27
-rw-r--r--arch/powerpc/kernel/setup_64.c5
-rw-r--r--arch/powerpc/kernel/stacktrace.c1
-rw-r--r--arch/powerpc/kernel/udbg.c4
-rw-r--r--arch/powerpc/kvm/44x_tlb.c224
-rw-r--r--arch/powerpc/kvm/44x_tlb.h91
-rw-r--r--arch/powerpc/kvm/Kconfig42
-rw-r--r--arch/powerpc/kvm/Makefile15
-rw-r--r--arch/powerpc/kvm/booke_guest.c615
-rw-r--r--arch/powerpc/kvm/booke_host.c83
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S436
-rw-r--r--arch/powerpc/kvm/emulate.c760
-rw-r--r--arch/powerpc/kvm/powerpc.c436
-rw-r--r--arch/powerpc/mm/fsl_booke_mmu.c2
-rw-r--r--arch/powerpc/mm/hash_low_32.S4
-rw-r--r--arch/powerpc/mm/init_32.c13
-rw-r--r--arch/powerpc/mm/init_64.c3
-rw-r--r--arch/powerpc/mm/mem.c46
-rw-r--r--arch/powerpc/mm/numa.c1
-rw-r--r--arch/powerpc/mm/pgtable_32.c23
-rw-r--r--arch/powerpc/platforms/86xx/mpc8610_hpcd.c190
-rw-r--r--arch/powerpc/platforms/Kconfig1
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype4
-rw-r--r--arch/powerpc/platforms/Makefile1
-rw-r--r--arch/powerpc/platforms/cell/Kconfig13
-rw-r--r--arch/powerpc/platforms/cell/Makefile20
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c6
-rw-r--r--arch/powerpc/platforms/cell/beat.c (renamed from arch/powerpc/platforms/celleb/beat.c)2
-rw-r--r--arch/powerpc/platforms/cell/beat.h (renamed from arch/powerpc/platforms/celleb/beat.h)0
-rw-r--r--arch/powerpc/platforms/cell/beat_htab.c (renamed from arch/powerpc/platforms/celleb/htab.c)0
-rw-r--r--arch/powerpc/platforms/cell/beat_hvCall.S (renamed from arch/powerpc/platforms/celleb/hvCall.S)0
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c (renamed from arch/powerpc/platforms/celleb/interrupt.c)2
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.h (renamed from arch/powerpc/platforms/celleb/interrupt.h)0
-rw-r--r--arch/powerpc/platforms/cell/beat_iommu.c (renamed from arch/powerpc/platforms/celleb/iommu.c)0
-rw-r--r--arch/powerpc/platforms/cell/beat_smp.c (renamed from arch/powerpc/platforms/celleb/smp.c)2
-rw-r--r--arch/powerpc/platforms/cell/beat_spu_priv1.c (renamed from arch/powerpc/platforms/celleb/spu_priv1.c)0
-rw-r--r--arch/powerpc/platforms/cell/beat_syscall.h (renamed from arch/powerpc/platforms/celleb/beat_syscall.h)0
-rw-r--r--arch/powerpc/platforms/cell/beat_udbg.c (renamed from arch/powerpc/platforms/celleb/udbg_beat.c)0
-rw-r--r--arch/powerpc/platforms/cell/beat_wrapper.h (renamed from arch/powerpc/platforms/celleb/beat_wrapper.h)0
-rw-r--r--arch/powerpc/platforms/cell/celleb_pci.c (renamed from arch/powerpc/platforms/celleb/pci.c)50
-rw-r--r--arch/powerpc/platforms/cell/celleb_pci.h (renamed from arch/powerpc/platforms/celleb/pci.h)19
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc.h (renamed from arch/powerpc/platforms/celleb/scc.h)87
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc_epci.c (renamed from arch/powerpc/platforms/celleb/scc_epci.c)77
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc_pciex.c547
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc_sio.c (renamed from arch/powerpc/platforms/celleb/scc_sio.c)0
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc_uhc.c (renamed from arch/powerpc/platforms/celleb/scc_uhc.c)2
-rw-r--r--arch/powerpc/platforms/cell/celleb_setup.c (renamed from arch/powerpc/platforms/celleb/setup.c)12
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c358
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.h49
-rw-r--r--arch/powerpc/platforms/cell/setup.c43
-rw-r--r--arch/powerpc/platforms/cell/spider-pci.c184
-rw-r--r--arch/powerpc/platforms/celleb/Kconfig12
-rw-r--r--arch/powerpc/platforms/celleb/Makefile9
-rw-r--r--arch/powerpc/platforms/celleb/io-workarounds.c280
-rw-r--r--arch/powerpc/platforms/iseries/exception.S27
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c1
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig5
-rw-r--r--arch/powerpc/platforms/pseries/Makefile4
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c1
-rw-r--r--arch/powerpc/platforms/pseries/eeh_cache.c1
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c10
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c39
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c36
-rw-r--r--arch/powerpc/platforms/pseries/ras.c4
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c14
-rw-r--r--arch/powerpc/platforms/pseries/scanlog.c23
-rw-r--r--arch/powerpc/platforms/pseries/setup.c17
-rw-r--r--arch/powerpc/platforms/pseries/smp.c11
-rw-r--r--arch/powerpc/platforms/pseries/xics.c1
-rw-r--r--arch/powerpc/sysdev/axonram.c5
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c41
-rw-r--r--arch/powerpc/sysdev/fsl_soc.h23
-rw-r--r--arch/powerpc/sysdev/mv64x60_dev.c52
-rw-r--r--arch/powerpc/sysdev/mv64x60_udbg.c2
-rw-r--r--arch/ppc/8260_io/fcc_enet.c19
-rw-r--r--arch/ppc/8xx_io/enet.c23
-rw-r--r--arch/ppc/Kconfig82
-rw-r--r--arch/ppc/configs/ads8272_defconfig930
-rw-r--r--arch/ppc/configs/mpc86x_ads_defconfig633
-rw-r--r--arch/ppc/configs/mpc885ads_defconfig622
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c1
-rw-r--r--arch/ppc/lib/string.S14
-rw-r--r--arch/ppc/platforms/Makefile4
-rw-r--r--arch/ppc/platforms/fads.h25
-rw-r--r--arch/ppc/platforms/mpc8272ads_setup.c367
-rw-r--r--arch/ppc/platforms/mpc885ads.h93
-rw-r--r--arch/ppc/platforms/mpc885ads_setup.c476
-rw-r--r--arch/ppc/platforms/pq2ads.c53
-rw-r--r--arch/ppc/platforms/pq2ads.h94
-rw-r--r--arch/ppc/platforms/pq2ads_pd.h32
-rw-r--r--arch/ppc/syslib/m8260_setup.c6
-rw-r--r--arch/ppc/syslib/m82xx_pci.c38
-rw-r--r--arch/ppc/syslib/m8xx_setup.c10
-rw-r--r--arch/s390/Kconfig14
-rw-r--r--arch/s390/Makefile2
-rw-r--r--arch/s390/kernel/early.c4
-rw-r--r--arch/s390/kernel/setup.c14
-rw-r--r--arch/s390/kernel/vtime.c1
-rw-r--r--arch/s390/kvm/Kconfig46
-rw-r--r--arch/s390/kvm/Makefile14
-rw-r--r--arch/s390/kvm/diag.c67
-rw-r--r--arch/s390/kvm/gaccess.h274
-rw-r--r--arch/s390/kvm/intercept.c216
-rw-r--r--arch/s390/kvm/interrupt.c592
-rw-r--r--arch/s390/kvm/kvm-s390.c685
-rw-r--r--arch/s390/kvm/kvm-s390.h64
-rw-r--r--arch/s390/kvm/priv.c323
-rw-r--r--arch/s390/kvm/sie64a.S47
-rw-r--r--arch/s390/kvm/sigp.c288
-rw-r--r--arch/s390/mm/pgtable.c65
-rw-r--r--arch/sh/mm/init.c9
-rw-r--r--arch/sparc/kernel/process.c2
-rw-r--r--arch/sparc/kernel/signal.c260
-rw-r--r--arch/sparc/kernel/sys_sparc.c14
-rw-r--r--arch/sparc64/Kconfig85
-rw-r--r--arch/sparc64/defconfig23
-rw-r--r--arch/sparc64/kernel/Makefile6
-rw-r--r--arch/sparc64/kernel/audit.c6
-rw-r--r--arch/sparc64/kernel/irq.c3
-rw-r--r--arch/sparc64/kernel/isa.c191
-rw-r--r--arch/sparc64/kernel/of_device.c6
-rw-r--r--arch/sparc64/kernel/pci.c2
-rw-r--r--arch/sparc64/kernel/process.c12
-rw-r--r--arch/sparc64/kernel/signal.c16
-rw-r--r--arch/sparc64/kernel/signal32.c272
-rw-r--r--arch/sparc64/kernel/smp.c27
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c2
-rw-r--r--arch/sparc64/kernel/sys_sparc.c4
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c11
-rw-r--r--arch/sparc64/mm/init.c16
-rw-r--r--arch/um/Kconfig.x86_647
-rw-r--r--arch/um/drivers/chan_kern.c15
-rw-r--r--arch/um/drivers/line.c2
-rw-r--r--arch/um/drivers/mcast_kern.c2
-rw-r--r--arch/um/drivers/mconsole_user.c2
-rw-r--r--arch/um/drivers/net_kern.c6
-rw-r--r--arch/um/drivers/port_user.c2
-rw-r--r--arch/um/drivers/slip_kern.c4
-rw-r--r--arch/um/drivers/stdio_console.c4
-rw-r--r--arch/um/drivers/ubd_kern.c385
-rw-r--r--arch/um/include/chan_kern.h2
-rw-r--r--arch/um/kernel/um_arch.c7
-rw-r--r--arch/um/os-Linux/helper.c1
-rw-r--r--arch/um/os-Linux/start_up.c14
-rw-r--r--arch/um/os-Linux/sys-i386/task_size.c12
-rw-r--r--arch/um/sys-i386/Makefile2
-rw-r--r--arch/um/sys-x86_64/Makefile2
-rw-r--r--arch/x86/Kconfig41
-rw-r--r--arch/x86/Kconfig.cpu11
-rw-r--r--arch/x86/Kconfig.debug24
-rw-r--r--arch/x86/boot/.gitignore5
-rw-r--r--arch/x86/boot/header.S6
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--arch/x86/ia32/ia32_signal.c10
-rw-r--r--arch/x86/ia32/ia32entry.S2
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/acpi/boot.c4
-rw-r--r--arch/x86/kernel/acpi/realmode/.gitignore3
-rw-r--r--arch/x86/kernel/alternative.c39
-rw-r--r--arch/x86/kernel/apic_32.c3
-rw-r--r--arch/x86/kernel/apic_64.c3
-rw-r--r--arch/x86/kernel/apm_32.c19
-rw-r--r--arch/x86/kernel/cpu/Makefile1
-rw-r--r--arch/x86/kernel/cpu/amd.c6
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c10
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_64.c18
-rw-r--r--arch/x86/kernel/cpu/nexgen.c59
-rw-r--r--arch/x86/kernel/cpu/perfctr-watchdog.c14
-rw-r--r--arch/x86/kernel/crash.c3
-rw-r--r--arch/x86/kernel/e820_64.c35
-rw-r--r--arch/x86/kernel/entry_32.S12
-rw-r--r--arch/x86/kernel/genapic_64.c2
-rw-r--r--arch/x86/kernel/head64.c25
-rw-r--r--arch/x86/kernel/hpet.c2
-rw-r--r--arch/x86/kernel/i8253.c6
-rw-r--r--arch/x86/kernel/io_apic_32.c3
-rw-r--r--arch/x86/kernel/io_apic_64.c2
-rw-r--r--arch/x86/kernel/irq_32.c2
-rw-r--r--arch/x86/kernel/kdebugfs.c163
-rw-r--r--arch/x86/kernel/kvm.c248
-rw-r--r--arch/x86/kernel/kvmclock.c187
-rw-r--r--arch/x86/kernel/mfgpt_32.c11
-rw-r--r--arch/x86/kernel/mpparse.c39
-rw-r--r--arch/x86/kernel/paravirt.c12
-rw-r--r--arch/x86/kernel/pci-calgary_64.c1
-rw-r--r--arch/x86/kernel/process.c117
-rw-r--r--arch/x86/kernel/process_32.c118
-rw-r--r--arch/x86/kernel/process_64.c123
-rw-r--r--arch/x86/kernel/ptrace.c95
-rw-r--r--arch/x86/kernel/reboot.c17
-rw-r--r--arch/x86/kernel/setup_32.c10
-rw-r--r--arch/x86/kernel/setup_64.c36
-rw-r--r--arch/x86/kernel/signal_32.c35
-rw-r--r--arch/x86/kernel/signal_64.c30
-rw-r--r--arch/x86/kernel/smpboot.c8
-rw-r--r--arch/x86/kernel/summit_32.c5
-rw-r--r--arch/x86/kernel/tlb_64.c4
-rw-r--r--arch/x86/kernel/trampoline_32.S2
-rw-r--r--arch/x86/kernel/traps_32.c2
-rw-r--r--arch/x86/kernel/vmi_32.c22
-rw-r--r--arch/x86/kernel/vmlinux_64.lds.S6
-rw-r--r--arch/x86/kvm/Kconfig13
-rw-r--r--arch/x86/kvm/Makefile6
-rw-r--r--arch/x86/kvm/i8254.c611
-rw-r--r--arch/x86/kvm/i8254.h63
-rw-r--r--arch/x86/kvm/irq.c18
-rw-r--r--arch/x86/kvm/irq.h3
-rw-r--r--arch/x86/kvm/kvm_svm.h2
-rw-r--r--arch/x86/kvm/lapic.c35
-rw-r--r--arch/x86/kvm/mmu.c672
-rw-r--r--arch/x86/kvm/mmu.h6
-rw-r--r--arch/x86/kvm/paging_tmpl.h86
-rw-r--r--arch/x86/kvm/segment_descriptor.h29
-rw-r--r--arch/x86/kvm/svm.c352
-rw-r--r--arch/x86/kvm/svm.h3
-rw-r--r--arch/x86/kvm/tss.h59
-rw-r--r--arch/x86/kvm/vmx.c278
-rw-r--r--arch/x86/kvm/vmx.h10
-rw-r--r--arch/x86/kvm/x86.c897
-rw-r--r--arch/x86/kvm/x86_emulate.c285
-rw-r--r--arch/x86/lib/Makefile3
-rw-r--r--arch/x86/lib/bitops_32.c70
-rw-r--r--arch/x86/lib/bitops_64.c175
-rw-r--r--arch/x86/mach-voyager/voyager_smp.c14
-rw-r--r--arch/x86/mm/Makefile2
-rw-r--r--arch/x86/mm/init_32.c69
-rw-r--r--arch/x86/mm/init_64.c74
-rw-r--r--arch/x86/mm/ioremap.c46
-rw-r--r--arch/x86/mm/numa_64.c42
-rw-r--r--arch/x86/mm/pageattr.c4
-rw-r--r--arch/x86/mm/pat.c207
-rw-r--r--arch/x86/mm/pgtable.c276
-rw-r--r--arch/x86/mm/pgtable_32.c204
-rw-r--r--arch/x86/vdso/vdso.S10
-rw-r--r--arch/x86/xen/Kconfig2
-rw-r--r--arch/x86/xen/Makefile4
-rw-r--r--arch/x86/xen/enlighten.c54
-rw-r--r--arch/x86/xen/grant-table.c91
-rw-r--r--arch/x86/xen/mmu.c147
-rw-r--r--arch/x86/xen/setup.c21
-rw-r--r--arch/x86/xen/smp.c22
-rw-r--r--arch/x86/xen/xen-asm.S42
-rw-r--r--arch/x86/xen/xen-ops.h8
-rw-r--r--block/bsg.c43
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/bay.c2
-rw-r--r--drivers/acpi/dispatcher/dsfield.c173
-rw-r--r--drivers/acpi/dispatcher/dsinit.c2
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c57
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c2
-rw-r--r--drivers/acpi/dispatcher/dsobject.c101
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c260
-rw-r--r--drivers/acpi/dispatcher/dsutils.c167
-rw-r--r--drivers/acpi/dispatcher/dswexec.c78
-rw-r--r--drivers/acpi/dispatcher/dswload.c37
-rw-r--r--drivers/acpi/dispatcher/dswscope.c2
-rw-r--r--drivers/acpi/dispatcher/dswstate.c517
-rw-r--r--drivers/acpi/ec.c240
-rw-r--r--drivers/acpi/events/evevent.c2
-rw-r--r--drivers/acpi/events/evgpe.c2
-rw-r--r--drivers/acpi/events/evgpeblk.c2
-rw-r--r--drivers/acpi/events/evmisc.c92
-rw-r--r--drivers/acpi/events/evregion.c4
-rw-r--r--drivers/acpi/events/evrgnini.c2
-rw-r--r--drivers/acpi/events/evsci.c2
-rw-r--r--drivers/acpi/events/evxface.c23
-rw-r--r--drivers/acpi/events/evxfevnt.c2
-rw-r--r--drivers/acpi/events/evxfregn.c2
-rw-r--r--drivers/acpi/executer/exconfig.c105
-rw-r--r--drivers/acpi/executer/exconvrt.c2
-rw-r--r--drivers/acpi/executer/excreate.c117
-rw-r--r--drivers/acpi/executer/exdump.c69
-rw-r--r--drivers/acpi/executer/exfield.c63
-rw-r--r--drivers/acpi/executer/exfldio.c46
-rw-r--r--drivers/acpi/executer/exmisc.c2
-rw-r--r--drivers/acpi/executer/exmutex.c237
-rw-r--r--drivers/acpi/executer/exnames.c2
-rw-r--r--drivers/acpi/executer/exoparg1.c25
-rw-r--r--drivers/acpi/executer/exoparg2.c21
-rw-r--r--drivers/acpi/executer/exoparg3.c3
-rw-r--r--drivers/acpi/executer/exoparg6.c10
-rw-r--r--drivers/acpi/executer/exprep.c17
-rw-r--r--drivers/acpi/executer/exregion.c10
-rw-r--r--drivers/acpi/executer/exresnte.c12
-rw-r--r--drivers/acpi/executer/exresolv.c55
-rw-r--r--drivers/acpi/executer/exresop.c13
-rw-r--r--drivers/acpi/executer/exstore.c119
-rw-r--r--drivers/acpi/executer/exstoren.c2
-rw-r--r--drivers/acpi/executer/exstorob.c2
-rw-r--r--drivers/acpi/executer/exsystem.c3
-rw-r--r--drivers/acpi/executer/exutils.c67
-rw-r--r--drivers/acpi/fan.c35
-rw-r--r--drivers/acpi/glue.c20
-rw-r--r--drivers/acpi/hardware/hwacpi.c2
-rw-r--r--drivers/acpi/hardware/hwgpe.c2
-rw-r--r--drivers/acpi/hardware/hwregs.c2
-rw-r--r--drivers/acpi/hardware/hwsleep.c16
-rw-r--r--drivers/acpi/hardware/hwtimer.c2
-rw-r--r--drivers/acpi/namespace/nsaccess.c101
-rw-r--r--drivers/acpi/namespace/nsalloc.c2
-rw-r--r--drivers/acpi/namespace/nsdump.c11
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c2
-rw-r--r--drivers/acpi/namespace/nseval.c2
-rw-r--r--drivers/acpi/namespace/nsinit.c12
-rw-r--r--drivers/acpi/namespace/nsload.c6
-rw-r--r--drivers/acpi/namespace/nsnames.c8
-rw-r--r--drivers/acpi/namespace/nsobject.c2
-rw-r--r--drivers/acpi/namespace/nsparse.c33
-rw-r--r--drivers/acpi/namespace/nssearch.c2
-rw-r--r--drivers/acpi/namespace/nsutils.c2
-rw-r--r--drivers/acpi/namespace/nswalk.c6
-rw-r--r--drivers/acpi/namespace/nsxfeval.c15
-rw-r--r--drivers/acpi/namespace/nsxfname.c2
-rw-r--r--drivers/acpi/namespace/nsxfobj.c2
-rw-r--r--drivers/acpi/osl.c1
-rw-r--r--drivers/acpi/parser/psargs.c63
-rw-r--r--drivers/acpi/parser/psloop.c61
-rw-r--r--drivers/acpi/parser/psopcode.c38
-rw-r--r--drivers/acpi/parser/psparse.c45
-rw-r--r--drivers/acpi/parser/psscope.c2
-rw-r--r--drivers/acpi/parser/pstree.c4
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/parser/pswalk.c2
-rw-r--r--drivers/acpi/parser/psxface.c2
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/processor_core.c31
-rw-r--r--drivers/acpi/processor_idle.c37
-rw-r--r--drivers/acpi/processor_thermal.c30
-rw-r--r--drivers/acpi/resources/rsaddr.c2
-rw-r--r--drivers/acpi/resources/rscalc.c26
-rw-r--r--drivers/acpi/resources/rscreate.c2
-rw-r--r--drivers/acpi/resources/rsdump.c10
-rw-r--r--drivers/acpi/resources/rsinfo.c2
-rw-r--r--drivers/acpi/resources/rsio.c41
-rw-r--r--drivers/acpi/resources/rsirq.c45
-rw-r--r--drivers/acpi/resources/rslist.c2
-rw-r--r--drivers/acpi/resources/rsmemory.c2
-rw-r--r--drivers/acpi/resources/rsmisc.c13
-rw-r--r--drivers/acpi/resources/rsutils.c8
-rw-r--r--drivers/acpi/resources/rsxface.c2
-rw-r--r--drivers/acpi/scan.c63
-rw-r--r--drivers/acpi/sleep/main.c42
-rw-r--r--drivers/acpi/tables/tbfadt.c2
-rw-r--r--drivers/acpi/tables/tbfind.c34
-rw-r--r--drivers/acpi/tables/tbinstal.c24
-rw-r--r--drivers/acpi/tables/tbutils.c4
-rw-r--r--drivers/acpi/tables/tbxface.c91
-rw-r--r--drivers/acpi/tables/tbxfroot.c2
-rw-r--r--drivers/acpi/thermal.c22
-rw-r--r--drivers/acpi/utilities/utalloc.c4
-rw-r--r--drivers/acpi/utilities/utcache.c2
-rw-r--r--drivers/acpi/utilities/utcopy.c61
-rw-r--r--drivers/acpi/utilities/utdebug.c19
-rw-r--r--drivers/acpi/utilities/utdelete.c23
-rw-r--r--drivers/acpi/utilities/uteval.c2
-rw-r--r--drivers/acpi/utilities/utglobal.c49
-rw-r--r--drivers/acpi/utilities/utinit.c5
-rw-r--r--drivers/acpi/utilities/utmath.c4
-rw-r--r--drivers/acpi/utilities/utmisc.c6
-rw-r--r--drivers/acpi/utilities/utmutex.c2
-rw-r--r--drivers/acpi/utilities/utobject.c8
-rw-r--r--drivers/acpi/utilities/utresrc.c2
-rw-r--r--drivers/acpi/utilities/utstate.c2
-rw-r--r--drivers/acpi/utilities/utxface.c6
-rw-r--r--drivers/acpi/utils.c2
-rw-r--r--drivers/acpi/video.c316
-rw-r--r--drivers/ata/ahci.c15
-rw-r--r--drivers/ata/ata_piix.c1
-rw-r--r--drivers/ata/libata-acpi.c4
-rw-r--r--drivers/ata/libata-core.c7
-rw-r--r--drivers/ata/libata-eh.c1
-rw-r--r--drivers/ata/libata-sff.c4
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/ata/pata_at32.c3
-rw-r--r--drivers/ata/pata_bf54x.c3
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c1
-rw-r--r--drivers/ata/pata_platform.c1
-rw-r--r--drivers/ata/pata_rb500_cf.c3
-rw-r--r--drivers/ata/sata_fsl.c2
-rw-r--r--drivers/ata/sata_mv.c583
-rw-r--r--drivers/ata/sata_nv.c11
-rw-r--r--drivers/ata/sata_sis.c12
-rw-r--r--drivers/atm/nicstar.c2
-rw-r--r--drivers/block/brd.c5
-rw-r--r--drivers/block/xen-blkfront.c23
-rw-r--r--drivers/char/Kconfig11
-rw-r--r--drivers/char/agp/amd-k7-agp.c3
-rw-r--r--drivers/char/agp/frontend.c4
-rw-r--r--drivers/char/cs5535_gpio.c2
-rw-r--r--drivers/char/drm/ati_pcigart.c7
-rw-r--r--drivers/char/drm/drm.h17
-rw-r--r--drivers/char/drm/drmP.h133
-rw-r--r--drivers/char/drm/drm_agpsupport.c2
-rw-r--r--drivers/char/drm/drm_drv.c60
-rw-r--r--drivers/char/drm/drm_fops.c41
-rw-r--r--drivers/char/drm/drm_irq.c381
-rw-r--r--drivers/char/drm/drm_proc.c61
-rw-r--r--drivers/char/drm/drm_stub.c138
-rw-r--r--drivers/char/drm/drm_sysfs.c46
-rw-r--r--drivers/char/drm/drm_vm.c22
-rw-r--r--drivers/char/drm/i810_dma.c4
-rw-r--r--drivers/char/drm/i830_dma.c4
-rw-r--r--drivers/char/drm/i915_dma.c160
-rw-r--r--drivers/char/drm/i915_drm.h45
-rw-r--r--drivers/char/drm/i915_drv.c8
-rw-r--r--drivers/char/drm/i915_drv.h103
-rw-r--r--drivers/char/drm/i915_irq.c605
-rw-r--r--drivers/char/drm/mga_drv.c7
-rw-r--r--drivers/char/drm/mga_drv.h6
-rw-r--r--drivers/char/drm/mga_irq.c69
-rw-r--r--drivers/char/drm/r128_cce.c2
-rw-r--r--drivers/char/drm/r128_drv.c7
-rw-r--r--drivers/char/drm/r128_drv.h9
-rw-r--r--drivers/char/drm/r128_irq.c55
-rw-r--r--drivers/char/drm/radeon_drv.c8
-rw-r--r--drivers/char/drm/radeon_drv.h19
-rw-r--r--drivers/char/drm/radeon_irq.c171
-rw-r--r--drivers/char/drm/via_drv.c6
-rw-r--r--drivers/char/drm/via_drv.h7
-rw-r--r--drivers/char/drm/via_irq.c81
-rw-r--r--drivers/char/keyboard.c6
-rw-r--r--drivers/char/mem.c133
-rw-r--r--drivers/char/n_hdlc.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c125
-rw-r--r--drivers/char/rio/rioroute.c2
-rw-r--r--drivers/char/rtc.c4
-rw-r--r--drivers/char/synclink.c258
-rw-r--r--drivers/char/synclink_gt.c102
-rw-r--r--drivers/char/synclinkmp.c265
-rw-r--r--drivers/char/sysrq.c3
-rw-r--r--drivers/char/tty_io.c2
-rw-r--r--drivers/char/vt.c8
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c2
-rw-r--r--drivers/cpufreq/cpufreq.c129
-rw-r--r--drivers/cpufreq/cpufreq_stats.c6
-rw-r--r--drivers/firmware/iscsi_ibft_find.c2
-rw-r--r--drivers/gpio/gpiolib.c123
-rw-r--r--drivers/gpio/mcp23s08.c1
-rw-r--r--drivers/gpio/pca953x.c1
-rw-r--r--drivers/gpio/pcf857x.c1
-rw-r--r--drivers/hid/usbhid/hid-core.c2
-rw-r--r--drivers/hid/usbhid/hid-quirks.c4
-rw-r--r--drivers/ide/Kconfig36
-rw-r--r--drivers/ide/Makefile2
-rw-r--r--drivers/ide/arm/bast-ide.c25
-rw-r--r--drivers/ide/arm/icside.c79
-rw-r--r--drivers/ide/arm/ide_arm.c20
-rw-r--r--drivers/ide/arm/palm_bk3710.c69
-rw-r--r--drivers/ide/arm/rapide.c12
-rw-r--r--drivers/ide/cris/Makefile3
-rw-r--r--drivers/ide/cris/ide-cris.c1081
-rw-r--r--drivers/ide/h8300/ide-h8300.c118
-rw-r--r--drivers/ide/ide-acpi.c30
-rw-r--r--drivers/ide/ide-cd.c947
-rw-r--r--drivers/ide/ide-cd.h4
-rw-r--r--drivers/ide/ide-disk.c159
-rw-r--r--drivers/ide/ide-dma.c164
-rw-r--r--drivers/ide/ide-floppy.c59
-rw-r--r--drivers/ide/ide-generic.c36
-rw-r--r--drivers/ide/ide-io.c97
-rw-r--r--drivers/ide/ide-iops.c428
-rw-r--r--drivers/ide/ide-lib.c46
-rw-r--r--drivers/ide/ide-pnp.c45
-rw-r--r--drivers/ide/ide-probe.c287
-rw-r--r--drivers/ide/ide-proc.c169
-rw-r--r--drivers/ide/ide-scan-pci.c2
-rw-r--r--drivers/ide/ide-tape.c1221
-rw-r--r--drivers/ide/ide-taskfile.c92
-rw-r--r--drivers/ide/ide.c491
-rw-r--r--drivers/ide/legacy/ali14xx.c44
-rw-r--r--drivers/ide/legacy/buddha.c18
-rw-r--r--drivers/ide/legacy/dtc2278.c39
-rw-r--r--drivers/ide/legacy/falconide.c40
-rw-r--r--drivers/ide/legacy/gayle.c22
-rw-r--r--drivers/ide/legacy/hd.c78
-rw-r--r--drivers/ide/legacy/ht6560b.c57
-rw-r--r--drivers/ide/legacy/ide-4drives.c52
-rw-r--r--drivers/ide/legacy/ide-cs.c84
-rw-r--r--drivers/ide/legacy/ide_platform.c16
-rw-r--r--drivers/ide/legacy/macide.c8
-rw-r--r--drivers/ide/legacy/q40ide.c74
-rw-r--r--drivers/ide/legacy/qd65xx.c238
-rw-r--r--drivers/ide/legacy/qd65xx.h1
-rw-r--r--drivers/ide/legacy/umc8672.c92
-rw-r--r--drivers/ide/mips/au1xxx-ide.c155
-rw-r--r--drivers/ide/mips/swarm.c20
-rw-r--r--drivers/ide/pci/aec62xx.c39
-rw-r--r--drivers/ide/pci/alim15x3.c332
-rw-r--r--drivers/ide/pci/amd74xx.c19
-rw-r--r--drivers/ide/pci/atiixp.c29
-rw-r--r--drivers/ide/pci/cmd640.c294
-rw-r--r--drivers/ide/pci/cmd64x.c153
-rw-r--r--drivers/ide/pci/cs5520.c29
-rw-r--r--drivers/ide/pci/cs5530.c18
-rw-r--r--drivers/ide/pci/cs5535.c24
-rw-r--r--drivers/ide/pci/cy82c693.c97
-rw-r--r--drivers/ide/pci/delkin_cb.c20
-rw-r--r--drivers/ide/pci/generic.c10
-rw-r--r--drivers/ide/pci/hpt34x.c17
-rw-r--r--drivers/ide/pci/hpt366.c132
-rw-r--r--drivers/ide/pci/it8213.c34
-rw-r--r--drivers/ide/pci/it821x.c52
-rw-r--r--drivers/ide/pci/jmicron.c29
-rw-r--r--drivers/ide/pci/ns87415.c84
-rw-r--r--drivers/ide/pci/opti621.c82
-rw-r--r--drivers/ide/pci/pdc202xx_new.c31
-rw-r--r--drivers/ide/pci/pdc202xx_old.c126
-rw-r--r--drivers/ide/pci/piix.c18
-rw-r--r--drivers/ide/pci/rz1000.c2
-rw-r--r--drivers/ide/pci/sc1200.c39
-rw-r--r--drivers/ide/pci/scc_pata.c287
-rw-r--r--drivers/ide/pci/serverworks.c38
-rw-r--r--drivers/ide/pci/sgiioc4.c141
-rw-r--r--drivers/ide/pci/siimage.c677
-rw-r--r--drivers/ide/pci/sis5513.c253
-rw-r--r--drivers/ide/pci/sl82c105.c83
-rw-r--r--drivers/ide/pci/slc90e66.c22
-rw-r--r--drivers/ide/pci/tc86c001.c54
-rw-r--r--drivers/ide/pci/triflex.c12
-rw-r--r--drivers/ide/pci/trm290.c47
-rw-r--r--drivers/ide/pci/via82cxxx.c20
-rw-r--r--drivers/ide/ppc/mpc8xx.c70
-rw-r--r--drivers/ide/ppc/pmac.c184
-rw-r--r--drivers/ide/setup-pci.c226
-rw-r--r--drivers/ieee1394/dv1394.c2
-rw-r--r--drivers/ieee1394/iso.h2
-rw-r--r--drivers/ieee1394/ohci1394.c34
-rw-r--r--drivers/ieee1394/raw1394.c9
-rw-r--r--drivers/ieee1394/video1394.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c75
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c16
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c15
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c51
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c6
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c23
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c6
-rw-r--r--drivers/infiniband/hw/mlx4/doorbell.c122
-rw-r--r--drivers/infiniband/hw/mlx4/main.c3
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h33
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c6
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c6
-rw-r--r--drivers/infiniband/hw/nes/nes.c15
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c27
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c20
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h2
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c18
-rw-r--r--drivers/infiniband/hw/nes/nes_utils.c4
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h20
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c125
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c19
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c15
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c1
-rw-r--r--drivers/input/Kconfig9
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/input-polldev.c6
-rw-r--r--drivers/input/joystick/Kconfig12
-rw-r--r--drivers/input/joystick/Makefile3
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c2
-rw-r--r--drivers/input/joystick/xpad.c233
-rw-r--r--drivers/input/joystick/zhenhua.c243
-rw-r--r--drivers/input/keyboard/aaed2000_kbd.c4
-rw-r--r--drivers/input/keyboard/bf54x-keys.c37
-rw-r--r--drivers/input/keyboard/corgikbd.c2
-rw-r--r--drivers/input/keyboard/gpio_keys.c5
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c2
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c4
-rw-r--r--drivers/input/keyboard/locomokbd.c73
-rw-r--r--drivers/input/keyboard/omap-keypad.c9
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c4
-rw-r--r--drivers/input/keyboard/spitzkbd.c1
-rw-r--r--drivers/input/keyboard/tosakbd.c23
-rw-r--r--drivers/input/misc/cobalt_btns.c3
-rw-r--r--drivers/input/misc/sparcspkr.c262
-rw-r--r--drivers/input/mouse/gpio_mouse.c4
-rw-r--r--drivers/input/serio/Kconfig10
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/at32psif.c375
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h12
-rw-r--r--drivers/input/serio/rpckbd.c2
-rw-r--r--drivers/input/tablet/Kconfig10
-rw-r--r--drivers/input/tablet/aiptek.c2
-rw-r--r--drivers/input/tablet/gtco.c8
-rw-r--r--drivers/input/tablet/wacom.h3
-rw-r--r--drivers/input/tablet/wacom_sys.c76
-rw-r--r--drivers/input/tablet/wacom_wac.c2
-rw-r--r--drivers/input/touchscreen/Kconfig53
-rw-r--r--drivers/input/touchscreen/Makefile7
-rw-r--r--drivers/input/touchscreen/ads7846.c22
-rw-r--r--drivers/input/touchscreen/corgi_ts.c2
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c4
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c302
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c4
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c31
-rw-r--r--drivers/input/touchscreen/wm9705.c353
-rw-r--r--drivers/input/touchscreen/wm9712.c462
-rw-r--r--drivers/input/touchscreen/wm9713.c460
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c829
-rw-r--r--drivers/input/xen-kbdfront.c340
-rw-r--r--drivers/isdn/capi/capi.c34
-rw-r--r--drivers/isdn/capi/capidrv.c28
-rw-r--r--drivers/isdn/capi/capifs.c5
-rw-r--r--drivers/isdn/capi/capilib.c4
-rw-r--r--drivers/isdn/capi/capiutil.c2
-rw-r--r--drivers/isdn/capi/kcapi.c22
-rw-r--r--drivers/isdn/capi/kcapi.h2
-rw-r--r--drivers/isdn/hardware/avm/b1.c10
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c10
-rw-r--r--drivers/isdn/hardware/avm/b1isa.c4
-rw-r--r--drivers/isdn/hardware/avm/b1pci.c4
-rw-r--r--drivers/isdn/hardware/avm/b1pcmcia.c4
-rw-r--r--drivers/isdn/hardware/avm/c4.c12
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c4
-rw-r--r--drivers/isdn/hardware/avm/t1pci.c4
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c2
-rw-r--r--drivers/isdn/hardware/eicon/message.c12
-rw-r--r--drivers/isdn/hisax/asuscom.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c2
-rw-r--r--drivers/isdn/hisax/diva.c2
-rw-r--r--drivers/isdn/hisax/elsa.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c2
-rw-r--r--drivers/isdn/hisax/hfc_usb.c6
-rw-r--r--drivers/isdn/hisax/hfcscard.c2
-rw-r--r--drivers/isdn/hisax/hisax_debug.h6
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c12
-rw-r--r--drivers/isdn/hisax/ix1_micro.c2
-rw-r--r--drivers/isdn/hisax/niccy.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c2
-rw-r--r--drivers/isdn/hisax/st5481.h10
-rw-r--r--drivers/isdn/hisax/st5481_usb.c2
-rw-r--r--drivers/isdn/hisax/teles3.c2
-rw-r--r--drivers/isdn/i4l/isdn_common.c2
-rw-r--r--drivers/isdn/i4l/isdn_net.h6
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c32
-rw-r--r--drivers/isdn/i4l/isdn_tty.c6
-rw-r--r--drivers/leds/Kconfig17
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-class.c12
-rw-r--r--drivers/leds/led-core.c4
-rw-r--r--drivers/leds/led-triggers.c120
-rw-r--r--drivers/leds/leds-clevo-mail.c16
-rw-r--r--drivers/leds/leds-cobalt-qube.c2
-rw-r--r--drivers/leds/leds-cobalt-raq.c6
-rw-r--r--drivers/leds/leds-corgi.c11
-rw-r--r--drivers/leds/leds-fsg.c261
-rw-r--r--drivers/leds/leds-gpio.c15
-rw-r--r--drivers/leds/leds-h1940.c64
-rw-r--r--drivers/leds/leds-hp6xx.c6
-rw-r--r--drivers/leds/leds-s3c24xx.c4
-rw-r--r--drivers/leds/leds-spitz.c11
-rw-r--r--drivers/leds/leds.h11
-rw-r--r--drivers/leds/ledtrig-default-on.c45
-rw-r--r--drivers/leds/ledtrig-ide-disk.c2
-rw-r--r--drivers/leds/ledtrig-timer.c35
-rw-r--r--drivers/macintosh/mac_hid.c6
-rw-r--r--drivers/macintosh/windfarm_pm112.c3
-rw-r--r--drivers/macintosh/windfarm_pm81.c4
-rw-r--r--drivers/macintosh/windfarm_pm91.c3
-rw-r--r--drivers/md/Makefile6
-rw-r--r--drivers/md/dm-exception-store.c10
-rw-r--r--drivers/md/dm-io.c38
-rw-r--r--drivers/md/dm-kcopyd.c (renamed from drivers/md/kcopyd.c)298
-rw-r--r--drivers/md/dm-log.c254
-rw-r--r--drivers/md/dm-raid1.c132
-rw-r--r--drivers/md/dm-snap.c22
-rw-r--r--drivers/md/dm-snap.h4
-rw-r--r--drivers/md/dm-table.c42
-rw-r--r--drivers/md/dm-uevent.c22
-rw-r--r--drivers/md/dm.c16
-rw-r--r--drivers/md/dm.h98
-rw-r--r--drivers/md/kcopyd.h42
-rw-r--r--drivers/md/md.c8
-rw-r--r--drivers/md/multipath.c3
-rw-r--r--drivers/md/raid1.c4
-rw-r--r--drivers/md/raid10.c4
-rw-r--r--drivers/md/raid5.c158
-rw-r--r--drivers/md/raid6algos.c3
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c4
-rw-r--r--drivers/media/dvb/frontends/Kconfig8
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/mt312.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1411.c888
-rw-r--r--drivers/media/dvb/frontends/s5h1411.h90
-rw-r--r--drivers/media/video/au0828/Kconfig2
-rw-r--r--drivers/media/video/au0828/au0828-cards.c1
-rw-r--r--drivers/media/video/au0828/au0828-core.c26
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c4
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c6
-rw-r--r--drivers/media/video/au0828/au0828.h8
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c4
-rw-r--r--drivers/media/video/cx88/Kconfig1
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c6
-rw-r--r--drivers/media/video/cx88/cx88-cards.c1
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c32
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c2
-rw-r--r--drivers/media/video/ir-kbd-i2c.c21
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c4
-rw-r--r--drivers/media/video/pvrusb2/Kconfig1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c28
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h22
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-dvb.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c2
-rw-r--r--drivers/media/video/tuner-core.c92
-rw-r--r--drivers/media/video/tuner-xc2028.c2
-rw-r--r--drivers/media/video/v4l2-common.c2
-rw-r--r--drivers/media/video/videobuf-core.c5
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/vivi.c2
-rw-r--r--drivers/mfd/sm501.c84
-rw-r--r--drivers/mfd/ucb1x00-ts.c7
-rw-r--r--drivers/misc/Kconfig21
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/eeepc-laptop.c666
-rw-r--r--drivers/misc/enclosure.c100
-rw-r--r--drivers/misc/intel_menlow.c28
-rw-r--r--drivers/misc/thinkpad_acpi.c765
-rw-r--r--drivers/mtd/Kconfig6
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/ar7part.c151
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c19
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c30
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c15
-rw-r--r--drivers/mtd/chips/cfi_probe.c7
-rw-r--r--drivers/mtd/chips/cfi_util.c2
-rw-r--r--drivers/mtd/chips/jedec_probe.c73
-rw-r--r--drivers/mtd/cmdlinepart.c15
-rw-r--r--drivers/mtd/devices/Kconfig7
-rw-r--r--drivers/mtd/devices/block2mtd.c10
-rw-r--r--drivers/mtd/devices/lart.c16
-rw-r--r--drivers/mtd/devices/m25p80.c40
-rw-r--r--drivers/mtd/devices/mtdram.c1
-rw-r--r--drivers/mtd/devices/phram.c2
-rw-r--r--drivers/mtd/ftl.c6
-rw-r--r--drivers/mtd/inftlmount.c5
-rw-r--r--drivers/mtd/maps/Kconfig3
-rw-r--r--drivers/mtd/maps/bast-flash.c5
-rw-r--r--drivers/mtd/maps/ck804xrom.c89
-rw-r--r--drivers/mtd/maps/integrator-flash.c2
-rw-r--r--drivers/mtd/maps/ixp2000.c3
-rw-r--r--drivers/mtd/maps/ixp4xx.c2
-rw-r--r--drivers/mtd/maps/omap_nor.c12
-rw-r--r--drivers/mtd/maps/pcmciamtd.c2
-rw-r--r--drivers/mtd/maps/physmap.c8
-rw-r--r--drivers/mtd/maps/plat-ram.c50
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c2
-rw-r--r--drivers/mtd/maps/sa1100-flash.c2
-rw-r--r--drivers/mtd/maps/sharpsl-flash.c2
-rw-r--r--drivers/mtd/maps/tqm8xxl.c6
-rw-r--r--drivers/mtd/mtdoops.c2
-rw-r--r--drivers/mtd/nand/Kconfig56
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/at91_nand.c370
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c17
-rw-r--r--drivers/mtd/nand/cs553x_nand.c2
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c39
-rw-r--r--drivers/mtd/nand/fsl_upm.c291
-rw-r--r--drivers/mtd/nand/nand_base.c21
-rw-r--r--drivers/mtd/nand/ndfc.c2
-rw-r--r--drivers/mtd/nand/orion_nand.c1
-rw-r--r--drivers/mtd/nand/plat_nand.c2
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c1249
-rw-r--r--drivers/mtd/nand/rtc_from4.c50
-rw-r--r--drivers/mtd/nand/s3c2410.c73
-rw-r--r--drivers/mtd/nftlmount.c5
-rw-r--r--drivers/mtd/ofpart.c2
-rw-r--r--drivers/mtd/onenand/onenand_base.c51
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c3
-rw-r--r--drivers/mtd/rfd_ftl.c2
-rw-r--r--drivers/mtd/ubi/Kconfig9
-rw-r--r--drivers/mtd/ubi/build.c40
-rw-r--r--drivers/mtd/ubi/debug.h4
-rw-r--r--drivers/mtd/ubi/gluebi.c5
-rw-r--r--drivers/mtd/ubi/io.c4
-rw-r--r--drivers/mtd/ubi/scan.c41
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/mtd/ubi/ubi-media.h (renamed from include/mtd/ubi-header.h)8
-rw-r--r--drivers/mtd/ubi/ubi.h7
-rw-r--r--drivers/net/Kconfig5
-rw-r--r--drivers/net/arm/at91_ether.c1
-rw-r--r--drivers/net/arm/ep93xx_eth.c2
-rw-r--r--drivers/net/atlx/atl1.c138
-rw-r--r--drivers/net/atlx/atlx.c177
-rw-r--r--drivers/net/ax88796.c1
-rw-r--r--drivers/net/bfin_mac.c7
-rw-r--r--drivers/net/cpmac.c2
-rw-r--r--drivers/net/dm9000.c1
-rw-r--r--drivers/net/e1000e/82571.c6
-rw-r--r--drivers/net/e1000e/defines.h3
-rw-r--r--drivers/net/e1000e/e1000.h34
-rw-r--r--drivers/net/e1000e/es2lan.c129
-rw-r--r--drivers/net/e1000e/ethtool.c49
-rw-r--r--drivers/net/e1000e/hw.h12
-rw-r--r--drivers/net/e1000e/netdev.c159
-rw-r--r--drivers/net/e1000e/phy.c73
-rw-r--r--drivers/net/ehea/ehea_main.c4
-rw-r--r--drivers/net/forcedeth.c432
-rw-r--r--drivers/net/gianfar.c104
-rw-r--r--drivers/net/ibm_newemac/core.c83
-rw-r--r--drivers/net/ibm_newemac/core.h14
-rw-r--r--drivers/net/ibm_newemac/mal.c20
-rw-r--r--drivers/net/ibm_newemac/rgmii.c2
-rw-r--r--drivers/net/ibm_newemac/tah.c2
-rw-r--r--drivers/net/ibm_newemac/zmii.c2
-rw-r--r--drivers/net/igb/igb_main.c2
-rw-r--r--drivers/net/irda/ali-ircc.c2
-rw-r--r--drivers/net/irda/pxaficp_ir.c2
-rw-r--r--drivers/net/irda/sa1100_ir.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c2
-rw-r--r--drivers/net/jazzsonic.c2
-rw-r--r--drivers/net/korina.c39
-rw-r--r--drivers/net/macb.c2
-rw-r--r--drivers/net/meth.c2
-rw-r--r--drivers/net/mlx4/alloc.c157
-rw-r--r--drivers/net/mlx4/cq.c2
-rw-r--r--drivers/net/mlx4/main.c3
-rw-r--r--drivers/net/mlx4/mlx4.h3
-rw-r--r--drivers/net/mlx4/qp.c31
-rw-r--r--drivers/net/mv643xx_eth.c5
-rw-r--r--drivers/net/netx-eth.c2
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c15
-rw-r--r--drivers/net/niu.c371
-rw-r--r--drivers/net/niu.h12
-rw-r--r--drivers/net/phy/mdio_bus.c3
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/phy/phy_device.c129
-rw-r--r--drivers/net/s2io.c128
-rw-r--r--drivers/net/s2io.h9
-rw-r--r--drivers/net/sgiseeq.c4
-rw-r--r--drivers/net/smc911x.c8
-rw-r--r--drivers/net/smc91x.c2
-rw-r--r--drivers/net/sni_82596.c2
-rw-r--r--drivers/net/tehuti.c15
-rw-r--r--drivers/net/tg3.c2
-rw-r--r--drivers/net/tsi108_eth.c2
-rw-r--r--drivers/net/typhoon.c1
-rw-r--r--drivers/net/ucc_geth.c2
-rw-r--r--drivers/net/via-velocity.c46
-rw-r--r--drivers/net/wan/c101.c6
-rw-r--r--drivers/net/wan/hdlc_fr.c4
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig6
-rw-r--r--drivers/net/xen-netfront.c2
-rw-r--r--drivers/of/of_i2c.c3
-rw-r--r--drivers/oprofile/buffer_sync.c2
-rw-r--r--drivers/oprofile/cpu_buffer.c16
-rw-r--r--drivers/oprofile/cpu_buffer.h3
-rw-r--r--drivers/oprofile/oprofile_stats.c4
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c2
-rw-r--r--drivers/pcmcia/Kconfig1
-rw-r--r--drivers/pnp/driver.c4
-rw-r--r--drivers/pnp/pnpacpi/core.c2
-rw-r--r--drivers/pnp/quirks.c15
-rw-r--r--drivers/rtc/Kconfig5
-rw-r--r--drivers/rtc/rtc-at91rm9200.c12
-rw-r--r--drivers/rtc/rtc-at91sam9.c2
-rw-r--r--drivers/rtc/rtc-ds1302.c2
-rw-r--r--drivers/rtc/rtc-ds1511.c6
-rw-r--r--drivers/rtc/rtc-ds1672.c14
-rw-r--r--drivers/rtc/rtc-isl1208.c357
-rw-r--r--drivers/rtc/rtc-max6900.c6
-rw-r--r--drivers/rtc/rtc-max6902.c4
-rw-r--r--drivers/rtc/rtc-pcf8563.c126
-rw-r--r--drivers/rtc/rtc-pcf8583.c2
-rw-r--r--drivers/rtc/rtc-rs5c313.c4
-rw-r--r--drivers/rtc/rtc-rs5c372.c18
-rw-r--r--drivers/rtc/rtc-s3c.c6
-rw-r--r--drivers/rtc/rtc-sh.c2
-rw-r--r--drivers/rtc/rtc-sysfs.c12
-rw-r--r--drivers/rtc/rtc-test.c8
-rw-r--r--drivers/rtc/rtc-v3020.c4
-rw-r--r--drivers/rtc/rtc-x1205.c170
-rw-r--r--drivers/s390/Makefile2
-rw-r--r--drivers/s390/block/dcssblk.c8
-rw-r--r--drivers/s390/kvm/Makefile9
-rw-r--r--drivers/s390/kvm/kvm_virtio.c338
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c39
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h18
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c114
-rw-r--r--drivers/scsi/FlashPoint.c2
-rw-r--r--drivers/scsi/Kconfig10
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/aha152x.c13
-rw-r--r--drivers/scsi/aha1542.c26
-rw-r--r--drivers/scsi/aic7xxx/aic7770_osm.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h23
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.reg115
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c835
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_inline.h859
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c181
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h177
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c33
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c8
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_reg.h_shipped1145
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped1555
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_seq.h_shipped6
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h55
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.reg45
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_93cx6.c16
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c676
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_inline.h616
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c95
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h142
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c77
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c9
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_proc.c4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped233
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped6
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm.c6
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_gram.y105
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_scan.l19
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c25
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h1
-rw-r--r--drivers/scsi/dpt_i2o.c2
-rw-r--r--drivers/scsi/eata.c11
-rw-r--r--drivers/scsi/esp_scsi.c35
-rw-r--r--drivers/scsi/esp_scsi.h13
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/hosts.c29
-rw-r--r--drivers/scsi/ide-scsi.c53
-rw-r--r--drivers/scsi/jazz_esp.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c10
-rw-r--r--drivers/scsi/mac_esp.c657
-rw-r--r--drivers/scsi/ncr53c8xx.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c394
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h26
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_proc.c7
-rw-r--r--drivers/scsi/scsi_scan.c84
-rw-r--r--drivers/scsi/scsi_sysfs.c142
-rw-r--r--drivers/scsi/scsi_transport_fc.c60
-rw-r--r--drivers/scsi/scsi_transport_sas.c22
-rw-r--r--drivers/scsi/scsi_transport_spi.c33
-rw-r--r--drivers/scsi/sgiwd93.c4
-rw-r--r--drivers/scsi/sni_53c710.c2
-rw-r--r--drivers/scsi/st.c10
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c6
-rw-r--r--drivers/scsi/u14-34f.c9
-rw-r--r--drivers/scsi/ultrastor.c4
-rw-r--r--drivers/serial/68360serial.c3
-rw-r--r--drivers/serial/8250.c9
-rw-r--r--drivers/serial/8250_au1x00.c100
-rw-r--r--drivers/serial/8250_pci.c2
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/atmel_serial.c1
-rw-r--r--drivers/serial/crisv10.c7
-rw-r--r--drivers/serial/dz.c2
-rw-r--r--drivers/serial/of_serial.c14
-rw-r--r--drivers/serial/serial_core.c15
-rw-r--r--drivers/serial/sunzilog.c4
-rw-r--r--drivers/serial/vr41xx_siu.c15
-rw-r--r--drivers/spi/Kconfig13
-rw-r--r--drivers/spi/atmel_spi.c2
-rw-r--r--drivers/spi/omap_uwire.c4
-rw-r--r--drivers/spi/pxa2xx_spi.c52
-rw-r--r--drivers/spi/spi_bitbang.c2
-rw-r--r--drivers/spi/spi_imx.c223
-rw-r--r--drivers/spi/spi_mpc83xx.c2
-rw-r--r--drivers/spi/spi_s3c24xx.c2
-rw-r--r--drivers/spi/xilinx_spi.c8
-rw-r--r--drivers/thermal/Kconfig4
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/thermal_sys.c (renamed from drivers/thermal/thermal.c)165
-rw-r--r--drivers/usb/atm/cxacru.c14
-rw-r--r--drivers/usb/atm/ueagle-atm.c12
-rw-r--r--drivers/usb/atm/usbatm.c27
-rw-r--r--drivers/usb/atm/usbatm.h2
-rw-r--r--drivers/usb/class/cdc-acm.c98
-rw-r--r--drivers/usb/class/cdc-acm.h7
-rw-r--r--drivers/usb/core/Kconfig42
-rw-r--r--drivers/usb/core/config.c17
-rw-r--r--drivers/usb/core/devio.c73
-rw-r--r--drivers/usb/core/driver.c52
-rw-r--r--drivers/usb/core/hcd-pci.c15
-rw-r--r--drivers/usb/core/hcd.c25
-rw-r--r--drivers/usb/core/hcd.h9
-rw-r--r--drivers/usb/core/hub.c396
-rw-r--r--drivers/usb/core/hub.h9
-rw-r--r--drivers/usb/core/inode.c4
-rw-r--r--drivers/usb/core/message.c17
-rw-r--r--drivers/usb/core/quirks.c14
-rw-r--r--drivers/usb/core/sysfs.c22
-rw-r--r--drivers/usb/core/urb.c26
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/gadget/Kconfig18
-rw-r--r--drivers/usb/gadget/amd5536udc.c30
-rw-r--r--drivers/usb/gadget/at91_udc.c9
-rw-r--r--drivers/usb/gadget/dummy_hcd.c101
-rw-r--r--drivers/usb/gadget/epautoconf.c12
-rw-r--r--drivers/usb/gadget/ether.c18
-rw-r--r--drivers/usb/gadget/file_storage.c36
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c4
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h2
-rw-r--r--drivers/usb/gadget/gmidi.c8
-rw-r--r--drivers/usb/gadget/goku_udc.c20
-rw-r--r--drivers/usb/gadget/inode.c18
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c132
-rw-r--r--drivers/usb/gadget/m66592-udc.h4
-rw-r--r--drivers/usb/gadget/net2280.h2
-rw-r--r--drivers/usb/gadget/omap_udc.c20
-rw-r--r--drivers/usb/gadget/printer.c92
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c26
-rw-r--r--drivers/usb/gadget/rndis.c148
-rw-r--r--drivers/usb/gadget/serial.c3
-rw-r--r--drivers/usb/host/Kconfig10
-rw-r--r--drivers/usb/host/ehci-au1xxx.c5
-rw-r--r--drivers/usb/host/ehci-dbg.c6
-rw-r--r--drivers/usb/host/ehci-fsl.c9
-rw-r--r--drivers/usb/host/ehci-hcd.c113
-rw-r--r--drivers/usb/host/ehci-hub.c36
-rw-r--r--drivers/usb/host/ehci-ixp4xx.c3
-rw-r--r--drivers/usb/host/ehci-pci.c9
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c5
-rw-r--r--drivers/usb/host/ehci-ps3.c1
-rw-r--r--drivers/usb/host/ehci-q.c108
-rw-r--r--drivers/usb/host/ehci-sched.c46
-rw-r--r--drivers/usb/host/isp116x-hcd.c14
-rw-r--r--drivers/usb/host/ohci-at91.c2
-rw-r--r--drivers/usb/host/ohci-au1xxx.c1
-rw-r--r--drivers/usb/host/ohci-dbg.c2
-rw-r--r--drivers/usb/host/ohci-ep93xx.c5
-rw-r--r--drivers/usb/host/ohci-hub.c128
-rw-r--r--drivers/usb/host/ohci-lh7a404.c1
-rw-r--r--drivers/usb/host/ohci-omap.c8
-rw-r--r--drivers/usb/host/ohci-pci.c47
-rw-r--r--drivers/usb/host/ohci-pnx4008.c1
-rw-r--r--drivers/usb/host/ohci-pnx8550.c1
-rw-r--r--drivers/usb/host/ohci-ppc-of.c1
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c1
-rw-r--r--drivers/usb/host/ohci-ps3.c2
-rw-r--r--drivers/usb/host/ohci-pxa27x.c6
-rw-r--r--drivers/usb/host/ohci-s3c2410.c1
-rw-r--r--drivers/usb/host/ohci-sa1111.c1
-rw-r--r--drivers/usb/host/ohci-sh.c1
-rw-r--r--drivers/usb/host/ohci-sm501.c16
-rw-r--r--drivers/usb/host/ohci-ssb.c37
-rw-r--r--drivers/usb/host/pci-quirks.c6
-rw-r--r--drivers/usb/host/r8a66597-hcd.c262
-rw-r--r--drivers/usb/host/r8a66597.h51
-rw-r--r--drivers/usb/host/sl811-hcd.c14
-rw-r--r--drivers/usb/host/u132-hcd.c5124
-rw-r--r--drivers/usb/host/uhci-hcd.c35
-rw-r--r--drivers/usb/host/uhci-q.c2
-rw-r--r--drivers/usb/image/Kconfig4
-rw-r--r--drivers/usb/image/microtek.c3
-rw-r--r--drivers/usb/image/microtek.h1
-rw-r--r--drivers/usb/misc/Kconfig20
-rw-r--r--drivers/usb/misc/adutux.c120
-rw-r--r--drivers/usb/misc/appledisplay.c6
-rw-r--r--drivers/usb/misc/auerswald.c135
-rw-r--r--drivers/usb/misc/emi26.c30
-rw-r--r--drivers/usb/misc/emi62.c32
-rw-r--r--drivers/usb/misc/ftdi-elan.c2
-rw-r--r--drivers/usb/misc/iowarrior.c10
-rw-r--r--drivers/usb/misc/ldusb.c10
-rw-r--r--drivers/usb/misc/legousbtower.c92
-rw-r--r--drivers/usb/misc/phidgetkit.c6
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c2
-rw-r--r--drivers/usb/misc/phidgetservo.c6
-rw-r--r--drivers/usb/misc/usblcd.c8
-rw-r--r--drivers/usb/misc/usbtest.c13
-rw-r--r--drivers/usb/mon/Makefile2
-rw-r--r--drivers/usb/mon/mon_bin.c9
-rw-r--r--drivers/usb/mon/mon_main.c3
-rw-r--r--drivers/usb/mon/mon_stat.c3
-rw-r--r--drivers/usb/serial/Kconfig76
-rw-r--r--drivers/usb/serial/Makefile3
-rw-r--r--drivers/usb/serial/aircable.c56
-rw-r--r--drivers/usb/serial/airprime.c37
-rw-r--r--drivers/usb/serial/ark3116.c10
-rw-r--r--drivers/usb/serial/belkin_sa.c23
-rw-r--r--drivers/usb/serial/ch341.c3
-rw-r--r--drivers/usb/serial/console.c10
-rw-r--r--drivers/usb/serial/cp2101.c114
-rw-r--r--drivers/usb/serial/cyberjack.c112
-rw-r--r--drivers/usb/serial/cypress_m8.c579
-rw-r--r--drivers/usb/serial/digi_acceleport.c50
-rw-r--r--drivers/usb/serial/empeg.c59
-rw-r--r--drivers/usb/serial/ezusb.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.c173
-rw-r--r--drivers/usb/serial/funsoft.c3
-rw-r--r--drivers/usb/serial/garmin_gps.c115
-rw-r--r--drivers/usb/serial/generic.c56
-rw-r--r--drivers/usb/serial/hp4x.c3
-rw-r--r--drivers/usb/serial/io_edgeport.c328
-rw-r--r--drivers/usb/serial/io_tables.h12
-rw-r--r--drivers/usb/serial/io_ti.c398
-rw-r--r--drivers/usb/serial/ipaq.c53
-rw-r--r--drivers/usb/serial/ipw.c51
-rw-r--r--drivers/usb/serial/ir-usb.c53
-rw-r--r--drivers/usb/serial/iuu_phoenix.c165
-rw-r--r--drivers/usb/serial/keyspan.c281
-rw-r--r--drivers/usb/serial/keyspan.h16
-rw-r--r--drivers/usb/serial/keyspan_pda.c42
-rw-r--r--drivers/usb/serial/kl5kusb105.c127
-rw-r--r--drivers/usb/serial/kobil_sct.c75
-rw-r--r--drivers/usb/serial/mct_u232.c41
-rw-r--r--drivers/usb/serial/mos7720.c122
-rw-r--r--drivers/usb/serial/mos7840.c164
-rw-r--r--drivers/usb/serial/navman.c31
-rw-r--r--drivers/usb/serial/omninet.c42
-rw-r--r--drivers/usb/serial/option.c92
-rw-r--r--drivers/usb/serial/oti6858.c134
-rw-r--r--drivers/usb/serial/pl2303.c117
-rw-r--r--drivers/usb/serial/safe_serial.c60
-rw-r--r--drivers/usb/serial/sierra.c129
-rw-r--r--drivers/usb/serial/spcp8x5.c1073
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c211
-rw-r--r--drivers/usb/serial/usb-serial.c107
-rw-r--r--drivers/usb/serial/usb_debug.c3
-rw-r--r--drivers/usb/serial/visor.c103
-rw-r--r--drivers/usb/serial/whiteheat.c118
-rw-r--r--drivers/usb/storage/Kconfig39
-rw-r--r--drivers/usb/storage/Makefile1
-rw-r--r--drivers/usb/storage/cypress_atacb.c200
-rw-r--r--drivers/usb/storage/cypress_atacb.h25
-rw-r--r--drivers/usb/storage/libusual.c14
-rw-r--r--drivers/usb/storage/scsiglue.c26
-rw-r--r--drivers/usb/storage/transport.c23
-rw-r--r--drivers/usb/storage/unusual_devs.h8
-rw-r--r--drivers/usb/storage/usb.c26
-rw-r--r--drivers/usb/usb-skeleton.c8
-rw-r--r--drivers/video/Kconfig87
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/am200epd.c295
-rw-r--r--drivers/video/amifb.c2
-rw-r--r--drivers/video/arkfb.c32
-rw-r--r--drivers/video/atafb.c2
-rw-r--r--drivers/video/atmel_lcdfb.c74
-rw-r--r--drivers/video/aty/aty128fb.c4
-rw-r--r--drivers/video/aty/atyfb_base.c7
-rw-r--r--drivers/video/aty/mach64_ct.c16
-rw-r--r--drivers/video/aty/radeon_base.c51
-rw-r--r--drivers/video/aty/radeon_i2c.c13
-rw-r--r--drivers/video/aty/radeon_monitor.c56
-rw-r--r--drivers/video/aty/radeonfb.h20
-rw-r--r--drivers/video/bf54x-lq043fb.c8
-rw-r--r--drivers/video/bw2.c5
-rw-r--r--drivers/video/cfbcopyarea.c23
-rw-r--r--drivers/video/cfbfillrect.c48
-rw-r--r--drivers/video/cfbimgblt.c54
-rw-r--r--drivers/video/cg14.c6
-rw-r--r--drivers/video/cg3.c2
-rw-r--r--drivers/video/cg6.c2
-rw-r--r--drivers/video/cirrusfb.c6
-rw-r--r--drivers/video/console/fbcon.c5
-rw-r--r--drivers/video/console/fbcon.h12
-rw-r--r--drivers/video/fb_draw.h31
-rw-r--r--drivers/video/fbmem.c95
-rw-r--r--drivers/video/ffb.c7
-rw-r--r--drivers/video/fsl-diu-fb.c1721
-rw-r--r--drivers/video/fsl-diu-fb.h223
-rw-r--r--drivers/video/geode/Kconfig20
-rw-r--r--drivers/video/geode/Makefile2
-rw-r--r--drivers/video/geode/display_gx.c125
-rw-r--r--drivers/video/geode/display_gx.h101
-rw-r--r--drivers/video/geode/gxfb.h358
-rw-r--r--drivers/video/geode/gxfb_core.c160
-rw-r--r--drivers/video/geode/lxfb.h527
-rw-r--r--drivers/video/geode/lxfb_core.c118
-rw-r--r--drivers/video/geode/lxfb_ops.c699
-rw-r--r--drivers/video/geode/suspend_gx.c267
-rw-r--r--drivers/video/geode/video_gx.c162
-rw-r--r--drivers/video/geode/video_gx.h72
-rw-r--r--drivers/video/gxt4500.c2
-rw-r--r--drivers/video/hecubafb.c302
-rw-r--r--drivers/video/imsttfb.c8
-rw-r--r--drivers/video/imxfb.c6
-rw-r--r--drivers/video/intelfb/intelfb.h12
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c2
-rw-r--r--drivers/video/intelfb/intelfbdrv.c12
-rw-r--r--drivers/video/intelfb/intelfbhw.c16
-rw-r--r--drivers/video/leo.c2
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c36
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c16
-rw-r--r--drivers/video/matrox/matroxfb_accel.c14
-rw-r--r--drivers/video/matrox/matroxfb_base.c42
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c2
-rw-r--r--drivers/video/matrox/matroxfb_maven.c2
-rw-r--r--drivers/video/matrox/matroxfb_misc.c12
-rw-r--r--drivers/video/metronomefb.c328
-rw-r--r--drivers/video/modedb.c26
-rw-r--r--drivers/video/n411.c202
-rw-r--r--drivers/video/nvidia/nv_hw.c4
-rw-r--r--drivers/video/nvidia/nv_setup.c4
-rw-r--r--drivers/video/nvidia/nvidia.c9
-rw-r--r--drivers/video/offb.c15
-rw-r--r--drivers/video/p9100.c2
-rw-r--r--drivers/video/pm2fb.c24
-rw-r--r--drivers/video/pm3fb.c4
-rw-r--r--drivers/video/riva/fbdev.c12
-rw-r--r--drivers/video/riva/nv_driver.c7
-rw-r--r--drivers/video/riva/riva_hw.c4
-rw-r--r--drivers/video/s3c2410fb.c6
-rw-r--r--drivers/video/s3fb.c34
-rw-r--r--drivers/video/sa1100fb.h2
-rw-r--r--drivers/video/savage/savagefb-i2c.c2
-rw-r--r--drivers/video/sis/sis.h2
-rw-r--r--drivers/video/sstfb.c10
-rw-r--r--drivers/video/stifb.c4
-rw-r--r--drivers/video/syscopyarea.c20
-rw-r--r--drivers/video/sysfillrect.c49
-rw-r--r--drivers/video/sysimgblt.c49
-rw-r--r--drivers/video/tcx.c10
-rw-r--r--drivers/video/tdfxfb.c2
-rw-r--r--drivers/video/tridentfb.c14
-rw-r--r--drivers/video/uvesafb.c9
-rw-r--r--drivers/video/vermilion/vermilion.c5
-rw-r--r--drivers/video/vt8623fb.c38
-rw-r--r--drivers/video/w100fb.c6
-rw-r--r--drivers/video/xen-fbfront.c550
-rw-r--r--drivers/xen/Kconfig19
-rw-r--r--drivers/xen/Makefile4
-rw-r--r--drivers/xen/balloon.c712
-rw-r--r--drivers/xen/events.c (renamed from arch/x86/xen/events.c)121
-rw-r--r--drivers/xen/features.c (renamed from arch/x86/xen/features.c)0
-rw-r--r--drivers/xen/grant-table.c37
-rw-r--r--drivers/xen/xenbus/xenbus_client.c6
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c32
-rw-r--r--drivers/xen/xencomm.c232
-rw-r--r--fs/9p/vfs_super.c7
-rw-r--r--fs/aio.c12
-rw-r--r--fs/binfmt_elf.c23
-rw-r--r--fs/binfmt_misc.c18
-rw-r--r--fs/binfmt_som.c10
-rw-r--r--fs/buffer.c20
-rw-r--r--fs/cifs/cifs_dfs_ref.c29
-rw-r--r--fs/cifs/cifsfs.c10
-rw-r--r--fs/cifs/cifsproto.h8
-rw-r--r--fs/dquot.c109
-rw-r--r--fs/exec.c28
-rw-r--r--fs/ext2/balloc.c29
-rw-r--r--fs/ext2/dir.c20
-rw-r--r--fs/ext2/ialloc.c12
-rw-r--r--fs/ext2/inode.c15
-rw-r--r--fs/ext2/super.c27
-rw-r--r--fs/ext2/xattr.c15
-rw-r--r--fs/ext2/xip.c53
-rw-r--r--fs/ext2/xip.h9
-rw-r--r--fs/ext3/balloc.c30
-rw-r--r--fs/ext3/ext3_jbd.c12
-rw-r--r--fs/ext3/fsync.c3
-rw-r--r--fs/ext3/ialloc.c6
-rw-r--r--fs/ext3/inode.c29
-rw-r--r--fs/ext3/namei.c37
-rw-r--r--fs/ext3/resize.c71
-rw-r--r--fs/ext3/super.c53
-rw-r--r--fs/ext3/xattr.c24
-rw-r--r--fs/ext3/xattr.h7
-rw-r--r--fs/ext4/super.c15
-rw-r--r--fs/fat/dir.c52
-rw-r--r--fs/fat/fatent.c9
-rw-r--r--fs/fat/file.c204
-rw-r--r--fs/fat/inode.c38
-rw-r--r--fs/fcntl.c40
-rw-r--r--fs/fuse/inode.c5
-rw-r--r--fs/gfs2/ops_address.c2
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/jbd/commit.c19
-rw-r--r--fs/jbd/journal.c18
-rw-r--r--fs/jbd/revoke.c2
-rw-r--r--fs/jbd/transaction.c38
-rw-r--r--fs/jffs2/README.Locking22
-rw-r--r--fs/jffs2/build.c1
-rw-r--r--fs/jffs2/debug.c164
-rw-r--r--fs/jffs2/debug.h6
-rw-r--r--fs/jffs2/dir.c58
-rw-r--r--fs/jffs2/erase.c80
-rw-r--r--fs/jffs2/file.c16
-rw-r--r--fs/jffs2/fs.c42
-rw-r--r--fs/jffs2/gc.c42
-rw-r--r--fs/jffs2/ioctl.c1
-rw-r--r--fs/jffs2/jffs2_fs_i.h4
-rw-r--r--fs/jffs2/jffs2_fs_sb.h7
-rw-r--r--fs/jffs2/nodelist.h2
-rw-r--r--fs/jffs2/nodemgmt.c24
-rw-r--r--fs/jffs2/readinode.c38
-rw-r--r--fs/jffs2/super.c14
-rw-r--r--fs/jffs2/wbuf.c28
-rw-r--r--fs/jffs2/write.c52
-rw-r--r--fs/lockd/svclock.c2
-rw-r--r--fs/lockd/svcsubs.c69
-rw-r--r--fs/locks.c33
-rw-r--r--fs/msdos/namei.c2
-rw-r--r--fs/namespace.c11
-rw-r--r--fs/ncpfs/inode.c6
-rw-r--r--fs/ncpfs/ioctl.c17
-rw-r--r--fs/ncpfs/ncpsign_kernel.c2
-rw-r--r--fs/nfs/super.c8
-rw-r--r--fs/nfsd/nfs4state.c3
-rw-r--r--fs/nfsd/nfs4xdr.c14
-rw-r--r--fs/nfsd/nfsctl.c65
-rw-r--r--fs/open.c2
-rw-r--r--fs/partitions/msdos.c20
-rw-r--r--fs/proc/proc_misc.c17
-rw-r--r--fs/proc/task_mmu.c18
-rw-r--r--fs/quota.c5
-rw-r--r--fs/quota_v1.c3
-rw-r--r--fs/quota_v2.c3
-rw-r--r--fs/reiserfs/bitmap.c8
-rw-r--r--fs/reiserfs/do_balan.c14
-rw-r--r--fs/reiserfs/ioctl.c4
-rw-r--r--fs/reiserfs/journal.c10
-rw-r--r--fs/reiserfs/namei.c8
-rw-r--r--fs/reiserfs/objectid.c7
-rw-r--r--fs/reiserfs/stree.c3
-rw-r--r--fs/reiserfs/super.c38
-rw-r--r--fs/super.c10
-rw-r--r--fs/sysfs/file.c14
-rw-r--r--fs/sysfs/group.c83
-rw-r--r--fs/sysfs/sysfs.h2
-rw-r--r--fs/udf/namei.c8
-rw-r--r--fs/ufs/balloc.c4
-rw-r--r--fs/ufs/dir.c14
-rw-r--r--fs/ufs/inode.c2
-rw-r--r--fs/ufs/swab.h36
-rw-r--r--fs/ufs/ufs.h2
-rw-r--r--fs/vfat/namei.c37
-rw-r--r--include/acpi/acconfig.h15
-rw-r--r--include/acpi/acdebug.h2
-rw-r--r--include/acpi/acdisasm.h38
-rw-r--r--include/acpi/acdispat.h31
-rw-r--r--include/acpi/acevents.h2
-rw-r--r--include/acpi/acexcep.h2
-rw-r--r--include/acpi/acglobal.h38
-rw-r--r--include/acpi/achware.h2
-rw-r--r--include/acpi/acinterp.h15
-rw-r--r--include/acpi/aclocal.h10
-rw-r--r--include/acpi/acmacros.h71
-rw-r--r--include/acpi/acnames.h2
-rw-r--r--include/acpi/acnamesp.h5
-rw-r--r--include/acpi/acobject.h5
-rw-r--r--include/acpi/acopcode.h6
-rw-r--r--include/acpi/acoutput.h2
-rw-r--r--include/acpi/acparser.h4
-rw-r--r--include/acpi/acpi.h2
-rw-r--r--include/acpi/acpiosxf.h2
-rw-r--r--include/acpi/acpixf.h7
-rw-r--r--include/acpi/acresrc.h3
-rw-r--r--include/acpi/acstruct.h5
-rw-r--r--include/acpi/actables.h2
-rw-r--r--include/acpi/actbl.h2
-rw-r--r--include/acpi/actbl1.h561
-rw-r--r--include/acpi/actypes.h93
-rw-r--r--include/acpi/acutils.h4
-rw-r--r--include/acpi/amlcode.h2
-rw-r--r--include/acpi/amlresrc.h2
-rw-r--r--include/acpi/platform/acenv.h2
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/acpi/platform/aclinux.h2
-rw-r--r--include/asm-alpha/bitops.h5
-rw-r--r--include/asm-alpha/bug.h16
-rw-r--r--include/asm-alpha/byteorder.h2
-rw-r--r--include/asm-alpha/pgtable.h2
-rw-r--r--include/asm-arm/arch-pxa/pxa3xx_nand.h18
-rw-r--r--include/asm-arm/arch-sa1100/ide.h6
-rw-r--r--include/asm-arm/pgtable.h3
-rw-r--r--include/asm-arm/plat-s3c/nand.h5
-rw-r--r--include/asm-avr32/pgtable.h8
-rw-r--r--include/asm-cris/arch-v10/ide.h11
-rw-r--r--include/asm-cris/pgtable.h4
-rw-r--r--include/asm-frv/pgtable.h2
-rw-r--r--include/asm-generic/bitops/__fls.h43
-rw-r--r--include/asm-generic/bitops/find.h2
-rw-r--r--include/asm-generic/bitops/fls64.h22
-rw-r--r--include/asm-generic/gpio.h15
-rw-r--r--include/asm-generic/iomap.h4
-rw-r--r--include/asm-ia64/bitops.h16
-rw-r--r--include/asm-ia64/gcc_intrin.h12
-rw-r--r--include/asm-ia64/hugetlb.h79
-rw-r--r--include/asm-ia64/kvm.h205
-rw-r--r--include/asm-ia64/kvm_host.h524
-rw-r--r--include/asm-ia64/kvm_para.h29
-rw-r--r--include/asm-ia64/page.h6
-rw-r--r--include/asm-ia64/pgtable.h3
-rw-r--r--include/asm-ia64/processor.h63
-rw-r--r--include/asm-ia64/system.h18
-rw-r--r--include/asm-m32r/pgtable.h10
-rw-r--r--include/asm-m68k/motorola_pgtable.h2
-rw-r--r--include/asm-m68k/sun3_pgtable.h2
-rw-r--r--include/asm-mips/bitops.h5
-rw-r--r--include/asm-mips/cmp.h18
-rw-r--r--include/asm-mips/cpu.h9
-rw-r--r--include/asm-mips/dec/ioasic.h2
-rw-r--r--include/asm-mips/ds1287.h27
-rw-r--r--include/asm-mips/gcmpregs.h117
-rw-r--r--include/asm-mips/gic.h487
-rw-r--r--include/asm-mips/io.h2
-rw-r--r--include/asm-mips/jmr3927/jmr3927.h4
-rw-r--r--include/asm-mips/jmr3927/tx3927.h2
-rw-r--r--include/asm-mips/jmr3927/txx927.h12
-rw-r--r--include/asm-mips/mach-au1x00/au1000.h26
-rw-r--r--include/asm-mips/mach-au1x00/au1xxx_ide.h42
-rw-r--r--include/asm-mips/mach-db1x00/db1200.h18
-rw-r--r--include/asm-mips/mach-generic/gpio.h6
-rw-r--r--include/asm-mips/mach-ip27/topology.h2
-rw-r--r--include/asm-mips/mach-pb1x00/pb1200.h18
-rw-r--r--include/asm-mips/mips-boards/generic.h1
-rw-r--r--include/asm-mips/mips-boards/launch.h35
-rw-r--r--include/asm-mips/mips-boards/malta.h23
-rw-r--r--include/asm-mips/mips-boards/maltaint.h27
-rw-r--r--include/asm-mips/mips-boards/maltasmp.h36
-rw-r--r--include/asm-mips/mipsmtregs.h8
-rw-r--r--include/asm-mips/pgtable-32.h4
-rw-r--r--include/asm-mips/pgtable-bits.h91
-rw-r--r--include/asm-mips/pgtable.h59
-rw-r--r--include/asm-mips/r4k-timer.h30
-rw-r--r--include/asm-mips/smp-ops.h1
-rw-r--r--include/asm-mips/smtc.h1
-rw-r--r--include/asm-mips/smvp.h19
-rw-r--r--include/asm-mips/traps.h2
-rw-r--r--include/asm-mips/tx4938/rbtx4938.h58
-rw-r--r--include/asm-mips/tx4938/tx4938.h38
-rw-r--r--include/asm-mips/tx4938/tx4938_mips.h54
-rw-r--r--include/asm-mips/txx9pio.h29
-rw-r--r--include/asm-mips/vr41xx/siu.h8
-rw-r--r--include/asm-mips/vr41xx/vr41xx.h8
-rw-r--r--include/asm-mn10300/pgtable.h3
-rw-r--r--include/asm-parisc/bitops.h1
-rw-r--r--include/asm-parisc/pgtable.h2
-rw-r--r--include/asm-powerpc/bitops.h5
-rw-r--r--include/asm-powerpc/fixmap.h106
-rw-r--r--include/asm-powerpc/highmem.h41
-rw-r--r--include/asm-powerpc/hugetlb.h79
-rw-r--r--include/asm-powerpc/io-defs.h101
-rw-r--r--include/asm-powerpc/io.h8
-rw-r--r--include/asm-powerpc/kdump.h5
-rw-r--r--include/asm-powerpc/kvm.h53
-rw-r--r--include/asm-powerpc/kvm_asm.h55
-rw-r--r--include/asm-powerpc/kvm_host.h152
-rw-r--r--include/asm-powerpc/kvm_para.h37
-rw-r--r--include/asm-powerpc/kvm_ppc.h88
-rw-r--r--include/asm-powerpc/mmu-44x.h2
-rw-r--r--include/asm-powerpc/paca.h1
-rw-r--r--include/asm-powerpc/page.h45
-rw-r--r--include/asm-powerpc/page_32.h6
-rw-r--r--include/asm-powerpc/page_64.h7
-rw-r--r--include/asm-powerpc/pgtable-ppc32.h3
-rw-r--r--include/asm-powerpc/pgtable-ppc64.h3
-rw-r--r--include/asm-powerpc/thread_info.h8
-rw-r--r--include/asm-ppc/mmu.h2
-rw-r--r--include/asm-ppc/mpc8260.h4
-rw-r--r--include/asm-ppc/mpc8xx.h4
-rw-r--r--include/asm-ppc/pgtable.h3
-rw-r--r--include/asm-s390/Kbuild1
-rw-r--r--include/asm-s390/bitops.h1
-rw-r--r--include/asm-s390/kvm.h41
-rw-r--r--include/asm-s390/kvm_host.h234
-rw-r--r--include/asm-s390/kvm_para.h150
-rw-r--r--include/asm-s390/kvm_virtio.h53
-rw-r--r--include/asm-s390/lowcore.h15
-rw-r--r--include/asm-s390/mmu.h1
-rw-r--r--include/asm-s390/mmu_context.h8
-rw-r--r--include/asm-s390/pgtable.h106
-rw-r--r--include/asm-s390/setup.h1
-rw-r--r--include/asm-sh/bitops.h1
-rw-r--r--include/asm-sh/hugetlb.h91
-rw-r--r--include/asm-sh/pgtable_32.h3
-rw-r--r--include/asm-sh/pgtable_64.h10
-rw-r--r--include/asm-sparc/pgtable.h7
-rw-r--r--include/asm-sparc/processor.h4
-rw-r--r--include/asm-sparc64/bitops.h1
-rw-r--r--include/asm-sparc64/floppy.h84
-rw-r--r--include/asm-sparc64/hugetlb.h84
-rw-r--r--include/asm-sparc64/isa.h47
-rw-r--r--include/asm-sparc64/page.h2
-rw-r--r--include/asm-sparc64/pgtable.h10
-rw-r--r--include/asm-sparc64/ptrace.h23
-rw-r--r--include/asm-sparc64/thread_info.h6
-rw-r--r--include/asm-um/pgtable.h10
-rw-r--r--include/asm-x86/bios_ebda.h2
-rw-r--r--include/asm-x86/bitops.h149
-rw-r--r--include/asm-x86/bitops_32.h166
-rw-r--r--include/asm-x86/bitops_64.h162
-rw-r--r--include/asm-x86/bootparam.h14
-rw-r--r--include/asm-x86/e820_64.h3
-rw-r--r--include/asm-x86/fixmap.h8
-rw-r--r--include/asm-x86/fixmap_32.h7
-rw-r--r--include/asm-x86/fixmap_64.h4
-rw-r--r--include/asm-x86/geode.h38
-rw-r--r--include/asm-x86/hugetlb.h91
-rw-r--r--include/asm-x86/io.h8
-rw-r--r--include/asm-x86/io_32.h6
-rw-r--r--include/asm-x86/io_64.h6
-rw-r--r--include/asm-x86/io_apic.h6
-rw-r--r--include/asm-x86/kvm.h41
-rw-r--r--include/asm-x86/kvm_host.h99
-rw-r--r--include/asm-x86/kvm_para.h55
-rw-r--r--include/asm-x86/mach-default/smpboot_hooks.h2
-rw-r--r--include/asm-x86/page.h1
-rw-r--r--include/asm-x86/paravirt.h43
-rw-r--r--include/asm-x86/pgalloc.h111
-rw-r--r--include/asm-x86/pgalloc_32.h95
-rw-r--r--include/asm-x86/pgalloc_64.h133
-rw-r--r--include/asm-x86/pgtable.h73
-rw-r--r--include/asm-x86/pgtable_32.h26
-rw-r--r--include/asm-x86/pgtable_64.h2
-rw-r--r--include/asm-x86/posix_types.h8
-rw-r--r--include/asm-x86/processor.h2
-rw-r--r--include/asm-x86/ptrace.h2
-rw-r--r--include/asm-x86/reboot.h2
-rw-r--r--include/asm-x86/rio.h11
-rw-r--r--include/asm-x86/unistd.h8
-rw-r--r--include/asm-x86/xen/events.h22
-rw-r--r--include/asm-x86/xen/grant_table.h7
-rw-r--r--include/asm-x86/xen/hypercall.h6
-rw-r--r--include/asm-x86/xen/interface.h28
-rw-r--r--include/asm-x86/xen/page.h168
-rw-r--r--include/asm-xtensa/pgtable.h4
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/bitmap.h6
-rw-r--r--include/linux/bitops.h140
-rw-r--r--include/linux/bootmem.h2
-rw-r--r--include/linux/bsg.h14
-rw-r--r--include/linux/cache.h4
-rw-r--r--include/linux/capability.h3
-rw-r--r--include/linux/compiler-gcc.h13
-rw-r--r--include/linux/cpumask.h22
-rw-r--r--include/linux/cpuset.h4
-rw-r--r--include/linux/device-mapper.h96
-rw-r--r--include/linux/dm-dirty-log.h (renamed from drivers/md/dm-log.h)84
-rw-r--r--include/linux/dm-io.h (renamed from drivers/md/dm-io.h)18
-rw-r--r--include/linux/dm-kcopyd.h47
-rw-r--r--include/linux/dmi.h1
-rw-r--r--include/linux/fb.h44
-rw-r--r--include/linux/file.h3
-rw-r--r--include/linux/fs.h13
-rw-r--r--include/linux/gfp.h44
-rw-r--r--include/linux/hdsmart.h126
-rw-r--r--include/linux/hid.h4
-rw-r--r--include/linux/hugetlb.h46
-rw-r--r--include/linux/i2o.h5
-rw-r--r--include/linux/ide.h276
-rw-r--r--include/linux/init_task.h3
-rw-r--r--include/linux/input.h8
-rw-r--r--include/linux/keyboard.h1
-rw-r--r--include/linux/kprobes.h34
-rw-r--r--include/linux/kvm.h130
-rw-r--r--include/linux/kvm_host.h59
-rw-r--r--include/linux/kvm_para.h11
-rw-r--r--include/linux/kvm_types.h2
-rw-r--r--include/linux/leds.h6
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/linux/list.h9
-rw-r--r--include/linux/lockd/lockd.h8
-rw-r--r--include/linux/memory_hotplug.h33
-rw-r--r--include/linux/mempolicy.h156
-rw-r--r--include/linux/mlx4/device.h40
-rw-r--r--include/linux/mlx4/qp.h4
-rw-r--r--include/linux/mm.h58
-rw-r--r--include/linux/mm_types.h9
-rw-r--r--include/linux/mmzone.h183
-rw-r--r--include/linux/msdos_fs.h10
-rw-r--r--include/linux/mtd/inftl.h5
-rw-r--r--include/linux/mtd/nftl.h5
-rw-r--r--include/linux/mtd/onenand.h3
-rw-r--r--include/linux/mtd/plat-ram.h5
-rw-r--r--include/linux/ncp_fs.h7
-rw-r--r--include/linux/nfsd/nfsd.h2
-rw-r--r--include/linux/nodemask.h22
-rw-r--r--include/linux/notifier.h1
-rw-r--r--include/linux/oom.h4
-rw-r--r--include/linux/page-flags.h319
-rw-r--r--include/linux/phy.h24
-rw-r--r--include/linux/prctl.h9
-rw-r--r--include/linux/quota.h21
-rw-r--r--include/linux/quotaops.h137
-rw-r--r--include/linux/raid/raid5.h7
-rw-r--r--include/linux/reiserfs_fs.h1
-rw-r--r--include/linux/sched.h7
-rw-r--r--include/linux/securebits.h25
-rw-r--r--include/linux/security.h912
-rw-r--r--include/linux/seqlock.h46
-rw-r--r--include/linux/serial_8250.h1
-rw-r--r--include/linux/serio.h1
-rw-r--r--include/linux/shmem_fs.h3
-rw-r--r--include/linux/slub_def.h16
-rw-r--r--include/linux/spi/ads7846.h3
-rw-r--r--include/linux/suspend.h15
-rw-r--r--include/linux/swap.h4
-rw-r--r--include/linux/synclink.h4
-rw-r--r--include/linux/sysfs.h4
-rw-r--r--include/linux/thermal.h39
-rw-r--r--include/linux/usb.h196
-rw-r--r--include/linux/usb/audio.h2
-rw-r--r--include/linux/usb/cdc.h4
-rw-r--r--include/linux/usb/ch9.h17
-rw-r--r--include/linux/usb/g_printer.h4
-rw-r--r--include/linux/usb/gadget.h2
-rw-r--r--include/linux/usb/gadgetfs.h16
-rw-r--r--include/linux/usb/input.h8
-rw-r--r--include/linux/usb/iowarrior.h6
-rw-r--r--include/linux/usb/isp116x.h6
-rw-r--r--include/linux/usb/midi.h2
-rw-r--r--include/linux/usb/net2280.h9
-rw-r--r--include/linux/usb/otg.h6
-rw-r--r--include/linux/usb/quirks.h5
-rw-r--r--include/linux/usb/rndis_host.h9
-rw-r--r--include/linux/usb/serial.h21
-rw-r--r--include/linux/usb/sl811.h5
-rw-r--r--include/linux/usb/usbnet.h8
-rw-r--r--include/linux/usb_usual.h1
-rw-r--r--include/linux/usbdevice_fs.h7
-rw-r--r--include/linux/vmalloc.h5
-rw-r--r--include/linux/vmstat.h6
-rw-r--r--include/linux/wm97xx.h314
-rw-r--r--include/linux/xfrm.h8
-rw-r--r--include/mtd/Kbuild1
-rw-r--r--include/net/compat.h3
-rw-r--r--include/scsi/scsi_device.h3
-rw-r--r--include/video/atmel_lcdc.h11
-rw-r--r--include/video/hecubafb.h51
-rw-r--r--include/video/metronomefb.h62
-rw-r--r--include/xen/balloon.h61
-rw-r--r--include/xen/events.h9
-rw-r--r--include/xen/grant_table.h7
-rw-r--r--include/xen/interface/callback.h102
-rw-r--r--include/xen/interface/grant_table.h11
-rw-r--r--include/xen/interface/io/fbif.h124
-rw-r--r--include/xen/interface/io/kbdif.h114
-rw-r--r--include/xen/interface/io/protocols.h21
-rw-r--r--include/xen/interface/memory.h12
-rw-r--r--include/xen/interface/vcpu.h5
-rw-r--r--include/xen/interface/xen.h22
-rw-r--r--include/xen/interface/xencomm.h41
-rw-r--r--include/xen/page.h181
-rw-r--r--include/xen/xen-ops.h8
-rw-r--r--include/xen/xenbus.h1
-rw-r--r--include/xen/xencomm.h77
-rw-r--r--init/Kconfig8
-rw-r--r--init/do_mounts_md.c2
-rw-r--r--init/do_mounts_rd.c2
-rw-r--r--init/main.c7
-rw-r--r--ipc/shm.c6
-rw-r--r--kernel/bounds.c23
-rw-r--r--kernel/cpuset.c25
-rw-r--r--kernel/exit.c8
-rw-r--r--kernel/fork.c66
-rw-r--r--kernel/hrtimer.c34
-rw-r--r--kernel/kexec.c3
-rw-r--r--kernel/kprobes.c349
-rw-r--r--kernel/pid_namespace.c2
-rw-r--r--kernel/power/Kconfig10
-rw-r--r--kernel/power/Makefile1
-rw-r--r--kernel/power/console.c27
-rw-r--r--kernel/power/pm.c205
-rw-r--r--kernel/ptrace.c7
-rw-r--r--kernel/sched.c54
-rw-r--r--kernel/sys.c27
-rw-r--r--kernel/time/tick-sched.c1
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/Kconfig.debug11
-rw-r--r--lib/Makefile1
-rw-r--r--lib/bitmap.c158
-rw-r--r--lib/find_next_bit.c77
-rw-r--r--lib/radix-tree.c9
-rw-r--r--mm/Kconfig12
-rw-r--r--mm/bootmem.c196
-rw-r--r--mm/dmapool.c12
-rw-r--r--mm/fadvise.c2
-rw-r--r--mm/filemap.c10
-rw-r--r--mm/filemap_xip.c200
-rw-r--r--mm/hugetlb.c78
-rw-r--r--mm/internal.h3
-rw-r--r--mm/madvise.c2
-rw-r--r--mm/memory.c228
-rw-r--r--mm/memory_hotplug.c186
-rw-r--r--mm/mempolicy.c1051
-rw-r--r--mm/mincore.c2
-rw-r--r--mm/mmap.c33
-rw-r--r--mm/mmzone.c30
-rw-r--r--mm/nommu.c6
-rw-r--r--mm/oom_kill.c58
-rw-r--r--mm/page_alloc.c274
-rw-r--r--mm/pagewalk.c8
-rw-r--r--mm/rmap.c8
-rw-r--r--mm/shmem.c144
-rw-r--r--mm/slab.c17
-rw-r--r--mm/slob.c3
-rw-r--r--mm/slub.c499
-rw-r--r--mm/sparse.c145
-rw-r--r--mm/swap.c37
-rw-r--r--mm/swapfile.c8
-rw-r--r--mm/truncate.c11
-rw-r--r--mm/vmalloc.c141
-rw-r--r--mm/vmscan.c46
-rw-r--r--mm/vmstat.c11
-rw-r--r--net/can/raw.c24
-rw-r--r--net/compat.c117
-rw-r--r--net/core/ethtool.c5
-rw-r--r--net/dccp/probe.c2
-rw-r--r--net/ipv4/ip_sockglue.c5
-rw-r--r--net/ipv4/tcp_input.c3
-rw-r--r--net/ipv4/tcp_probe.c9
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c5
-rw-r--r--net/ipv6/raw.c18
-rw-r--r--net/key/af_key.c5
-rw-r--r--net/mac80211/Kconfig4
-rw-r--r--net/mac80211/mesh.h1
-rw-r--r--net/mac80211/mesh_hwmp.c1
-rw-r--r--net/sunrpc/xprt.c2
-rw-r--r--net/tipc/msg.h7
-rw-r--r--net/tipc/socket.c4
-rw-r--r--net/xfrm/xfrm_algo.c3
-rw-r--r--net/xfrm/xfrm_state.c2
-rw-r--r--scripts/Makefile.build6
-rw-r--r--scripts/Makefile.clean2
-rw-r--r--scripts/Makefile.host12
-rw-r--r--scripts/Makefile.modpost8
-rwxr-xr-xscripts/checkpatch.pl7
-rw-r--r--scripts/gen_initramfs_list.sh2
-rw-r--r--scripts/kconfig/Makefile4
-rw-r--r--scripts/kconfig/lex.zconf.c_shipped25
-rw-r--r--scripts/kconfig/lkc_proto.h2
-rw-r--r--scripts/kconfig/lxdialog/inputbox.c2
-rw-r--r--scripts/kconfig/menu.c64
-rw-r--r--scripts/kconfig/symbol.c118
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped301
-rw-r--r--scripts/kconfig/zconf.y13
-rwxr-xr-xscripts/kernel-doc25
-rw-r--r--scripts/mod/modpost.c27
-rw-r--r--security/capability.c1
-rw-r--r--security/commoncap.c103
-rw-r--r--security/dummy.c2
-rw-r--r--security/root_plug.c1
-rw-r--r--security/security.c4
-rw-r--r--security/selinux/hooks.c5
-rw-r--r--security/selinux/include/avc_ss.h9
-rw-r--r--security/selinux/include/netlabel.h2
-rw-r--r--security/selinux/include/objsec.h60
-rw-r--r--security/selinux/include/security.h4
-rw-r--r--security/selinux/netnode.c104
-rw-r--r--security/selinux/netport.c40
-rw-r--r--security/selinux/ss/conditional.h6
-rw-r--r--security/selinux/ss/context.h4
-rw-r--r--security/selinux/ss/hashtab.h6
-rw-r--r--security/selinux/ss/mls.h6
-rw-r--r--security/selinux/ss/mls_types.h4
-rw-r--r--security/selinux/ss/policydb.h10
-rw-r--r--security/smack/smack_lsm.c3
-rw-r--r--security/smack/smackfs.c4
-rw-r--r--virt/kvm/kvm_main.c230
-rw-r--r--virt/kvm/kvm_trace.c276
2007 files changed, 85880 insertions, 42966 deletions
diff --git a/.gitignore b/.gitignore
index fdcce40226d7..3016ed30526d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@ TAGS
vmlinux*
!vmlinux.lds.S
System.map
+Module.markers
Module.symvers
!.gitignore
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index a82a113b4a4b..1977fab38656 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -329,8 +329,6 @@ sgi-visws.txt
- short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
-smart-config.txt
- - description of the Smart Config makefile feature.
sound/
- directory with info on sound card support.
sparc/
diff --git a/Documentation/ABI/stable/sysfs-class-ubi b/Documentation/ABI/stable/sysfs-class-ubi
new file mode 100644
index 000000000000..18d471d9faea
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-class-ubi
@@ -0,0 +1,212 @@
+What: /sys/class/ubi/
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ The ubi/ class sub-directory belongs to the UBI subsystem and
+ provides general UBI information, per-UBI device information
+ and per-UBI volume information.
+
+What: /sys/class/ubi/version
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ This file contains version of the latest supported UBI on-media
+ format. Currently it is 1, and there is no plan to change this.
+ However, if in the future UBI needs on-flash format changes
+ which cannot be done in a compatible manner, a new format
+ version will be added. So this is a mechanism for possible
+ future backward-compatible (but forward-incompatible)
+ improvements.
+
+What: /sys/class/ubiX/
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ The /sys/class/ubi0, /sys/class/ubi1, etc directories describe
+ UBI devices (UBI device 0, 1, etc). They contain general UBI
+ device information and per UBI volume information (each UBI
+ device may have many UBI volumes)
+
+What: /sys/class/ubi/ubiX/avail_eraseblocks
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Amount of available logical eraseblock. For example, one may
+ create a new UBI volume which has this amount of logical
+ eraseblocks.
+
+What: /sys/class/ubi/ubiX/bad_peb_count
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Count of bad physical eraseblocks on the underlying MTD device.
+
+What: /sys/class/ubi/ubiX/bgt_enabled
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Contains ASCII "0\n" if the UBI background thread is disabled,
+ and ASCII "1\n" if it is enabled.
+
+What: /sys/class/ubi/ubiX/dev
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Major and minor numbers of the character device corresponding
+ to this UBI device (in <major>:<minor> format).
+
+What: /sys/class/ubi/ubiX/eraseblock_size
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Maximum logical eraseblock size this UBI device may provide. UBI
+ volumes may have smaller logical eraseblock size because of their
+ alignment.
+
+What: /sys/class/ubi/ubiX/max_ec
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Maximum physical eraseblock erase counter value.
+
+What: /sys/class/ubi/ubiX/max_vol_count
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Maximum number of volumes which this UBI device may have.
+
+What: /sys/class/ubi/ubiX/min_io_size
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Minimum input/output unit size. All the I/O may only be done
+ in fractions of the contained number.
+
+What: /sys/class/ubi/ubiX/mtd_num
+Date: January 2008
+KernelVersion: 2.6.25
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Number of the underlying MTD device.
+
+What: /sys/class/ubi/ubiX/reserved_for_bad
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Number of physical eraseblocks reserved for bad block handling.
+
+What: /sys/class/ubi/ubiX/total_eraseblocks
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Total number of good (not marked as bad) physical eraseblocks on
+ the underlying MTD device.
+
+What: /sys/class/ubi/ubiX/volumes_count
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Count of volumes on this UBI device.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ The /sys/class/ubi/ubiX/ubiX_0/, /sys/class/ubi/ubiX/ubiX_1/,
+ etc directories describe UBI volumes on UBI device X (volumes
+ 0, 1, etc).
+
+What: /sys/class/ubi/ubiX/ubiX_Y/alignment
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Volume alignment - the value the logical eraseblock size of
+ this volume has to be aligned on. For example, 2048 means that
+ logical eraseblock size is multiple of 2048. In other words,
+ volume logical eraseblock size is UBI device logical eraseblock
+ size aligned to the alignment value.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/corrupted
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Contains ASCII "0\n" if the UBI volume is OK, and ASCII "1\n"
+ if it is corrupted (e.g., due to an interrupted volume update).
+
+What: /sys/class/ubi/ubiX/ubiX_Y/data_bytes
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ The amount of data this volume contains. This value makes sense
+ only for static volumes, and for dynamic volume it equivalent
+ to the total volume size in bytes.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/dev
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Major and minor numbers of the character device corresponding
+ to this UBI volume (in <major>:<minor> format).
+
+What: /sys/class/ubi/ubiX/ubiX_Y/name
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Volume name.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/reserved_ebs
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Count of physical eraseblock reserved for this volume.
+ Equivalent to the volume size in logical eraseblocks.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/type
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Volume type. Contains ASCII "dynamic\n" for dynamic volumes and
+ "static\n" for static volumes.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/upd_marker
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Contains ASCII "0\n" if the update marker is not set for this
+ volume, and "1\n" if it is set. The update marker is set when
+ volume update starts, and cleaned when it ends. So the presence
+ of the update marker indicates that the volume is being updated
+ at the moment of the update was interrupted. The later may be
+ checked using the "corrupted" sysfs file.
+
+What: /sys/class/ubi/ubiX/ubiX_Y/usable_eb_size
+Date: July 2006
+KernelVersion: 2.6.22
+Contact: Artem Bityutskiy <dedekind@infradead.org>
+Description:
+ Logical eraseblock size of this volume. Equivalent to logical
+ eraseblock size of the device aligned on the volume alignment
+ value.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index b2b6366bba51..83966e94cc32 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -187,8 +187,11 @@ quiet_cmd_fig2png = FIG2PNG $@
###
# Rule to convert a .c file to inline XML documentation
+ gen_xml = :
+ quiet_gen_xml = echo ' GEN $@'
+silent_gen_xml = :
%.xml: %.c
- @echo ' GEN $@'
+ @$($(quiet)gen_xml)
@( \
echo "<programlisting>"; \
expand --tabs=8 < $< | \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 488dd4a4945b..b7b1482f6e04 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -119,7 +119,7 @@ X!Ilib/string.c
!Elib/string.c
</sect1>
<sect1><title>Bit Operations</title>
-!Iinclude/asm-x86/bitops_32.h
+!Iinclude/asm-x86/bitops.h
</sect1>
</chapter>
@@ -645,4 +645,58 @@ X!Idrivers/video/console/fonts.c
!Edrivers/i2c/i2c-core.c
</chapter>
+ <chapter id="clk">
+ <title>Clock Framework</title>
+
+ <para>
+ The clock framework defines programming interfaces to support
+ software management of the system clock tree.
+ This framework is widely used with System-On-Chip (SOC) platforms
+ to support power management and various devices which may need
+ custom clock rates.
+ Note that these "clocks" don't relate to timekeeping or real
+ time clocks (RTCs), each of which have separate frameworks.
+ These <structname>struct clk</structname> instances may be used
+ to manage for example a 96 MHz signal that is used to shift bits
+ into and out of peripherals or busses, or otherwise trigger
+ synchronous state machine transitions in system hardware.
+ </para>
+
+ <para>
+ Power management is supported by explicit software clock gating:
+ unused clocks are disabled, so the system doesn't waste power
+ changing the state of transistors that aren't in active use.
+ On some systems this may be backed by hardware clock gating,
+ where clocks are gated without being disabled in software.
+ Sections of chips that are powered but not clocked may be able
+ to retain their last state.
+ This low power state is often called a <emphasis>retention
+ mode</emphasis>.
+ This mode still incurs leakage currents, especially with finer
+ circuit geometries, but for CMOS circuits power is mostly used
+ by clocked state changes.
+ </para>
+
+ <para>
+ Power-aware drivers only enable their clocks when the device
+ they manage is in active use. Also, system sleep states often
+ differ according to which clock domains are active: while a
+ "standby" state may allow wakeup from several active domains, a
+ "mem" (suspend-to-RAM) state may require a more wholesale shutdown
+ of clocks derived from higher speed PLLs and oscillators, limiting
+ the number of possible wakeup event sources. A driver's suspend
+ method may need to be aware of system-specific clock constraints
+ on the target sleep state.
+ </para>
+
+ <para>
+ Some platforms support programmable clock generators. These
+ can be used by external chips of various kinds, such as other
+ CPUs, multimedia codecs, and devices with strict requirements
+ for interface clocking.
+ </para>
+
+!Iinclude/linux/clk.h
+ </chapter>
+
</book>
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 54835610b3d6..0291ade44c17 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -249,9 +249,11 @@ process is as follows:
release a new -rc kernel every week.
- Process continues until the kernel is considered "ready", the
process should last around 6 weeks.
- - A list of known regressions present in each -rc release is
- tracked at the following URI:
- http://kernelnewbies.org/known_regressions
+ - Known regressions in each release are periodically posted to the
+ linux-kernel mailing list. The goal is to reduce the length of
+ that list to zero before declaring the kernel to be "ready," but, in
+ the real world, a small number of regressions often remain at
+ release time.
It is worth mentioning what Andrew Morton wrote on the linux-kernel
mailing list about kernel releases:
@@ -261,7 +263,7 @@ mailing list about kernel releases:
2.6.x.y -stable kernel tree
---------------------------
-Kernels with 4 digit versions are -stable kernels. They contain
+Kernels with 4-part versions are -stable kernels. They contain
relatively small and critical fixes for security problems or significant
regressions discovered in a given 2.6.x kernel.
@@ -273,7 +275,10 @@ If no 2.6.x.y kernel is available, then the highest numbered 2.6.x
kernel is the current stable kernel.
2.6.x.y are maintained by the "stable" team <stable@kernel.org>, and are
-released almost every other week.
+released as needs dictate. The normal release period is approximately
+two weeks, but it can be longer if there are no pressing problems. A
+security-related problem, instead, can cause a release to happen almost
+instantly.
The file Documentation/stable_kernel_rules.txt in the kernel tree
documents what kinds of changes are acceptable for the -stable tree, and
@@ -298,7 +303,9 @@ a while Andrew or the subsystem maintainer pushes it on to Linus for
inclusion in mainline.
It is heavily encouraged that all new patches get tested in the -mm tree
-before they are sent to Linus for inclusion in the main kernel tree.
+before they are sent to Linus for inclusion in the main kernel tree. Code
+which does not make an appearance in -mm before the opening of the merge
+window will prove hard to merge into the mainline.
These kernels are not appropriate for use on systems that are supposed
to be stable and they are more risky to run than any of the other
@@ -354,11 +361,12 @@ Here is a list of some of the different kernel trees available:
- SCSI, James Bottomley <James.Bottomley@SteelEye.com>
git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
+ - x86, Ingo Molnar <mingo@elte.hu>
+ git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
+
quilt trees:
- - USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de>
+ - USB, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de>
kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
- - x86-64, partly i386, Andi Kleen <ak@suse.de>
- ftp.firstfloor.org:/pub/ak/x86_64/quilt/
Other kernel trees can be found listed at http://git.kernel.org/ and in
the MAINTAINERS file.
@@ -392,8 +400,8 @@ If you want to be advised of the future bug reports, you can subscribe to the
bugme-new mailing list (only new bug reports are mailed here) or to the
bugme-janitor mailing list (every change in the bugzilla is mailed here)
- http://lists.osdl.org/mailman/listinfo/bugme-new
- http://lists.osdl.org/mailman/listinfo/bugme-janitors
+ http://lists.linux-foundation.org/mailman/listinfo/bugme-new
+ http://lists.linux-foundation.org/mailman/listinfo/bugme-janitors
diff --git a/Documentation/arm/Samsung-S3C24XX/NAND.txt b/Documentation/arm/Samsung-S3C24XX/NAND.txt
new file mode 100644
index 000000000000..bc478a3409b8
--- /dev/null
+++ b/Documentation/arm/Samsung-S3C24XX/NAND.txt
@@ -0,0 +1,30 @@
+ S3C24XX NAND Support
+ ====================
+
+Introduction
+------------
+
+Small Page NAND
+---------------
+
+The driver uses a 512 byte (1 page) ECC code for this setup. The
+ECC code is not directly compatible with the default kernel ECC
+code, so the driver enforces its own OOB layout and ECC parameters
+
+Large Page NAND
+---------------
+
+The driver is capable of handling NAND flash with a 2KiB page
+size, with support for hardware ECC generation and correction.
+
+Unlike the 512byte page mode, the driver generates ECC data for
+each 256 byte block in an 2KiB page. This means that more than
+one error in a page can be rectified. It also means that the
+OOB layout remains the default kernel layout for these flashes.
+
+
+Document Author
+---------------
+
+Ben Dooks, Copyright 2007 Simtec Electronics
+
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
index c31b76fa66c4..d04e1e30c47f 100644
--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
+++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
@@ -156,6 +156,8 @@ NAND
controller. If there are any problems the latest linux-mtd
code can be found from http://www.linux-mtd.infradead.org/
+ For more information see Documentation/arm/Samsung-S3C24XX/NAND.txt
+
Serial
------
diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt
new file mode 100644
index 000000000000..6680cab2c705
--- /dev/null
+++ b/Documentation/device-mapper/dm-crypt.txt
@@ -0,0 +1,52 @@
+dm-crypt
+=========
+
+Device-Mapper's "crypt" target provides transparent encryption of block devices
+using the kernel crypto API.
+
+Parameters: <cipher> <key> <iv_offset> <device path> <offset>
+
+<cipher>
+ Encryption cipher and an optional IV generation mode.
+ (In format cipher-chainmode-ivopts:ivmode).
+ Examples:
+ des
+ aes-cbc-essiv:sha256
+ twofish-ecb
+
+ /proc/crypto contains supported crypto modes
+
+<key>
+ Key used for encryption. It is encoded as a hexadecimal number.
+ You can only use key sizes that are valid for the selected cipher.
+
+<iv_offset>
+ The IV offset is a sector count that is added to the sector number
+ before creating the IV.
+
+<device path>
+ This is the device that is going to be used as backend and contains the
+ encrypted data. You can specify it as a path like /dev/xxx or a device
+ number <major>:<minor>.
+
+<offset>
+ Starting sector within the device where the encrypted data begins.
+
+Example scripts
+===============
+LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
+encryption with dm-crypt using the 'cryptsetup' utility, see
+http://luks.endorphin.org/
+
+[[
+#!/bin/sh
+# Create a crypt device using dmsetup
+dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
+]]
+
+[[
+#!/bin/sh
+# Create a crypt device using cryptsetup and LUKS header with default cipher
+cryptsetup luksFormat $1
+cryptsetup luksOpen $1 crypt1
+]]
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 354aec047c0e..881e6dd03aea 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -141,6 +141,7 @@ mkprep
mktables
mktree
modpost
+modules.order
modversions.h*
offset.h
offsets.h
@@ -171,6 +172,7 @@ sm_tbl*
split-include
tags
tftpboot.img
+timeconst.h
times.h*
tkparse
trix_boot.h
diff --git a/Documentation/fb/gxfb.txt b/Documentation/fb/gxfb.txt
new file mode 100644
index 000000000000..2f640903bbb2
--- /dev/null
+++ b/Documentation/fb/gxfb.txt
@@ -0,0 +1,52 @@
+[This file is cloned from VesaFB/aty128fb]
+
+What is gxfb?
+=================
+
+This is a graphics framebuffer driver for AMD Geode GX2 based processors.
+
+Advantages:
+
+ * No need to use AMD's VSA code (or other VESA emulation layer) in the
+ BIOS.
+ * It provides a nice large console (128 cols + 48 lines with 1024x768)
+ without using tiny, unreadable fonts.
+ * You can run XF68_FBDev on top of /dev/fb0
+ * Most important: boot logo :-)
+
+Disadvantages:
+
+ * graphic mode is slower than text mode...
+
+
+How to use it?
+==============
+
+Switching modes is done using gxfb.mode_option=<resolution>... boot
+parameter or using `fbset' program.
+
+See Documentation/fb/modedb.txt for more information on modedb
+resolutions.
+
+
+X11
+===
+
+XF68_FBDev should generally work fine, but it is non-accelerated.
+
+
+Configuration
+=============
+
+You can pass kernel command line options to gxfb with gxfb.<option>.
+For example, gxfb.mode_option=800x600@75.
+Accepted options:
+
+mode_option - specify the video mode. Of the form
+ <x>x<y>[-<bpp>][@<refresh>]
+vram - size of video ram (normally auto-detected)
+vt_switch - enable vt switching during suspend/resume. The vt
+ switch is slow, but harmless.
+
+--
+Andres Salomon <dilinger@debian.org>
diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt
index da5ee74219e8..27a3160650a4 100644
--- a/Documentation/fb/intelfb.txt
+++ b/Documentation/fb/intelfb.txt
@@ -14,6 +14,8 @@ graphics devices. These would include:
Intel 915GM
Intel 945G
Intel 945GM
+ Intel 965G
+ Intel 965GM
B. List of available options
diff --git a/Documentation/fb/lxfb.txt b/Documentation/fb/lxfb.txt
new file mode 100644
index 000000000000..38b3ca6f6ca7
--- /dev/null
+++ b/Documentation/fb/lxfb.txt
@@ -0,0 +1,52 @@
+[This file is cloned from VesaFB/aty128fb]
+
+What is lxfb?
+=================
+
+This is a graphics framebuffer driver for AMD Geode LX based processors.
+
+Advantages:
+
+ * No need to use AMD's VSA code (or other VESA emulation layer) in the
+ BIOS.
+ * It provides a nice large console (128 cols + 48 lines with 1024x768)
+ without using tiny, unreadable fonts.
+ * You can run XF68_FBDev on top of /dev/fb0
+ * Most important: boot logo :-)
+
+Disadvantages:
+
+ * graphic mode is slower than text mode...
+
+
+How to use it?
+==============
+
+Switching modes is done using lxfb.mode_option=<resolution>... boot
+parameter or using `fbset' program.
+
+See Documentation/fb/modedb.txt for more information on modedb
+resolutions.
+
+
+X11
+===
+
+XF68_FBDev should generally work fine, but it is non-accelerated.
+
+
+Configuration
+=============
+
+You can pass kernel command line options to lxfb with lxfb.<option>.
+For example, lxfb.mode_option=800x600@75.
+Accepted options:
+
+mode_option - specify the video mode. Of the form
+ <x>x<y>[-<bpp>][@<refresh>]
+vram - size of video ram (normally auto-detected)
+vt_switch - enable vt switching during suspend/resume. The vt
+ switch is slow, but harmless.
+
+--
+Andres Salomon <dilinger@debian.org>
diff --git a/Documentation/fb/metronomefb.txt b/Documentation/fb/metronomefb.txt
index b9a2e7b7e838..237ca412582d 100644
--- a/Documentation/fb/metronomefb.txt
+++ b/Documentation/fb/metronomefb.txt
@@ -1,7 +1,7 @@
Metronomefb
-----------
Maintained by Jaya Kumar <jayakumar.lkml.gmail.com>
-Last revised: Nov 20, 2007
+Last revised: Mar 10, 2008
Metronomefb is a driver for the Metronome display controller. The controller
is from E-Ink Corporation. It is intended to be used to drive the E-Ink
@@ -11,20 +11,18 @@ display media here http://www.e-ink.com/products/matrix/metronome.html .
Metronome is interfaced to the host CPU through the AMLCD interface. The
host CPU generates the control information and the image in a framebuffer
which is then delivered to the AMLCD interface by a host specific method.
-Currently, that's implemented for the PXA's LCDC controller. The display and
-error status are each pulled through individual GPIOs.
+The display and error status are each pulled through individual GPIOs.
-Metronomefb was written for the PXA255/gumstix/lyre combination and
-therefore currently has board set specific code in it. If other boards based on
-other architectures are available, then the host specific code can be separated
-and abstracted out.
+Metronomefb is platform independent and depends on a board specific driver
+to do all physical IO work. Currently, an example is implemented for the
+PXA board used in the AM-200 EPD devkit. This example is am200epd.c
Metronomefb requires waveform information which is delivered via the AMLCD
interface to the metronome controller. The waveform information is expected to
be delivered from userspace via the firmware class interface. The waveform file
can be compressed as long as your udev or hotplug script is aware of the need
-to uncompress it before delivering it. metronomefb will ask for waveform.wbf
-which would typically go into /lib/firmware/waveform.wbf depending on your
+to uncompress it before delivering it. metronomefb will ask for metronome.wbf
+which would typically go into /lib/firmware/metronome.wbf depending on your
udev/hotplug setup. I have only tested with a single waveform file which was
originally labeled 23P01201_60_WT0107_MTC. I do not know what it stands for.
Caution should be exercised when manipulating the waveform as there may be
diff --git a/Documentation/fb/modedb.txt b/Documentation/fb/modedb.txt
index 4fcdb4cf4cca..ec4dee75a354 100644
--- a/Documentation/fb/modedb.txt
+++ b/Documentation/fb/modedb.txt
@@ -125,8 +125,12 @@ There may be more modes.
amifb - Amiga chipset frame buffer
aty128fb - ATI Rage128 / Pro frame buffer
atyfb - ATI Mach64 frame buffer
+ pm2fb - Permedia 2/2V frame buffer
+ pm3fb - Permedia 3 frame buffer
+ sstfb - Voodoo 1/2 (SST1) chipset frame buffer
tdfxfb - 3D Fx frame buffer
tridentfb - Trident (Cyber)blade chipset frame buffer
+ vt8623fb - VIA 8623 frame buffer
BTW, only a few drivers use this at the moment. Others are to follow
(feel free to send patches).
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 448729fcaeb1..599fe55bf297 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -128,15 +128,6 @@ Who: Arjan van de Ven <arjan@linux.intel.com>
---------------------------
-What: vm_ops.nopage
-When: Soon, provided in-kernel callers have been converted
-Why: This interface is replaced by vm_ops.fault, but it has been around
- forever, is used by a lot of drivers, and doesn't cost much to
- maintain.
-Who: Nick Piggin <npiggin@suse.de>
-
----------------------------
-
What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
When: October 2008
Why: The stacking of class devices makes these values misleading and
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 42d4b30b1045..c2992bc54f2f 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -511,7 +511,6 @@ prototypes:
void (*open)(struct vm_area_struct*);
void (*close)(struct vm_area_struct*);
int (*fault)(struct vm_area_struct*, struct vm_fault *);
- struct page *(*nopage)(struct vm_area_struct*, unsigned long, int *);
int (*page_mkwrite)(struct vm_area_struct *, struct page *);
locking rules:
@@ -519,7 +518,6 @@ locking rules:
open: no yes
close: no yes
fault: no yes
-nopage: no yes
page_mkwrite: no yes no
->page_mkwrite() is called when a previously read-only page is
@@ -537,4 +535,3 @@ NULL.
ipc/shm.c::shm_delete() - may need BKL.
->read() and ->write() in many drivers are (probably) missing BKL.
-drivers/sgi/char/graphics.c::sgi_graphics_nopage() - may need BKL.
diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs-rdma.txt
index 1ae34879574b..d0ec45ae4e7d 100644
--- a/Documentation/filesystems/nfs-rdma.txt
+++ b/Documentation/filesystems/nfs-rdma.txt
@@ -5,7 +5,7 @@
################################################################################
Author: NetApp and Open Grid Computing
- Date: February 25, 2008
+ Date: April 15, 2008
Table of Contents
~~~~~~~~~~~~~~~~~
@@ -197,12 +197,16 @@ NFS/RDMA Setup
- On the server system, configure the /etc/exports file and
start the NFS/RDMA server.
- Exports entries with the following format have been tested:
+ Exports entries with the following formats have been tested:
- /vol0 10.97.103.47(rw,async) 192.168.0.47(rw,async,insecure,no_root_squash)
+ /vol0 192.168.0.47(fsid=0,rw,async,insecure,no_root_squash)
+ /vol0 192.168.0.0/255.255.255.0(fsid=0,rw,async,insecure,no_root_squash)
- Here the first IP address is the client's Ethernet address and the second
- IP address is the clients IPoIB address.
+ The IP address(es) is(are) the client's IPoIB address for an InfiniBand HCA or the
+ cleint's iWARP address(es) for an RNIC.
+
+ NOTE: The "insecure" option must be used because the NFS/RDMA client does not
+ use a reserved port.
Each time a machine boots:
diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt
index 7fb8e6dc62bf..b843743aa0b5 100644
--- a/Documentation/filesystems/seq_file.txt
+++ b/Documentation/filesystems/seq_file.txt
@@ -122,8 +122,7 @@ stop() is the place to free it.
}
Finally, the show() function should format the object currently pointed to
-by the iterator for output. It should return zero, or an error code if
-something goes wrong. The example module's show() function is:
+by the iterator for output. The example module's show() function is:
static int ct_seq_show(struct seq_file *s, void *v)
{
@@ -132,6 +131,12 @@ something goes wrong. The example module's show() function is:
return 0;
}
+If all is well, the show() function should return zero. A negative error
+code in the usual manner indicates that something went wrong; it will be
+passed back to user space. This function can also return SEQ_SKIP, which
+causes the current item to be skipped; if the show() function has already
+generated output before returning SEQ_SKIP, that output will be dropped.
+
We will look at seq_printf() in a moment. But first, the definition of the
seq_file iterator is finished by creating a seq_operations structure with
the four functions we have just defined:
@@ -182,12 +187,18 @@ The first two output a single character and a string, just like one would
expect. seq_escape() is like seq_puts(), except that any character in s
which is in the string esc will be represented in octal form in the output.
-There is also a function for printing filenames:
+There is also a pair of functions for printing filenames:
int seq_path(struct seq_file *m, struct path *path, char *esc);
+ int seq_path_root(struct seq_file *m, struct path *path,
+ struct path *root, char *esc)
Here, path indicates the file of interest, and esc is a set of characters
-which should be escaped in the output.
+which should be escaped in the output. A call to seq_path() will output
+the path relative to the current process's filesystem root. If a different
+root is desired, it can be used with seq_path_root(). Note that, if it
+turns out that path cannot be reached from root, the value of root will be
+changed in seq_file_root() to a root which *does* work.
Making it all work
diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt
index 145e44086358..222437efd75a 100644
--- a/Documentation/filesystems/tmpfs.txt
+++ b/Documentation/filesystems/tmpfs.txt
@@ -92,6 +92,18 @@ NodeList format is a comma-separated list of decimal numbers and ranges,
a range being two hyphen-separated decimal numbers, the smallest and
largest node numbers in the range. For example, mpol=bind:0-3,5,7,9-15
+NUMA memory allocation policies have optional flags that can be used in
+conjunction with their modes. These optional flags can be specified
+when tmpfs is mounted by appending them to the mode before the NodeList.
+See Documentation/vm/numa_memory_policy.txt for a list of all available
+memory allocation policy mode flags.
+
+ =static is equivalent to MPOL_F_STATIC_NODES
+ =relative is equivalent to MPOL_F_RELATIVE_NODES
+
+For example, mpol=bind=static:NodeList, is the equivalent of an
+allocation policy of MPOL_BIND | MPOL_F_STATIC_NODES.
+
Note that trying to mount a tmpfs with an mpol option will fail if the
running kernel does not support NUMA; and will fail if its nodelist
specifies a node which is not online. If your system relies on that
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index fcc123ffa252..2d5e1e582e13 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -17,6 +17,21 @@ dmask=### -- The permission mask for the directory.
fmask=### -- The permission mask for files.
The default is the umask of current process.
+allow_utime=### -- This option controls the permission check of mtime/atime.
+
+ 20 - If current process is in group of file's group ID,
+ you can change timestamp.
+ 2 - Other users can change timestamp.
+
+ The default is set from `dmask' option. (If the directory is
+ writable, utime(2) is also allowed. I.e. ~dmask & 022)
+
+ Normally utime(2) checks current process is owner of
+ the file, or it has CAP_FOWNER capability. But FAT
+ filesystem doesn't have uid/gid on disk, so normal
+ check is too unflexible. With this option you can
+ relax it.
+
codepage=### -- Sets the codepage number for converting to shortname
characters on FAT filesystem.
By default, FAT_DEFAULT_CODEPAGE setting is used.
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 54630095aa3c..c35ca9e40d4c 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -107,6 +107,16 @@ type of GPIO controller, and on one particular board 80-95 with an FPGA.
The numbers need not be contiguous; either of those platforms could also
use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders.
+If you want to initialize a structure with an invalid GPIO number, use
+some negative number (perhaps "-EINVAL"); that will never be valid. To
+test if a number could reference a GPIO, you may use this predicate:
+
+ int gpio_is_valid(int number);
+
+A number that's not valid will be rejected by calls which may request
+or free GPIOs (see below). Other numbers may also be rejected; for
+example, a number might be valid but unused on a given board.
+
Whether a platform supports multiple GPIO controllers is currently a
platform-specific implementation issue.
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 2eb16100bb3f..0fac3465f2e3 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -42,6 +42,8 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable.
Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of
the boot command line
+Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical
+ pointer to single linked list of struct setup_data.
**** MEMORY LAYOUT
@@ -172,6 +174,8 @@ Offset Proto Name Meaning
0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data
0248/4 2.08+ payload_offset Offset of kernel payload
024C/4 2.08+ payload_length Length of kernel payload
+0250/8 2.09+ setup_data 64-bit physical pointer to linked list
+ of struct setup_data
(1) For backwards compatibility, if the setup_sects field contains 0, the
real value is 4.
@@ -572,6 +576,28 @@ command line is entered using the following protocol:
covered by setup_move_size, so you may need to adjust this
field.
+Field name: setup_data
+Type: write (obligatory)
+Offset/size: 0x250/8
+Protocol: 2.09+
+
+ The 64-bit physical pointer to NULL terminated single linked list of
+ struct setup_data. This is used to define a more extensible boot
+ parameters passing mechanism. The definition of struct setup_data is
+ as follow:
+
+ struct setup_data {
+ u64 next;
+ u32 type;
+ u32 len;
+ u8 data[0];
+ };
+
+ Where, the next is a 64-bit physical pointer to the next node of
+ linked list, the next field of the last node is 0; the type is used
+ to identify the contents of data; the len is the length of data
+ field; the data holds the real payload.
+
**** MEMORY LAYOUT OF THE REAL-MODE CODE
diff --git a/Documentation/ia64/kvm.txt b/Documentation/ia64/kvm.txt
new file mode 100644
index 000000000000..bec9d815da33
--- /dev/null
+++ b/Documentation/ia64/kvm.txt
@@ -0,0 +1,82 @@
+Currently, kvm module in EXPERIMENTAL stage on IA64. This means that
+interfaces are not stable enough to use. So, plase had better don't run
+critical applications in virtual machine. We will try our best to make it
+strong in future versions!
+ Guide: How to boot up guests on kvm/ia64
+
+This guide is to describe how to enable kvm support for IA-64 systems.
+
+1. Get the kvm source from git.kernel.org.
+ Userspace source:
+ git clone git://git.kernel.org/pub/scm/virt/kvm/kvm-userspace.git
+ Kernel Source:
+ git clone git://git.kernel.org/pub/scm/linux/kernel/git/xiantao/kvm-ia64.git
+
+2. Compile the source code.
+ 2.1 Compile userspace code:
+ (1)cd ./kvm-userspace
+ (2)./configure
+ (3)cd kernel
+ (4)make sync LINUX= $kernel_dir (kernel_dir is the directory of kernel source.)
+ (5)cd ..
+ (6)make qemu
+ (7)cd qemu; make install
+
+ 2.2 Compile kernel source code:
+ (1) cd ./$kernel_dir
+ (2) Make menuconfig
+ (3) Enter into virtualization option, and choose kvm.
+ (4) make
+ (5) Once (4) done, make modules_install
+ (6) Make initrd, and use new kernel to reboot up host machine.
+ (7) Once (6) done, cd $kernel_dir/arch/ia64/kvm
+ (8) insmod kvm.ko; insmod kvm-intel.ko
+
+Note: For step 2, please make sure that host page size == TARGET_PAGE_SIZE of qemu, otherwise, may fail.
+
+3. Get Guest Firmware named as Flash.fd, and put it under right place:
+ (1) If you have the guest firmware (binary) released by Intel Corp for Xen, use it directly.
+
+ (2) If you have no firmware at hand, Please download its source from
+ hg clone http://xenbits.xensource.com/ext/efi-vfirmware.hg
+ you can get the firmware's binary in the directory of efi-vfirmware.hg/binaries.
+
+ (3) Rename the firware you owned to Flash.fd, and copy it to /usr/local/share/qemu
+
+4. Boot up Linux or Windows guests:
+ 4.1 Create or install a image for guest boot. If you have xen experience, it should be easy.
+
+ 4.2 Boot up guests use the following command.
+ /usr/local/bin/qemu-system-ia64 -smp xx -m 512 -hda $your_image
+ (xx is the number of virtual processors for the guest, now the maximum value is 4)
+
+5. Known possibile issue on some platforms with old Firmware.
+
+If meet strange host crashe issues, try to solve it through either of the following ways:
+
+(1): Upgrade your Firmware to the latest one.
+
+(2): Applying the below patch to kernel source.
+diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S
+index 0b53344..f02b0f7 100644
+--- a/arch/ia64/kernel/pal.S
++++ b/arch/ia64/kernel/pal.S
+@@ -84,7 +84,8 @@ GLOBAL_ENTRY(ia64_pal_call_static)
+ mov ar.pfs = loc1
+ mov rp = loc0
+ ;;
+- srlz.d // seralize restoration of psr.l
++ srlz.i // seralize restoration of psr.l
++ ;;
+ br.ret.sptk.many b0
+ END(ia64_pal_call_static)
+
+6. Bug report:
+ If you found any issues when use kvm/ia64, Please post the bug info to kvm-ia64-devel mailing list.
+ https://lists.sourceforge.net/lists/listinfo/kvm-ia64-devel/
+
+Thanks for your interest! Let's work together, and make kvm/ia64 stronger and stronger!
+
+
+ Xiantao Zhang <xiantao.zhang@intel.com>
+ 2008.3.10
diff --git a/Documentation/ide/ide-tape.txt b/Documentation/ide/ide-tape.txt
index 658f271a373f..3f348a0b21d8 100644
--- a/Documentation/ide/ide-tape.txt
+++ b/Documentation/ide/ide-tape.txt
@@ -1,146 +1,65 @@
-/*
- * IDE ATAPI streaming tape driver.
- *
- * This driver is a part of the Linux ide driver.
- *
- * The driver, in co-operation with ide.c, basically traverses the
- * request-list for the block device interface. The character device
- * interface, on the other hand, creates new requests, adds them
- * to the request-list of the block device, and waits for their completion.
- *
- * Pipelined operation mode is now supported on both reads and writes.
- *
- * The block device major and minor numbers are determined from the
- * tape's relative position in the ide interfaces, as explained in ide.c.
- *
- * The character device interface consists of the following devices:
- *
- * ht0 major 37, minor 0 first IDE tape, rewind on close.
- * ht1 major 37, minor 1 second IDE tape, rewind on close.
- * ...
- * nht0 major 37, minor 128 first IDE tape, no rewind on close.
- * nht1 major 37, minor 129 second IDE tape, no rewind on close.
- * ...
- *
- * The general magnetic tape commands compatible interface, as defined by
- * include/linux/mtio.h, is accessible through the character device.
- *
- * General ide driver configuration options, such as the interrupt-unmask
- * flag, can be configured by issuing an ioctl to the block device interface,
- * as any other ide device.
- *
- * Our own ide-tape ioctl's can be issued to either the block device or
- * the character device interface.
- *
- * Maximal throughput with minimal bus load will usually be achieved in the
- * following scenario:
- *
- * 1. ide-tape is operating in the pipelined operation mode.
- * 2. No buffering is performed by the user backup program.
- *
- * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
- *
- * Here are some words from the first releases of hd.c, which are quoted
- * in ide.c and apply here as well:
- *
- * | Special care is recommended. Have Fun!
- *
- *
- * An overview of the pipelined operation mode.
- *
- * In the pipelined write mode, we will usually just add requests to our
- * pipeline and return immediately, before we even start to service them. The
- * user program will then have enough time to prepare the next request while
- * we are still busy servicing previous requests. In the pipelined read mode,
- * the situation is similar - we add read-ahead requests into the pipeline,
- * before the user even requested them.
- *
- * The pipeline can be viewed as a "safety net" which will be activated when
- * the system load is high and prevents the user backup program from keeping up
- * with the current tape speed. At this point, the pipeline will get
- * shorter and shorter but the tape will still be streaming at the same speed.
- * Assuming we have enough pipeline stages, the system load will hopefully
- * decrease before the pipeline is completely empty, and the backup program
- * will be able to "catch up" and refill the pipeline again.
- *
- * When using the pipelined mode, it would be best to disable any type of
- * buffering done by the user program, as ide-tape already provides all the
- * benefits in the kernel, where it can be done in a more efficient way.
- * As we will usually not block the user program on a request, the most
- * efficient user code will then be a simple read-write-read-... cycle.
- * Any additional logic will usually just slow down the backup process.
- *
- * Using the pipelined mode, I get a constant over 400 KBps throughput,
- * which seems to be the maximum throughput supported by my tape.
- *
- * However, there are some downfalls:
- *
- * 1. We use memory (for data buffers) in proportional to the number
- * of pipeline stages (each stage is about 26 KB with my tape).
- * 2. In the pipelined write mode, we cheat and postpone error codes
- * to the user task. In read mode, the actual tape position
- * will be a bit further than the last requested block.
- *
- * Concerning (1):
- *
- * 1. We allocate stages dynamically only when we need them. When
- * we don't need them, we don't consume additional memory. In
- * case we can't allocate stages, we just manage without them
- * (at the expense of decreased throughput) so when Linux is
- * tight in memory, we will not pose additional difficulties.
- *
- * 2. The maximum number of stages (which is, in fact, the maximum
- * amount of memory) which we allocate is limited by the compile
- * time parameter IDETAPE_MAX_PIPELINE_STAGES.
- *
- * 3. The maximum number of stages is a controlled parameter - We
- * don't start from the user defined maximum number of stages
- * but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
- * will not even allocate this amount of stages if the user
- * program can't handle the speed). We then implement a feedback
- * loop which checks if the pipeline is empty, and if it is, we
- * increase the maximum number of stages as necessary until we
- * reach the optimum value which just manages to keep the tape
- * busy with minimum allocated memory or until we reach
- * IDETAPE_MAX_PIPELINE_STAGES.
- *
- * Concerning (2):
- *
- * In pipelined write mode, ide-tape can not return accurate error codes
- * to the user program since we usually just add the request to the
- * pipeline without waiting for it to be serviced. In case an error
- * occurs, I will report it on the next user request.
- *
- * In the pipelined read mode, subsequent read requests or forward
- * filemark spacing will perform correctly, as we preserve all blocks
- * and filemarks which we encountered during our excess read-ahead.
- *
- * For accurate tape positioning and error reporting, disabling
- * pipelined mode might be the best option.
- *
- * You can enable/disable/tune the pipelined operation mode by adjusting
- * the compile time parameters below.
- *
- *
- * Possible improvements.
- *
- * 1. Support for the ATAPI overlap protocol.
- *
- * In order to maximize bus throughput, we currently use the DSC
- * overlap method which enables ide.c to service requests from the
- * other device while the tape is busy executing a command. The
- * DSC overlap method involves polling the tape's status register
- * for the DSC bit, and servicing the other device while the tape
- * isn't ready.
- *
- * In the current QIC development standard (December 1995),
- * it is recommended that new tape drives will *in addition*
- * implement the ATAPI overlap protocol, which is used for the
- * same purpose - efficient use of the IDE bus, but is interrupt
- * driven and thus has much less CPU overhead.
- *
- * ATAPI overlap is likely to be supported in most new ATAPI
- * devices, including new ATAPI cdroms, and thus provides us
- * a method by which we can achieve higher throughput when
- * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
- */
+IDE ATAPI streaming tape driver.
+
+This driver is a part of the Linux ide driver.
+
+The driver, in co-operation with ide.c, basically traverses the
+request-list for the block device interface. The character device
+interface, on the other hand, creates new requests, adds them
+to the request-list of the block device, and waits for their completion.
+
+The block device major and minor numbers are determined from the
+tape's relative position in the ide interfaces, as explained in ide.c.
+
+The character device interface consists of the following devices:
+
+ht0 major 37, minor 0 first IDE tape, rewind on close.
+ht1 major 37, minor 1 second IDE tape, rewind on close.
+...
+nht0 major 37, minor 128 first IDE tape, no rewind on close.
+nht1 major 37, minor 129 second IDE tape, no rewind on close.
+...
+
+The general magnetic tape commands compatible interface, as defined by
+include/linux/mtio.h, is accessible through the character device.
+
+General ide driver configuration options, such as the interrupt-unmask
+flag, can be configured by issuing an ioctl to the block device interface,
+as any other ide device.
+
+Our own ide-tape ioctl's can be issued to either the block device or
+the character device interface.
+
+Maximal throughput with minimal bus load will usually be achieved in the
+following scenario:
+
+ 1. ide-tape is operating in the pipelined operation mode.
+ 2. No buffering is performed by the user backup program.
+
+Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
+
+Here are some words from the first releases of hd.c, which are quoted
+in ide.c and apply here as well:
+
+| Special care is recommended. Have Fun!
+
+Possible improvements:
+
+1. Support for the ATAPI overlap protocol.
+
+In order to maximize bus throughput, we currently use the DSC
+overlap method which enables ide.c to service requests from the
+other device while the tape is busy executing a command. The
+DSC overlap method involves polling the tape's status register
+for the DSC bit, and servicing the other device while the tape
+isn't ready.
+
+In the current QIC development standard (December 1995),
+it is recommended that new tape drives will *in addition*
+implement the ATAPI overlap protocol, which is used for the
+same purpose - efficient use of the IDE bus, but is interrupt
+driven and thus has much less CPU overhead.
+
+ATAPI overlap is likely to be supported in most new ATAPI
+devices, including new ATAPI cdroms, and thus provides us
+a method by which we can achieve higher throughput when
+sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
diff --git a/Documentation/ide/ide.txt b/Documentation/ide/ide.txt
index 486c699f4aea..0c78f4b1d9d9 100644
--- a/Documentation/ide/ide.txt
+++ b/Documentation/ide/ide.txt
@@ -82,27 +82,26 @@ Drives are normally found by auto-probing and/or examining the CMOS/BIOS data.
For really weird situations, the apparent (fdisk) geometry can also be specified
on the kernel "command line" using LILO. The format of such lines is:
- hdx=cyls,heads,sects
-or hdx=cdrom
+ ide_core.chs=[interface_number.device_number]:cyls,heads,sects
+or ide_core.cdrom=[interface_number.device_number]
-where hdx can be any of hda through hdh, Three values are required
-(cyls,heads,sects). For example:
+For example:
- hdc=1050,32,64 hdd=cdrom
+ ide_core.chs=1.0:1050,32,64 ide_core.cdrom=1.1
-either {hda,hdb} or {hdc,hdd}. The results of successful auto-probing may
-override the physical geometry/irq specified, though the "original" geometry
-may be retained as the "logical" geometry for partitioning purposes (fdisk).
+The results of successful auto-probing may override the physical geometry/irq
+specified, though the "original" geometry may be retained as the "logical"
+geometry for partitioning purposes (fdisk).
If the auto-probing during boot time confuses a drive (ie. the drive works
with hd.c but not with ide.c), then an command line option may be specified
for each drive for which you'd like the drive to skip the hardware
probe/identification sequence. For example:
- hdb=noprobe
+ ide_core.noprobe=0.1
or
- hdc=768,16,32
- hdc=noprobe
+ ide_core.chs=1.0:768,16,32
+ ide_core.noprobe=1.0
Note that when only one IDE device is attached to an interface, it should be
jumpered as "single" or "master", *not* "slave". Many folks have had
@@ -118,9 +117,9 @@ If for some reason your cdrom drive is *not* found at boot time, you can force
the probe to look harder by supplying a kernel command line parameter
via LILO, such as:
- hdc=cdrom /* hdc = "master" on second interface */
+ ide_core.cdrom=1.0 /* "master" on second interface (hdc) */
or
- hdd=cdrom /* hdd = "slave" on second interface */
+ ide_core.cdrom=1.1 /* "slave" on second interface (hdd) */
For example, a GW2000 system might have a hard drive on the primary
interface (/dev/hda) and an IDE cdrom drive on the secondary interface
@@ -174,9 +173,7 @@ to /etc/modprobe.conf.
When ide.c is used as a module, you can pass command line parameters to the
driver using the "options=" keyword to insmod, while replacing any ',' with
-';'. For example:
-
- insmod ide.o options="hda=nodma hdb=nodma"
+';'.
================================================================================
@@ -184,57 +181,6 @@ driver using the "options=" keyword to insmod, while replacing any ',' with
Summary of ide driver parameters for kernel command line
--------------------------------------------------------
- "hdx=" is recognized for all "x" from "a" to "u", such as "hdc".
-
- "idex=" is recognized for all "x" from "0" to "9", such as "ide1".
-
- "hdx=noprobe" : drive may be present, but do not probe for it
-
- "hdx=none" : drive is NOT present, ignore cmos and do not probe
-
- "hdx=nowerr" : ignore the WRERR_STAT bit on this drive
-
- "hdx=cdrom" : drive is present, and is a cdrom drive
-
- "hdx=cyl,head,sect" : disk drive is present, with specified geometry
-
- "hdx=autotune" : driver will attempt to tune interface speed
- to the fastest PIO mode supported,
- if possible for this drive only.
- Not fully supported by all chipset types,
- and quite likely to cause trouble with
- older/odd IDE drives.
-
- "hdx=nodma" : disallow DMA
-
- "idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz,
- where "xx" is between 20 and 66 inclusive,
- used when tuning chipset PIO modes.
- For PCI bus, 25 is correct for a P75 system,
- 30 is correct for P90,P120,P180 systems,
- and 33 is used for P100,P133,P166 systems.
- If in doubt, use idebus=33 for PCI.
- As for VLB, it is safest to not specify it.
- Bigger values are safer than smaller ones.
-
- "idex=serialize" : do not overlap operations on idex. Please note
- that you will have to specify this option for
- both the respective primary and secondary channel
- to take effect.
-
- "idex=reset" : reset interface after probe
-
- "idex=ata66" : informs the interface that it has an 80c cable
- for chipsets that are ATA-66 capable, but the
- ability to bit test for detection is currently
- unknown.
-
- "ide=doubler" : probe/support IDE doublers on Amiga
-
-There may be more options than shown -- use the source, Luke!
-
-Everything else is rejected with a "BAD OPTION" message.
-
For legacy IDE VLB host drivers (ali14xx/dtc2278/ht6560b/qd65xx/umc8672)
you need to explicitly enable probing by using "probe" kernel parameter,
i.e. to enable probing for ALI M14xx chipsets (ali14xx host driver) use:
@@ -251,6 +197,33 @@ are detected automatically).
You also need to use "probe" kernel parameter for ide-4drives driver
(support for IDE generic chipset with four drives on one port).
+To enable support for IDE doublers on Amiga use "doubler" kernel parameter
+for gayle host driver (i.e. "gayle.doubler" if the driver is built-in).
+
+To force ignoring cable detection (this should be needed only if you're using
+short 40-wires cable which cannot be automatically detected - if this is not
+a case please report it as a bug instead) use "ignore_cable" kernel parameter:
+
+* "ide_core.ignore_cable=[interface_number]" boot option if IDE is built-in
+ (i.e. "ide_core.ignore_cable=1" to force ignoring cable for "ide1")
+
+* "ignore_cable=[interface_number]" module parameter (for ide_core module)
+ if IDE is compiled as module
+
+Other kernel parameters for ide_core are:
+
+* "nodma=[interface_number.device_number]" to disallow DMA for a device
+
+* "noflush=[interface_number.device_number]" to disable flush requests
+
+* "noprobe=[interface_number.device_number]" to skip probing
+
+* "nowerr=[interface_number.device_number]" to ignore the WRERR_STAT bit
+
+* "cdrom=[interface_number.device_number]" to force device as a CD-ROM
+
+* "chs=[interface_number.device_number]" to force device as a disk (using CHS)
+
================================================================================
Some Terminology
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index c18363bd8d11..240ce7a56c40 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -183,6 +183,8 @@ Code Seq# Include File Comments
0xAC 00-1F linux/raw.h
0xAD 00 Netfilter device in development:
<mailto:rusty@rustcorp.com.au>
+0xAE all linux/kvm.h Kernel-based Virtual Machine
+ <mailto:kvm-devel@lists.sourceforge.net>
0xB0 all RATIO devices in development:
<mailto:vgo@ratio.de>
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 649cb8799890..00b950d1c193 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -104,14 +104,15 @@ applicable everywhere (see syntax).
Reverse dependencies can only be used with boolean or tristate
symbols.
Note:
- select is evil.... select will by brute force set a symbol
- equal to 'y' without visiting the dependencies. So abusing
- select you are able to select a symbol FOO even if FOO depends
- on BAR that is not set. In general use select only for
- non-visible symbols (no prompts anywhere) and for symbols with
- no dependencies. That will limit the usefulness but on the
- other hand avoid the illegal configurations all over. kconfig
- should one day warn about such things.
+ select should be used with care. select will force
+ a symbol to a value without visiting the dependencies.
+ By abusing select you are able to select a symbol FOO even
+ if FOO depends on BAR that is not set.
+ In general use select only for non-visible symbols
+ (no prompts anywhere) and for symbols with no dependencies.
+ That will limit the usefulness but on the other hand avoid
+ the illegal configurations all over.
+ kconfig should one day warn about such things.
- numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
This allows to limit the range of possible input values for int
diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt
index 1d247d59ad56..1821c077b435 100644
--- a/Documentation/kbuild/modules.txt
+++ b/Documentation/kbuild/modules.txt
@@ -486,7 +486,7 @@ Module.symvers contains a list of all exported symbols from a kernel build.
Sometimes, an external module uses exported symbols from another
external module. Kbuild needs to have full knowledge on all symbols
to avoid spitting out warnings about undefined symbols.
- Two solutions exist to let kbuild know all symbols of more than
+ Three solutions exist to let kbuild know all symbols of more than
one external module.
The method with a top-level kbuild file is recommended but may be
impractical in certain situations.
@@ -523,6 +523,13 @@ Module.symvers contains a list of all exported symbols from a kernel build.
containing the sum of all symbols defined and not part of the
kernel.
+ Use make variable KBUILD_EXTRA_SYMBOLS in the Makefile
+ If it is impractical to copy Module.symvers from another
+ module, you can assign a space separated list of files to
+ KBUILD_EXTRA_SYMBOLS in your Makfile. These files will be
+ loaded by modpost during the initialisation of its symbol
+ tables.
+
=== 8. Tips & Tricks
--- 8.1 Testing for CONFIG_FOO_BAR
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bf6303ec0bde..e5f3d918316f 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -772,10 +772,6 @@ and is between 256 and 4096 characters. It is defined in the file
Format: ide=nodma or ide=doubler
See Documentation/ide/ide.txt.
- ide?= [HW] (E)IDE subsystem
- Format: ide?=ata66 or chipset specific parameters.
- See Documentation/ide/ide.txt.
-
idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed
See Documentation/ide/ide.txt.
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index be89f393274f..6877e7187113 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -37,6 +37,11 @@ registration function such as register_kprobe() specifies where
the probe is to be inserted and what handler is to be called when
the probe is hit.
+There are also register_/unregister_*probes() functions for batch
+registration/unregistration of a group of *probes. These functions
+can speed up unregistration process when you have to unregister
+a lot of probes at once.
+
The next three subsections explain how the different types of
probes work. They explain certain things that you'll need to
know in order to make the best use of Kprobes -- e.g., the
@@ -190,10 +195,11 @@ code mapping.
4. API Reference
The Kprobes API includes a "register" function and an "unregister"
-function for each type of probe. Here are terse, mini-man-page
-specifications for these functions and the associated probe handlers
-that you'll write. See the files in the samples/kprobes/ sub-directory
-for examples.
+function for each type of probe. The API also includes "register_*probes"
+and "unregister_*probes" functions for (un)registering arrays of probes.
+Here are terse, mini-man-page specifications for these functions and
+the associated probe handlers that you'll write. See the files in the
+samples/kprobes/ sub-directory for examples.
4.1 register_kprobe
@@ -319,6 +325,43 @@ void unregister_kretprobe(struct kretprobe *rp);
Removes the specified probe. The unregister function can be called
at any time after the probe has been registered.
+NOTE:
+If the functions find an incorrect probe (ex. an unregistered probe),
+they clear the addr field of the probe.
+
+4.5 register_*probes
+
+#include <linux/kprobes.h>
+int register_kprobes(struct kprobe **kps, int num);
+int register_kretprobes(struct kretprobe **rps, int num);
+int register_jprobes(struct jprobe **jps, int num);
+
+Registers each of the num probes in the specified array. If any
+error occurs during registration, all probes in the array, up to
+the bad probe, are safely unregistered before the register_*probes
+function returns.
+- kps/rps/jps: an array of pointers to *probe data structures
+- num: the number of the array entries.
+
+NOTE:
+You have to allocate(or define) an array of pointers and set all
+of the array entries before using these functions.
+
+4.6 unregister_*probes
+
+#include <linux/kprobes.h>
+void unregister_kprobes(struct kprobe **kps, int num);
+void unregister_kretprobes(struct kretprobe **rps, int num);
+void unregister_jprobes(struct jprobe **jps, int num);
+
+Removes each of the num probes in the specified array at once.
+
+NOTE:
+If the functions find some incorrect probes (ex. unregistered
+probes) in the specified array, they clear the addr field of those
+incorrect probes. However, other probes in the array are
+unregistered correctly.
+
5. Kprobes Features and Limitations
Kprobes allows multiple probes at the same address. Currently,
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 76cb428435da..01c6c3d8a7e3 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -1,7 +1,7 @@
ThinkPad ACPI Extras Driver
- Version 0.19
- January 06th, 2008
+ Version 0.20
+ April 09th, 2008
Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -18,6 +18,11 @@ This driver used to be named ibm-acpi until kernel 2.6.21 and release
moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
2.6.22, and release 0.14.
+The driver is named "thinkpad-acpi". In some places, like module
+names, "thinkpad_acpi" is used because of userspace issues.
+
+"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
+long due to length limitations on some Linux kernel versions.
Status
------
@@ -571,6 +576,47 @@ netlink interface and the input layer interface, and don't bother at all
with hotkey_report_mode.
+Brightness hotkey notes:
+
+These are the current sane choices for brightness key mapping in
+thinkpad-acpi:
+
+For IBM and Lenovo models *without* ACPI backlight control (the ones on
+which thinkpad-acpi will autoload its backlight interface by default,
+and on which ACPI video does not export a backlight interface):
+
+1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as
+ these older firmware versions unfortunately won't respect the hotkey
+ mask for brightness keys anyway, and always reacts to them. This
+ usually work fine, unless X.org drivers are doing something to block
+ the BIOS. In that case, use (3) below. This is the default mode of
+ operation.
+
+2. Enable the hotkeys, but map them to something else that is NOT
+ KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause
+ userspace to try to change the backlight level, and use that as an
+ on-screen-display hint.
+
+3. IF AND ONLY IF X.org drivers find a way to block the firmware from
+ automatically changing the brightness, enable the hotkeys and map
+ them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to
+ something that calls xbacklight. thinkpad-acpi will not be able to
+ change brightness in that case either, so you should disable its
+ backlight interface.
+
+For Lenovo models *with* ACPI backlight control:
+
+1. Load up ACPI video and use that. ACPI video will report ACPI
+ events for brightness change keys. Do not mess with thinkpad-acpi
+ defaults in this case. thinkpad-acpi should not have anything to do
+ with backlight events in a scenario where ACPI video is loaded:
+ brightness hotkeys must be disabled, and the backlight interface is
+ to be kept disabled as well. This is the default mode of operation.
+
+2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi,
+ and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
+ these keys on userspace somehow (e.g. by calling xbacklight).
+
Bluetooth
---------
@@ -647,16 +693,31 @@ while others are still having problems. For more information:
https://bugs.freedesktop.org/show_bug.cgi?id=2000
-ThinkLight control -- /proc/acpi/ibm/light
-------------------------------------------
+ThinkLight control
+------------------
+
+procfs: /proc/acpi/ibm/light
+sysfs attributes: as per LED class, for the "tpacpi::thinklight" LED
-The current status of the ThinkLight can be found in this file. A few
-models which do not make the status available will show it as
-"unknown". The available commands are:
+procfs notes:
+
+The ThinkLight status can be read and set through the procfs interface. A
+few models which do not make the status available will show the ThinkLight
+status as "unknown". The available commands are:
echo on > /proc/acpi/ibm/light
echo off > /proc/acpi/ibm/light
+sysfs notes:
+
+The ThinkLight sysfs interface is documented by the LED class
+documentation, in Documentation/leds-class.txt. The ThinkLight LED name
+is "tpacpi::thinklight".
+
+Due to limitations in the sysfs LED class, if the status of the thinklight
+cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
+It is impossible to know if the status returned through sysfs is valid.
+
Docking / undocking -- /proc/acpi/ibm/dock
------------------------------------------
@@ -815,28 +876,63 @@ The cmos command interface is prone to firmware split-brain problems, as
in newer ThinkPads it is just a compatibility layer. Do not use it, it is
exported just as a debug tool.
-LED control -- /proc/acpi/ibm/led
----------------------------------
+LED control
+-----------
+
+procfs: /proc/acpi/ibm/led
+sysfs attributes: as per LED class, see below for names
+
+Some of the LED indicators can be controlled through this feature. On
+some older ThinkPad models, it is possible to query the status of the
+LED indicators as well. Newer ThinkPads cannot query the real status
+of the LED indicators.
-Some of the LED indicators can be controlled through this feature. The
-available commands are:
+procfs notes:
+
+The available commands are:
- echo '<led number> on' >/proc/acpi/ibm/led
- echo '<led number> off' >/proc/acpi/ibm/led
- echo '<led number> blink' >/proc/acpi/ibm/led
+ echo '<LED number> on' >/proc/acpi/ibm/led
+ echo '<LED number> off' >/proc/acpi/ibm/led
+ echo '<LED number> blink' >/proc/acpi/ibm/led
-The <led number> range is 0 to 7. The set of LEDs that can be
-controlled varies from model to model. Here is the mapping on the X40:
+The <LED number> range is 0 to 7. The set of LEDs that can be
+controlled varies from model to model. Here is the common ThinkPad
+mapping:
0 - power
1 - battery (orange)
2 - battery (green)
- 3 - UltraBase
+ 3 - UltraBase/dock
4 - UltraBay
+ 5 - UltraBase battery slot
+ 6 - (unknown)
7 - standby
All of the above can be turned on and off and can be made to blink.
+sysfs notes:
+
+The ThinkPad LED sysfs interface is described in detail by the LED class
+documentation, in Documentation/leds-class.txt.
+
+The leds are named (in LED ID order, from 0 to 7):
+"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
+"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
+"tpacpi::unknown_led", "tpacpi::standby".
+
+Due to limitations in the sysfs LED class, if the status of the LED
+indicators cannot be read due to an error, thinkpad-acpi will report it as
+a brightness of zero (same as LED off).
+
+If the thinkpad firmware doesn't support reading the current status,
+trying to read the current LED brightness will just return whatever
+brightness was last written to that attribute.
+
+These LEDs can blink using hardware acceleration. To request that a
+ThinkPad indicator LED should blink in hardware accelerated mode, use the
+"timer" trigger, and leave the delay_on and delay_off parameters set to
+zero (to request hardware acceleration autodetection).
+
ACPI sounds -- /proc/acpi/ibm/beep
----------------------------------
@@ -1090,6 +1186,15 @@ it there will be the following attributes:
dim the display.
+WARNING:
+
+ Whatever you do, do NOT ever call thinkpad-acpi backlight-level change
+ interface and the ACPI-based backlight level change interface
+ (available on newer BIOSes, and driven by the Linux ACPI video driver)
+ at the same time. The two will interact in bad ways, do funny things,
+ and maybe reduce the life of the backlight lamps by needlessly kicking
+ its level up and down at every change.
+
Volume control -- /proc/acpi/ibm/volume
---------------------------------------
diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt
index 56757c751d6f..18860ad9935a 100644
--- a/Documentation/leds-class.txt
+++ b/Documentation/leds-class.txt
@@ -19,6 +19,12 @@ optimises away.
Complex triggers whilst available to all LEDs have LED specific
parameters and work on a per LED basis. The timer trigger is an example.
+The timer trigger will periodically change the LED brightness between
+LED_OFF and the current brightness setting. The "on" and "off" time can
+be specified via /sys/class/leds/<device>/delay_{on,off} in milliseconds.
+You can change the brightness value of a LED independently of the timer
+trigger. However, if you set the brightness value to LED_OFF it will
+also disable the timer trigger.
You can change triggers in a similar manner to the way an IO scheduler
is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
@@ -63,9 +69,9 @@ value if it is called with *delay_on==0 && *delay_off==0 parameters. In
this case the driver should give back the chosen value through delay_on
and delay_off parameters to the leds subsystem.
-Any call to the brightness_set() callback function should cancel the
-previously programmed hardware blinking function so setting the brightness
-to 0 can also cancel the blinking of the LED.
+Setting the brightness to zero with brightness_set() callback function
+should completely turn off the LED and cancel the previously programmed
+hardware blinking function, if any.
Known Issues
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 396cdd982c26..a8b430627473 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -450,3 +450,9 @@ These currently include
there are upper and lower limits (32768, 16). Default is 128.
strip_cache_active (currently raid5 only)
number of active entries in the stripe cache
+ preread_bypass_threshold (currently raid5 only)
+ number of times a stripe requiring preread will be bypassed by
+ a stripe that does not require preread. For fairness defaults
+ to 1. Setting this to 0 disables bypass accounting and
+ requires preread stripes to wait until all full-width stripe-
+ writes are complete. Valid values are 0 to stripe_cache_size.
diff --git a/Documentation/mips/AU1xxx_IDE.README b/Documentation/mips/AU1xxx_IDE.README
index 5c8334123f4f..25a6ed1aaa5b 100644
--- a/Documentation/mips/AU1xxx_IDE.README
+++ b/Documentation/mips/AU1xxx_IDE.README
@@ -46,8 +46,6 @@ Two files are introduced:
a) 'include/asm-mips/mach-au1x00/au1xxx_ide.h'
containes : struct _auide_hwif
- struct drive_list_entry dma_white_list
- struct drive_list_entry dma_black_list
timing parameters for PIO mode 0/1/2/3/4
timing parameters for MWDMA 0/1/2
@@ -63,12 +61,6 @@ Four configs variables are introduced:
CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ - maximum transfer size
per descriptor
-If MWDMA is enabled and the connected hard disc is not on the white list, the
-kernel switches to a "safe mwdma mode" at boot time. In this mode the IDE
-performance is substantial slower then in full speed mwdma. In this case
-please add your hard disc to the white list (follow instruction from 'ADD NEW
-HARD DISC TO WHITE OR BLACK LIST' section).
-
SUPPORTED IDE MODES
-------------------
@@ -120,44 +112,6 @@ CONFIG_IDEDMA_AUTO=y
Also undefine 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to
disable the burst support on DBDMA controller.
-ADD NEW HARD DISC TO WHITE OR BLACK LIST
-----------------------------------------
-
-Step 1 : detect the model name of your hard disc
-
- a) connect your hard disc to the AU1XXX
-
- b) boot your kernel and get the hard disc model.
-
- Example boot log:
-
- --snipped--
- Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
- ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
- Au1xxx IDE(builtin) configured for MWDMA2
- Probing IDE interface ide0...
- hda: Maxtor 6E040L0, ATA DISK drive
- ide0 at 0xac800000-0xac800007,0xac8001c0 on irq 64
- hda: max request size: 64KiB
- hda: 80293248 sectors (41110 MB) w/2048KiB Cache, CHS=65535/16/63, (U)DMA
- --snipped--
-
- In this example 'Maxtor 6E040L0'.
-
-Step 2 : edit 'include/asm-mips/mach-au1x00/au1xxx_ide.h'
-
- Add your hard disc to the dma_white_list or dma_black_list structur.
-
-Step 3 : Recompile the kernel
-
- Enable MWDMA support in the kernel configuration. Recompile the kernel and
- reboot.
-
-Step 4 : Tests
-
- If you have add a hard disc to the white list, please run some stress tests
- for verification.
-
ACKNOWLEDGMENTS
---------------
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
index 0bc95eab1512..8df6a7b0e66c 100644
--- a/Documentation/networking/phy.txt
+++ b/Documentation/networking/phy.txt
@@ -1,7 +1,7 @@
-------
PHY Abstraction Layer
-(Updated 2006-11-30)
+(Updated 2008-04-08)
Purpose
@@ -291,3 +291,39 @@ Writing a PHY driver
Feel free to look at the Marvell, Cicada, and Davicom drivers in
drivers/net/phy/ for examples (the lxt and qsemi drivers have
not been tested as of this writing)
+
+Board Fixups
+
+ Sometimes the specific interaction between the platform and the PHY requires
+ special handling. For instance, to change where the PHY's clock input is,
+ or to add a delay to account for latency issues in the data path. In order
+ to support such contingencies, the PHY Layer allows platform code to register
+ fixups to be run when the PHY is brought up (or subsequently reset).
+
+ When the PHY Layer brings up a PHY it checks to see if there are any fixups
+ registered for it, matching based on UID (contained in the PHY device's phy_id
+ field) and the bus identifier (contained in phydev->dev.bus_id). Both must
+ match, however two constants, PHY_ANY_ID and PHY_ANY_UID, are provided as
+ wildcards for the bus ID and UID, respectively.
+
+ When a match is found, the PHY layer will invoke the run function associated
+ with the fixup. This function is passed a pointer to the phy_device of
+ interest. It should therefore only operate on that PHY.
+
+ The platform code can either register the fixup using phy_register_fixup():
+
+ int phy_register_fixup(const char *phy_id,
+ u32 phy_uid, u32 phy_uid_mask,
+ int (*run)(struct phy_device *));
+
+ Or using one of the two stubs, phy_register_fixup_for_uid() and
+ phy_register_fixup_for_id():
+
+ int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+ int (*run)(struct phy_device *));
+ int phy_register_fixup_for_id(const char *phy_id,
+ int (*run)(struct phy_device *));
+
+ The stubs set one of the two matching criteria, and set the other one to
+ match anything.
+
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 4cc780024e6c..1d2a772506cf 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -2601,6 +2601,17 @@ platforms are moved over to use the flattened-device-tree model.
differ between different families. May be
'virtex2p', 'virtex4', or 'virtex5'.
+ vi) Xilinx Uart 16550
+
+ Xilinx UART 16550 devices are very similar to the NS16550 but with
+ different register spacing and an offset from the base address.
+
+ Requred properties:
+ - clock-frequency : Frequency of the clock input
+ - reg-offset : A value of 3 is required
+ - reg-shift : A value of 2 is required
+
+
p) Freescale Synchronous Serial Interface
The SSI is a serial device that communicates with audio codecs. It can
@@ -2825,6 +2836,39 @@ platforms are moved over to use the flattened-device-tree model.
big-endian;
};
+ r) Freescale Display Interface Unit
+
+ The Freescale DIU is a LCD controller, with proper hardware, it can also
+ drive DVI monitors.
+
+ Required properties:
+ - compatible : should be "fsl-diu".
+ - reg : should contain at least address and length of the DIU register
+ set.
+ - Interrupts : one DIU interrupt should be describe here.
+
+ Example (MPC8610HPCD)
+ display@2c000 {
+ compatible = "fsl,diu";
+ reg = <0x2c000 100>;
+ interrupts = <72 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ s) Freescale on board FPGA
+
+ This is the memory-mapped registers for on board FPGA.
+
+ Required properities:
+ - compatible : should be "fsl,fpga-pixis".
+ - reg : should contain the address and the lenght of the FPPGA register
+ set.
+
+ Example (MPC8610HPCD)
+ board-control@e8000000 {
+ compatible = "fsl,fpga-pixis";
+ reg = <0xe8000000 32>;
+ };
VII - Marvell Discovery mv64[345]6x System Controller chips
===========================================================
diff --git a/Documentation/powerpc/kvm_440.txt b/Documentation/powerpc/kvm_440.txt
new file mode 100644
index 000000000000..c02a003fa03a
--- /dev/null
+++ b/Documentation/powerpc/kvm_440.txt
@@ -0,0 +1,41 @@
+Hollis Blanchard <hollisb@us.ibm.com>
+15 Apr 2008
+
+Various notes on the implementation of KVM for PowerPC 440:
+
+To enforce isolation, host userspace, guest kernel, and guest userspace all
+run at user privilege level. Only the host kernel runs in supervisor mode.
+Executing privileged instructions in the guest traps into KVM (in the host
+kernel), where we decode and emulate them. Through this technique, unmodified
+440 Linux kernels can be run (slowly) as guests. Future performance work will
+focus on reducing the overhead and frequency of these traps.
+
+The usual code flow is started from userspace invoking an "run" ioctl, which
+causes KVM to switch into guest context. We use IVPR to hijack the host
+interrupt vectors while running the guest, which allows us to direct all
+interrupts to kvmppc_handle_interrupt(). At this point, we could either
+- handle the interrupt completely (e.g. emulate "mtspr SPRG0"), or
+- let the host interrupt handler run (e.g. when the decrementer fires), or
+- return to host userspace (e.g. when the guest performs device MMIO)
+
+Address spaces: We take advantage of the fact that Linux doesn't use the AS=1
+address space (in host or guest), which gives us virtual address space to use
+for guest mappings. While the guest is running, the host kernel remains mapped
+in AS=0, but the guest can only use AS=1 mappings.
+
+TLB entries: The TLB entries covering the host linear mapping remain
+present while running the guest. This reduces the overhead of lightweight
+exits, which are handled by KVM running in the host kernel. We keep three
+copies of the TLB:
+ - guest TLB: contents of the TLB as the guest sees it
+ - shadow TLB: the TLB that is actually in hardware while guest is running
+ - host TLB: to restore TLB state when context switching guest -> host
+When a TLB miss occurs because a mapping was not present in the shadow TLB,
+but was present in the guest TLB, KVM handles the fault without invoking the
+guest. Large guest pages are backed by multiple 4KB shadow pages through this
+mechanism.
+
+IO: MMIO and DCR accesses are emulated by userspace. We use virtio for network
+and block IO, so those drivers must be enabled in the guest. It's possible
+that some qemu device emulation (e.g. e1000 or rtl8139) may also work with
+little effort.
diff --git a/Documentation/s390/kvm.txt b/Documentation/s390/kvm.txt
new file mode 100644
index 000000000000..6f5ceb0f09fc
--- /dev/null
+++ b/Documentation/s390/kvm.txt
@@ -0,0 +1,125 @@
+*** BIG FAT WARNING ***
+The kvm module is currently in EXPERIMENTAL state for s390. This means that
+the interface to the module is not yet considered to remain stable. Thus, be
+prepared that we keep breaking your userspace application and guest
+compatibility over and over again until we feel happy with the result. Make sure
+your guest kernel, your host kernel, and your userspace launcher are in a
+consistent state.
+
+This Documentation describes the unique ioctl calls to /dev/kvm, the resulting
+kvm-vm file descriptors, and the kvm-vcpu file descriptors that differ from x86.
+
+1. ioctl calls to /dev/kvm
+KVM does support the following ioctls on s390 that are common with other
+architectures and do behave the same:
+KVM_GET_API_VERSION
+KVM_CREATE_VM (*) see note
+KVM_CHECK_EXTENSION
+KVM_GET_VCPU_MMAP_SIZE
+
+Notes:
+* KVM_CREATE_VM may fail on s390, if the calling process has multiple
+threads and has not called KVM_S390_ENABLE_SIE before.
+
+In addition, on s390 the following architecture specific ioctls are supported:
+ioctl: KVM_S390_ENABLE_SIE
+args: none
+see also: include/linux/kvm.h
+This call causes the kernel to switch on PGSTE in the user page table. This
+operation is needed in order to run a virtual machine, and it requires the
+calling process to be single-threaded. Note that the first call to KVM_CREATE_VM
+will implicitly try to switch on PGSTE if the user process has not called
+KVM_S390_ENABLE_SIE before. User processes that want to launch multiple threads
+before creating a virtual machine have to call KVM_S390_ENABLE_SIE, or will
+observe an error calling KVM_CREATE_VM. Switching on PGSTE is a one-time
+operation, is not reversible, and will persist over the entire lifetime of
+the calling process. It does not have any user-visible effect other than a small
+performance penalty.
+
+2. ioctl calls to the kvm-vm file descriptor
+KVM does support the following ioctls on s390 that are common with other
+architectures and do behave the same:
+KVM_CREATE_VCPU
+KVM_SET_USER_MEMORY_REGION (*) see note
+KVM_GET_DIRTY_LOG (**) see note
+
+Notes:
+* kvm does only allow exactly one memory slot on s390, which has to start
+ at guest absolute address zero and at a user address that is aligned on any
+ page boundary. This hardware "limitation" allows us to have a few unique
+ optimizations. The memory slot doesn't have to be filled
+ with memory actually, it may contain sparse holes. That said, with different
+ user memory layout this does still allow a large flexibility when
+ doing the guest memory setup.
+** KVM_GET_DIRTY_LOG doesn't work properly yet. The user will receive an empty
+log. This ioctl call is only needed for guest migration, and we intend to
+implement this one in the future.
+
+In addition, on s390 the following architecture specific ioctls for the kvm-vm
+file descriptor are supported:
+ioctl: KVM_S390_INTERRUPT
+args: struct kvm_s390_interrupt *
+see also: include/linux/kvm.h
+This ioctl is used to submit a floating interrupt for a virtual machine.
+Floating interrupts may be delivered to any virtual cpu in the configuration.
+Only some interrupt types defined in include/linux/kvm.h make sense when
+submitted as floating interrupts. The following interrupts are not considered
+to be useful as floating interrupts, and a call to inject them will result in
+-EINVAL error code: program interrupts and interprocessor signals. Valid
+floating interrupts are:
+KVM_S390_INT_VIRTIO
+KVM_S390_INT_SERVICE
+
+3. ioctl calls to the kvm-vcpu file descriptor
+KVM does support the following ioctls on s390 that are common with other
+architectures and do behave the same:
+KVM_RUN
+KVM_GET_REGS
+KVM_SET_REGS
+KVM_GET_SREGS
+KVM_SET_SREGS
+KVM_GET_FPU
+KVM_SET_FPU
+
+In addition, on s390 the following architecture specific ioctls for the
+kvm-vcpu file descriptor are supported:
+ioctl: KVM_S390_INTERRUPT
+args: struct kvm_s390_interrupt *
+see also: include/linux/kvm.h
+This ioctl is used to submit an interrupt for a specific virtual cpu.
+Only some interrupt types defined in include/linux/kvm.h make sense when
+submitted for a specific cpu. The following interrupts are not considered
+to be useful, and a call to inject them will result in -EINVAL error code:
+service processor calls and virtio interrupts. Valid interrupt types are:
+KVM_S390_PROGRAM_INT
+KVM_S390_SIGP_STOP
+KVM_S390_RESTART
+KVM_S390_SIGP_SET_PREFIX
+KVM_S390_INT_EMERGENCY
+
+ioctl: KVM_S390_STORE_STATUS
+args: unsigned long
+see also: include/linux/kvm.h
+This ioctl stores the state of the cpu at the guest real address given as
+argument, unless one of the following values defined in include/linux/kvm.h
+is given as arguement:
+KVM_S390_STORE_STATUS_NOADDR - the CPU stores its status to the save area in
+absolute lowcore as defined by the principles of operation
+KVM_S390_STORE_STATUS_PREFIXED - the CPU stores its status to the save area in
+its prefix page just like the dump tool that comes with zipl. This is useful
+to create a system dump for use with lkcdutils or crash.
+
+ioctl: KVM_S390_SET_INITIAL_PSW
+args: struct kvm_s390_psw *
+see also: include/linux/kvm.h
+This ioctl can be used to set the processor status word (psw) of a stopped cpu
+prior to running it with KVM_RUN. Note that this call is not required to modify
+the psw during sie intercepts that fall back to userspace because struct kvm_run
+does contain the psw, and this value is evaluated during reentry of KVM_RUN
+after the intercept exit was recognized.
+
+ioctl: KVM_S390_INITIAL_RESET
+args: none
+see also: include/linux/kvm.h
+This ioctl can be used to perform an initial cpu reset as defined by the
+principles of operation. The target cpu has to be in stopped state.
diff --git a/Documentation/smart-config.txt b/Documentation/smart-config.txt
deleted file mode 100644
index 8467447b5a87..000000000000
--- a/Documentation/smart-config.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-Smart CONFIG_* Dependencies
-1 August 1999
-
-Michael Chastain <mec@shout.net>
-Werner Almesberger <almesber@lrc.di.epfl.ch>
-Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>
-
-Here is the problem:
-
- Suppose that drivers/net/foo.c has the following lines:
-
- #include <linux/config.h>
-
- ...
-
- #ifdef CONFIG_FOO_AUTOFROB
- /* Code for auto-frobbing */
- #else
- /* Manual frobbing only */
- #endif
-
- ...
-
- #ifdef CONFIG_FOO_MODEL_TWO
- /* Code for model two */
- #endif
-
- Now suppose the user (the person building kernels) reconfigures the
- kernel to change some unrelated setting. This will regenerate the
- file include/linux/autoconf.h, which will cause include/linux/config.h
- to be out of date, which will cause drivers/net/foo.c to be recompiled.
-
- Most kernel sources, perhaps 80% of them, have at least one CONFIG_*
- dependency somewhere. So changing _any_ CONFIG_* setting requires
- almost _all_ of the kernel to be recompiled.
-
-Here is the solution:
-
- We've made the dependency generator, mkdep.c, smarter. Instead of
- generating this dependency:
-
- drivers/net/foo.c: include/linux/config.h
-
- It now generates these dependencies:
-
- drivers/net/foo.c: \
- include/config/foo/autofrob.h \
- include/config/foo/model/two.h
-
- So drivers/net/foo.c depends only on the CONFIG_* lines that
- it actually uses.
-
- A new program, split-include.c, runs at the beginning of
- compilation (make bzImage or make zImage). split-include reads
- include/linux/autoconf.h and updates the include/config/ tree,
- writing one file per option. It updates only the files for options
- that have changed.
-
-Flag Dependencies
-
- Martin Von Loewis contributed another feature to this patch:
- 'flag dependencies'. The idea is that a .o file depends on
- the compilation flags used to build it. The file foo.o has
- its flags stored in .flags.foo.o.
-
- Suppose the user changes the foo driver from resident to modular.
- 'make' will notice that the current foo.o was not compiled with
- -DMODULE and will recompile foo.c.
-
- All .o files made from C source have flag dependencies. So do .o
- files made with ld, and .a files made with ar. However, .o files
- made from assembly source do not have flag dependencies (nobody
- needs this yet, but it would be good to fix).
-
-Per-source-file Flags
-
- Flag dependencies also work with per-source-file flags.
- You can specify compilation flags for individual source files
- like this:
-
- CFLAGS_foo.o = -DSPECIAL_FOO_DEFINE
-
- This helps clean up drivers/net/Makefile, drivers/scsi/Makefile,
- and several other Makefiles.
-
-Credit
-
- Werner Almesberger had the original idea and wrote the first
- version of this patch.
-
- Michael Chastain picked it up and continued development. He is
- now the principal author and maintainer. Please report any bugs
- to him.
-
- Martin von Loewis wrote flag dependencies, with some modifications
- by Michael Chastain.
-
- Thanks to all of the beta testers.
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
index 5c8e1b988a08..ed2da5e5b28a 100644
--- a/Documentation/spi/spidev
+++ b/Documentation/spi/spidev
@@ -126,8 +126,8 @@ NOTES:
FULL DUPLEX CHARACTER DEVICE API
================================
-See the sample program below for one example showing the use of the full
-duplex programming interface. (Although it doesn't perform a full duplex
+See the spidev_fdx.c sample program for one example showing the use of the
+full duplex programming interface. (Although it doesn't perform a full duplex
transfer.) The model is the same as that used in the kernel spi_sync()
request; the individual transfers offer the same capabilities as are
available to kernel drivers (except that it's not asynchronous).
@@ -141,167 +141,3 @@ and bitrate for each transfer segment.)
To make a full duplex request, provide both rx_buf and tx_buf for the
same transfer. It's even OK if those are the same buffer.
-
-
-SAMPLE PROGRAM
-==============
-
--------------------------------- CUT HERE
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <linux/types.h>
-#include <linux/spi/spidev.h>
-
-
-static int verbose;
-
-static void do_read(int fd, int len)
-{
- unsigned char buf[32], *bp;
- int status;
-
- /* read at least 2 bytes, no more than 32 */
- if (len < 2)
- len = 2;
- else if (len > sizeof(buf))
- len = sizeof(buf);
- memset(buf, 0, sizeof buf);
-
- status = read(fd, buf, len);
- if (status < 0) {
- perror("read");
- return;
- }
- if (status != len) {
- fprintf(stderr, "short read\n");
- return;
- }
-
- printf("read(%2d, %2d): %02x %02x,", len, status,
- buf[0], buf[1]);
- status -= 2;
- bp = buf + 2;
- while (status-- > 0)
- printf(" %02x", *bp++);
- printf("\n");
-}
-
-static void do_msg(int fd, int len)
-{
- struct spi_ioc_transfer xfer[2];
- unsigned char buf[32], *bp;
- int status;
-
- memset(xfer, 0, sizeof xfer);
- memset(buf, 0, sizeof buf);
-
- if (len > sizeof buf)
- len = sizeof buf;
-
- buf[0] = 0xaa;
- xfer[0].tx_buf = (__u64) buf;
- xfer[0].len = 1;
-
- xfer[1].rx_buf = (__u64) buf;
- xfer[1].len = len;
-
- status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
- if (status < 0) {
- perror("SPI_IOC_MESSAGE");
- return;
- }
-
- printf("response(%2d, %2d): ", len, status);
- for (bp = buf; len; len--)
- printf(" %02x", *bp++);
- printf("\n");
-}
-
-static void dumpstat(const char *name, int fd)
-{
- __u8 mode, lsb, bits;
- __u32 speed;
-
- if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
- perror("SPI rd_mode");
- return;
- }
- if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
- perror("SPI rd_lsb_fist");
- return;
- }
- if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
- perror("SPI bits_per_word");
- return;
- }
- if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
- perror("SPI max_speed_hz");
- return;
- }
-
- printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
- name, mode, bits, lsb ? "(lsb first) " : "", speed);
-}
-
-int main(int argc, char **argv)
-{
- int c;
- int readcount = 0;
- int msglen = 0;
- int fd;
- const char *name;
-
- while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
- switch (c) {
- case 'm':
- msglen = atoi(optarg);
- if (msglen < 0)
- goto usage;
- continue;
- case 'r':
- readcount = atoi(optarg);
- if (readcount < 0)
- goto usage;
- continue;
- case 'v':
- verbose++;
- continue;
- case 'h':
- case '?':
-usage:
- fprintf(stderr,
- "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
- argv[0]);
- return 1;
- }
- }
-
- if ((optind + 1) != argc)
- goto usage;
- name = argv[optind];
-
- fd = open(name, O_RDWR);
- if (fd < 0) {
- perror("open");
- return 1;
- }
-
- dumpstat(name, fd);
-
- if (msglen)
- do_msg(fd, msglen);
-
- if (readcount)
- do_read(fd, readcount);
-
- close(fd);
- return 0;
-}
diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c
new file mode 100644
index 000000000000..fc354f760384
--- /dev/null
+++ b/Documentation/spi/spidev_fdx.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+
+static int verbose;
+
+static void do_read(int fd, int len)
+{
+ unsigned char buf[32], *bp;
+ int status;
+
+ /* read at least 2 bytes, no more than 32 */
+ if (len < 2)
+ len = 2;
+ else if (len > sizeof(buf))
+ len = sizeof(buf);
+ memset(buf, 0, sizeof buf);
+
+ status = read(fd, buf, len);
+ if (status < 0) {
+ perror("read");
+ return;
+ }
+ if (status != len) {
+ fprintf(stderr, "short read\n");
+ return;
+ }
+
+ printf("read(%2d, %2d): %02x %02x,", len, status,
+ buf[0], buf[1]);
+ status -= 2;
+ bp = buf + 2;
+ while (status-- > 0)
+ printf(" %02x", *bp++);
+ printf("\n");
+}
+
+static void do_msg(int fd, int len)
+{
+ struct spi_ioc_transfer xfer[2];
+ unsigned char buf[32], *bp;
+ int status;
+
+ memset(xfer, 0, sizeof xfer);
+ memset(buf, 0, sizeof buf);
+
+ if (len > sizeof buf)
+ len = sizeof buf;
+
+ buf[0] = 0xaa;
+ xfer[0].tx_buf = (__u64) buf;
+ xfer[0].len = 1;
+
+ xfer[1].rx_buf = (__u64) buf;
+ xfer[1].len = len;
+
+ status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
+ if (status < 0) {
+ perror("SPI_IOC_MESSAGE");
+ return;
+ }
+
+ printf("response(%2d, %2d): ", len, status);
+ for (bp = buf; len; len--)
+ printf(" %02x", *bp++);
+ printf("\n");
+}
+
+static void dumpstat(const char *name, int fd)
+{
+ __u8 mode, lsb, bits;
+ __u32 speed;
+
+ if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+ perror("SPI rd_mode");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
+ perror("SPI rd_lsb_fist");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
+ perror("SPI bits_per_word");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
+ perror("SPI max_speed_hz");
+ return;
+ }
+
+ printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+ name, mode, bits, lsb ? "(lsb first) " : "", speed);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int readcount = 0;
+ int msglen = 0;
+ int fd;
+ const char *name;
+
+ while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
+ switch (c) {
+ case 'm':
+ msglen = atoi(optarg);
+ if (msglen < 0)
+ goto usage;
+ continue;
+ case 'r':
+ readcount = atoi(optarg);
+ if (readcount < 0)
+ goto usage;
+ continue;
+ case 'v':
+ verbose++;
+ continue;
+ case 'h':
+ case '?':
+usage:
+ fprintf(stderr,
+ "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
+ argv[0]);
+ return 1;
+ }
+ }
+
+ if ((optind + 1) != argc)
+ goto usage;
+ name = argv[optind];
+
+ fd = open(name, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ dumpstat(name, fd);
+
+ if (msglen)
+ do_msg(fd, msglen);
+
+ if (readcount)
+ do_read(fd, readcount);
+
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index d9f28be75403..70d68ce8640a 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -108,10 +108,12 @@ and throttle appropriate devices.
RO read only value
RW read/write value
-All thermal sysfs attributes will be represented under /sys/class/thermal
+Thermal sysfs attributes will be represented under /sys/class/thermal.
+Hwmon sysfs I/F extension is also available under /sys/class/hwmon
+if hwmon is compiled in or built as a module.
Thermal zone device sys I/F, created once it's registered:
-|thermal_zone[0-*]:
+/sys/class/thermal/thermal_zone[0-*]:
|-----type: Type of the thermal zone
|-----temp: Current temperature
|-----mode: Working mode of the thermal zone
@@ -119,7 +121,7 @@ Thermal zone device sys I/F, created once it's registered:
|-----trip_point_[0-*]_type: Trip point type
Thermal cooling device sys I/F, created once it's registered:
-|cooling_device[0-*]:
+/sys/class/thermal/cooling_device[0-*]:
|-----type : Type of the cooling device(processor/fan/...)
|-----max_state: Maximum cooling state of the cooling device
|-----cur_state: Current cooling state of the cooling device
@@ -130,10 +132,19 @@ They represent the relationship between a thermal zone and its associated coolin
They are created/removed for each
thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful execution.
-|thermal_zone[0-*]
+/sys/class/thermal/thermal_zone[0-*]
|-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone
|-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with
+Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
+the generic thermal driver also creates a hwmon sysfs I/F for each _type_ of
+thermal zone device. E.g. the generic thermal driver registers one hwmon class device
+and build the associated hwmon sysfs I/F for all the registered ACPI thermal zones.
+/sys/class/hwmon/hwmon[0-*]:
+ |-----name: The type of the thermal zone devices.
+ |-----temp[1-*]_input: The current temperature of thermal zone [1-*].
+ |-----temp[1-*]_critical: The critical trip point of thermal zone [1-*].
+Please read Documentation/hwmon/sysfs-interface for additional information.
***************************
* Thermal zone attributes *
@@ -141,7 +152,10 @@ thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful e
type Strings which represent the thermal zone type.
This is given by thermal zone driver as part of registration.
- Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
+ Eg: "acpitz" indicates it's an ACPI thermal device.
+ In order to keep it consistent with hwmon sys attribute,
+ this should be a short, lowercase string,
+ not containing spaces nor dashes.
RO
Required
@@ -218,7 +232,7 @@ the sys I/F structure will be built like this:
/sys/class/thermal:
|thermal_zone1:
- |-----type: ACPI thermal zone
+ |-----type: acpitz
|-----temp: 37000
|-----mode: kernel
|-----trip_point_0_temp: 100000
@@ -243,3 +257,10 @@ the sys I/F structure will be built like this:
|-----type: Fan
|-----max_state: 2
|-----cur_state: 0
+
+/sys/class/hwmon:
+
+|hwmon0:
+ |-----name: acpitz
+ |-----temp1_input: 37000
+ |-----temp1_crit: 100000
diff --git a/Documentation/usb/anchors.txt b/Documentation/usb/anchors.txt
new file mode 100644
index 000000000000..7304bcf5a306
--- /dev/null
+++ b/Documentation/usb/anchors.txt
@@ -0,0 +1,50 @@
+What is anchor?
+===============
+
+A USB driver needs to support some callbacks requiring
+a driver to cease all IO to an interface. To do so, a
+driver has to keep track of the URBs it has submitted
+to know they've all completed or to call usb_kill_urb
+for them. The anchor is a data structure takes care of
+keeping track of URBs and provides methods to deal with
+multiple URBs.
+
+Allocation and Initialisation
+=============================
+
+There's no API to allocate an anchor. It is simply declared
+as struct usb_anchor. init_usb_anchor() must be called to
+initialise the data structure.
+
+Deallocation
+============
+
+Once it has no more URBs associated with it, the anchor can be
+freed with normal memory management operations.
+
+Association and disassociation of URBs with anchors
+===================================================
+
+An association of URBs to an anchor is made by an explicit
+call to usb_anchor_urb(). The association is maintained until
+an URB is finished by (successfull) completion. Thus disassociation
+is automatic. A function is provided to forcibly finish (kill)
+all URBs associated with an anchor.
+Furthermore, disassociation can be made with usb_unanchor_urb()
+
+Operations on multitudes of URBs
+================================
+
+usb_kill_anchored_urbs()
+------------------------
+
+This function kills all URBs associated with an anchor. The URBs
+are called in the reverse temporal order they were submitted.
+This way no data can be reordered.
+
+usb_wait_anchor_empty_timeout()
+-------------------------------
+
+This function waits for all URBs associated with an anchor to finish
+or a timeout, whichever comes first. Its return value will tell you
+whether the timeout was reached.
diff --git a/Documentation/usb/callbacks.txt b/Documentation/usb/callbacks.txt
new file mode 100644
index 000000000000..7c812411945b
--- /dev/null
+++ b/Documentation/usb/callbacks.txt
@@ -0,0 +1,132 @@
+What callbacks will usbcore do?
+===============================
+
+Usbcore will call into a driver through callbacks defined in the driver
+structure and through the completion handler of URBs a driver submits.
+Only the former are in the scope of this document. These two kinds of
+callbacks are completely independent of each other. Information on the
+completion callback can be found in Documentation/usb/URB.txt.
+
+The callbacks defined in the driver structure are:
+
+1. Hotplugging callbacks:
+
+ * @probe: Called to see if the driver is willing to manage a particular
+ * interface on a device.
+ * @disconnect: Called when the interface is no longer accessible, usually
+ * because its device has been (or is being) disconnected or the
+ * driver module is being unloaded.
+
+2. Odd backdoor through usbfs:
+
+ * @ioctl: Used for drivers that want to talk to userspace through
+ * the "usbfs" filesystem. This lets devices provide ways to
+ * expose information to user space regardless of where they
+ * do (or don't) show up otherwise in the filesystem.
+
+3. Power management (PM) callbacks:
+
+ * @suspend: Called when the device is going to be suspended.
+ * @resume: Called when the device is being resumed.
+ * @reset_resume: Called when the suspended device has been reset instead
+ * of being resumed.
+
+4. Device level operations:
+
+ * @pre_reset: Called when the device is about to be reset.
+ * @post_reset: Called after the device has been reset
+
+The ioctl interface (2) should be used only if you have a very good
+reason. Sysfs is preferred these days. The PM callbacks are covered
+separately in Documentation/usb/power-management.txt.
+
+Calling conventions
+===================
+
+All callbacks are mutually exclusive. There's no need for locking
+against other USB callbacks. All callbacks are called from a task
+context. You may sleep. However, it is important that all sleeps have a
+small fixed upper limit in time. In particular you must not call out to
+user space and await results.
+
+Hotplugging callbacks
+=====================
+
+These callbacks are intended to associate and disassociate a driver with
+an interface. A driver's bond to an interface is exclusive.
+
+The probe() callback
+--------------------
+
+int (*probe) (struct usb_interface *intf,
+ const struct usb_device_id *id);
+
+Accept or decline an interface. If you accept the device return 0,
+otherwise -ENODEV or -ENXIO. Other error codes should be used only if a
+genuine error occurred during initialisation which prevented a driver
+from accepting a device that would else have been accepted.
+You are strongly encouraged to use usbcore'sfacility,
+usb_set_intfdata(), to associate a data structure with an interface, so
+that you know which internal state and identity you associate with a
+particular interface. The device will not be suspended and you may do IO
+to the interface you are called for and endpoint 0 of the device. Device
+initialisation that doesn't take too long is a good idea here.
+
+The disconnect() callback
+-------------------------
+
+void (*disconnect) (struct usb_interface *intf);
+
+This callback is a signal to break any connection with an interface.
+You are not allowed any IO to a device after returning from this
+callback. You also may not do any other operation that may interfere
+with another driver bound the interface, eg. a power management
+operation.
+If you are called due to a physical disconnection, all your URBs will be
+killed by usbcore. Note that in this case disconnect will be called some
+time after the physical disconnection. Thus your driver must be prepared
+to deal with failing IO even prior to the callback.
+
+Device level callbacks
+======================
+
+pre_reset
+---------
+
+int (*pre_reset)(struct usb_interface *intf);
+
+Another driver or user space is triggering a reset on the device which
+contains the interface passed as an argument. Cease IO and save any
+device state you need to restore.
+
+If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if you
+are in atomic context.
+
+post_reset
+----------
+
+int (*post_reset)(struct usb_interface *intf);
+
+The reset has completed. Restore any saved device state and begin
+using the device again.
+
+If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if you
+are in atomic context.
+
+Call sequences
+==============
+
+No callbacks other than probe will be invoked for an interface
+that isn't bound to your driver.
+
+Probe will never be called for an interface bound to a driver.
+Hence following a successful probe, disconnect will be called
+before there is another probe for the same interface.
+
+Once your driver is bound to an interface, disconnect can be
+called at any time except in between pre_reset and post_reset.
+pre_reset is always followed by post_reset, even if the reset
+failed or the device has been unplugged.
+
+suspend is always followed by one of: resume, reset_resume, or
+disconnect.
diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt
index df54d645cbb5..d56cb1a11550 100644
--- a/Documentation/usb/persist.txt
+++ b/Documentation/usb/persist.txt
@@ -2,7 +2,7 @@
Alan Stern <stern@rowland.harvard.edu>
- September 2, 2006 (Updated May 29, 2007)
+ September 2, 2006 (Updated February 25, 2008)
What is the problem?
@@ -65,9 +65,10 @@ much better.)
What is the solution?
-Setting CONFIG_USB_PERSIST will cause the kernel to work around these
-issues. It enables a mode in which the core USB device data
-structures are allowed to persist across a power-session disruption.
+The kernel includes a feature called USB-persist. It tries to work
+around these issues by allowing the core USB device data structures to
+persist across a power-session disruption.
+
It works like this. If the kernel sees that a USB host controller is
not in the expected state during resume (i.e., if the controller was
reset or otherwise had lost power) then it applies a persistence check
@@ -80,28 +81,30 @@ re-enumeration shows that the device now attached to that port has the
same descriptors as before, including the Vendor and Product IDs, then
the kernel continues to use the same device structure. In effect, the
kernel treats the device as though it had merely been reset instead of
-unplugged.
+unplugged. The same thing happens if the host controller is in the
+expected state but a USB device was unplugged and then replugged.
If no device is now attached to the port, or if the descriptors are
different from what the kernel remembers, then the treatment is what
you would expect. The kernel destroys the old device structure and
behaves as though the old device had been unplugged and a new device
-plugged in, just as it would without the CONFIG_USB_PERSIST option.
+plugged in.
The end result is that the USB device remains available and usable.
Filesystem mounts and memory mappings are unaffected, and the world is
now a good and happy place.
-Note that even when CONFIG_USB_PERSIST is set, the "persist" feature
-will be applied only to those devices for which it is enabled. You
-can enable the feature by doing (as root):
+Note that the "USB-persist" feature will be applied only to those
+devices for which it is enabled. You can enable the feature by doing
+(as root):
echo 1 >/sys/bus/usb/devices/.../power/persist
where the "..." should be filled in the with the device's ID. Disable
the feature by writing 0 instead of 1. For hubs the feature is
-automatically and permanently enabled, so you only have to worry about
-setting it for devices where it really matters.
+automatically and permanently enabled and the power/persist file
+doesn't even exist, so you only have to worry about setting it for
+devices where it really matters.
Is this the best solution?
@@ -112,19 +115,19 @@ centralized Logical Volume Manager. Such a solution would allow you
to plug in a USB flash device, create a persistent volume associated
with it, unplug the flash device, plug it back in later, and still
have the same persistent volume associated with the device. As such
-it would be more far-reaching than CONFIG_USB_PERSIST.
+it would be more far-reaching than USB-persist.
On the other hand, writing a persistent volume manager would be a big
job and using it would require significant input from the user. This
solution is much quicker and easier -- and it exists now, a giant
point in its favor!
-Furthermore, the USB_PERSIST option applies to _all_ USB devices, not
+Furthermore, the USB-persist feature applies to _all_ USB devices, not
just mass-storage devices. It might turn out to be equally useful for
other device types, such as network interfaces.
- WARNING: Using CONFIG_USB_PERSIST can be dangerous!!
+ WARNING: USB-persist can be dangerous!!
When recovering an interrupted power session the kernel does its best
to make sure the USB device hasn't been changed; that is, the same
@@ -133,10 +136,10 @@ aren't guaranteed to be 100% accurate.
If you replace one USB device with another of the same type (same
manufacturer, same IDs, and so on) there's an excellent chance the
-kernel won't detect the change. Serial numbers and other strings are
-not compared. In many cases it wouldn't help if they were, because
-manufacturers frequently omit serial numbers entirely in their
-devices.
+kernel won't detect the change. The serial number string and other
+descriptors are compared with the kernel's stored values, but this
+might not help since manufacturers frequently omit serial numbers
+entirely in their devices.
Furthermore it's quite possible to leave a USB device exactly the same
while changing its media. If you replace the flash memory card in a
@@ -152,5 +155,5 @@ but yourself.
YOU HAVE BEEN WARNED! USE AT YOUR OWN RISK!
That having been said, most of the time there shouldn't be any trouble
-at all. The "persist" feature can be extremely useful. Make the most
-of it.
+at all. The USB-persist feature can be extremely useful. Make the
+most of it.
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 8b077e43eee7..ff2c1ff57ba2 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -192,12 +192,9 @@ Keyspan USA-series Serial Adapters
FTDI Single Port Serial Driver
- This is a single port DB-25 serial adapter. More information about this
- device and the Linux driver can be found at:
- http://reality.sgi.com/bryder_wellington/ftdi_sio/
+ This is a single port DB-25 serial adapter.
- For any questions or problems with this driver, please contact Bill Ryder
- at bryder@sgi.com
+ For any questions or problems with this driver, please contact Bill Ryder.
ZyXEL omni.net lcd plus ISDN TA
diff --git a/Documentation/vm/numa_memory_policy.txt b/Documentation/vm/numa_memory_policy.txt
index dd4986497996..bad16d3f6a47 100644
--- a/Documentation/vm/numa_memory_policy.txt
+++ b/Documentation/vm/numa_memory_policy.txt
@@ -135,77 +135,58 @@ most general to most specific:
Components of Memory Policies
- A Linux memory policy is a tuple consisting of a "mode" and an optional set
- of nodes. The mode determine the behavior of the policy, while the
- optional set of nodes can be viewed as the arguments to the behavior.
+ A Linux memory policy consists of a "mode", optional mode flags, and an
+ optional set of nodes. The mode determines the behavior of the policy,
+ the optional mode flags determine the behavior of the mode, and the
+ optional set of nodes can be viewed as the arguments to the policy
+ behavior.
Internally, memory policies are implemented by a reference counted
structure, struct mempolicy. Details of this structure will be discussed
in context, below, as required to explain the behavior.
- Note: in some functions AND in the struct mempolicy itself, the mode
- is called "policy". However, to avoid confusion with the policy tuple,
- this document will continue to use the term "mode".
-
Linux memory policy supports the following 4 behavioral modes:
- Default Mode--MPOL_DEFAULT: The behavior specified by this mode is
- context or scope dependent.
-
- As mentioned in the Policy Scope section above, during normal
- system operation, the System Default Policy is hard coded to
- contain the Default mode.
-
- In this context, default mode means "local" allocation--that is
- attempt to allocate the page from the node associated with the cpu
- where the fault occurs. If the "local" node has no memory, or the
- node's memory can be exhausted [no free pages available], local
- allocation will "fallback to"--attempt to allocate pages from--
- "nearby" nodes, in order of increasing "distance".
+ Default Mode--MPOL_DEFAULT: This mode is only used in the memory
+ policy APIs. Internally, MPOL_DEFAULT is converted to the NULL
+ memory policy in all policy scopes. Any existing non-default policy
+ will simply be removed when MPOL_DEFAULT is specified. As a result,
+ MPOL_DEFAULT means "fall back to the next most specific policy scope."
- Implementation detail -- subject to change: "Fallback" uses
- a per node list of sibling nodes--called zonelists--built at
- boot time, or when nodes or memory are added or removed from
- the system [memory hotplug]. These per node zonelist are
- constructed with nodes in order of increasing distance based
- on information provided by the platform firmware.
+ For example, a NULL or default task policy will fall back to the
+ system default policy. A NULL or default vma policy will fall
+ back to the task policy.
- When a task/process policy or a shared policy contains the Default
- mode, this also means "local allocation", as described above.
+ When specified in one of the memory policy APIs, the Default mode
+ does not use the optional set of nodes.
- In the context of a VMA, Default mode means "fall back to task
- policy"--which may or may not specify Default mode. Thus, Default
- mode can not be counted on to mean local allocation when used
- on a non-shared region of the address space. However, see
- MPOL_PREFERRED below.
-
- The Default mode does not use the optional set of nodes.
+ It is an error for the set of nodes specified for this policy to
+ be non-empty.
MPOL_BIND: This mode specifies that memory must come from the
- set of nodes specified by the policy.
-
- The memory policy APIs do not specify an order in which the nodes
- will be searched. However, unlike "local allocation", the Bind
- policy does not consider the distance between the nodes. Rather,
- allocations will fallback to the nodes specified by the policy in
- order of numeric node id. Like everything in Linux, this is subject
- to change.
+ set of nodes specified by the policy. Memory will be allocated from
+ the node in the set with sufficient free memory that is closest to
+ the node where the allocation takes place.
MPOL_PREFERRED: This mode specifies that the allocation should be
attempted from the single node specified in the policy. If that
- allocation fails, the kernel will search other nodes, exactly as
- it would for a local allocation that started at the preferred node
- in increasing distance from the preferred node. "Local" allocation
- policy can be viewed as a Preferred policy that starts at the node
+ allocation fails, the kernel will search other nodes, in order of
+ increasing distance from the preferred node based on information
+ provided by the platform firmware.
containing the cpu where the allocation takes place.
Internally, the Preferred policy uses a single node--the
- preferred_node member of struct mempolicy. A "distinguished
- value of this preferred_node, currently '-1', is interpreted
- as "the node containing the cpu where the allocation takes
- place"--local allocation. This is the way to specify
- local allocation for a specific range of addresses--i.e. for
- VMA policies.
+ preferred_node member of struct mempolicy. When the internal
+ mode flag MPOL_F_LOCAL is set, the preferred_node is ignored and
+ the policy is interpreted as local allocation. "Local" allocation
+ policy can be viewed as a Preferred policy that starts at the node
+ containing the cpu where the allocation takes place.
+
+ It is possible for the user to specify that local allocation is
+ always preferred by passing an empty nodemask with this mode.
+ If an empty nodemask is passed, the policy cannot use the
+ MPOL_F_STATIC_NODES or MPOL_F_RELATIVE_NODES flags described
+ below.
MPOL_INTERLEAVED: This mode specifies that page allocations be
interleaved, on a page granularity, across the nodes specified in
@@ -231,6 +212,154 @@ Components of Memory Policies
the temporary interleaved system default policy works in this
mode.
+ Linux memory policy supports the following optional mode flags:
+
+ MPOL_F_STATIC_NODES: This flag specifies that the nodemask passed by
+ the user should not be remapped if the task or VMA's set of allowed
+ nodes changes after the memory policy has been defined.
+
+ Without this flag, anytime a mempolicy is rebound because of a
+ change in the set of allowed nodes, the node (Preferred) or
+ nodemask (Bind, Interleave) is remapped to the new set of
+ allowed nodes. This may result in nodes being used that were
+ previously undesired.
+
+ With this flag, if the user-specified nodes overlap with the
+ nodes allowed by the task's cpuset, then the memory policy is
+ applied to their intersection. If the two sets of nodes do not
+ overlap, the Default policy is used.
+
+ For example, consider a task that is attached to a cpuset with
+ mems 1-3 that sets an Interleave policy over the same set. If
+ the cpuset's mems change to 3-5, the Interleave will now occur
+ over nodes 3, 4, and 5. With this flag, however, since only node
+ 3 is allowed from the user's nodemask, the "interleave" only
+ occurs over that node. If no nodes from the user's nodemask are
+ now allowed, the Default behavior is used.
+
+ MPOL_F_STATIC_NODES cannot be combined with the
+ MPOL_F_RELATIVE_NODES flag. It also cannot be used for
+ MPOL_PREFERRED policies that were created with an empty nodemask
+ (local allocation).
+
+ MPOL_F_RELATIVE_NODES: This flag specifies that the nodemask passed
+ by the user will be mapped relative to the set of the task or VMA's
+ set of allowed nodes. The kernel stores the user-passed nodemask,
+ and if the allowed nodes changes, then that original nodemask will
+ be remapped relative to the new set of allowed nodes.
+
+ Without this flag (and without MPOL_F_STATIC_NODES), anytime a
+ mempolicy is rebound because of a change in the set of allowed
+ nodes, the node (Preferred) or nodemask (Bind, Interleave) is
+ remapped to the new set of allowed nodes. That remap may not
+ preserve the relative nature of the user's passed nodemask to its
+ set of allowed nodes upon successive rebinds: a nodemask of
+ 1,3,5 may be remapped to 7-9 and then to 1-3 if the set of
+ allowed nodes is restored to its original state.
+
+ With this flag, the remap is done so that the node numbers from
+ the user's passed nodemask are relative to the set of allowed
+ nodes. In other words, if nodes 0, 2, and 4 are set in the user's
+ nodemask, the policy will be effected over the first (and in the
+ Bind or Interleave case, the third and fifth) nodes in the set of
+ allowed nodes. The nodemask passed by the user represents nodes
+ relative to task or VMA's set of allowed nodes.
+
+ If the user's nodemask includes nodes that are outside the range
+ of the new set of allowed nodes (for example, node 5 is set in
+ the user's nodemask when the set of allowed nodes is only 0-3),
+ then the remap wraps around to the beginning of the nodemask and,
+ if not already set, sets the node in the mempolicy nodemask.
+
+ For example, consider a task that is attached to a cpuset with
+ mems 2-5 that sets an Interleave policy over the same set with
+ MPOL_F_RELATIVE_NODES. If the cpuset's mems change to 3-7, the
+ interleave now occurs over nodes 3,5-6. If the cpuset's mems
+ then change to 0,2-3,5, then the interleave occurs over nodes
+ 0,3,5.
+
+ Thanks to the consistent remapping, applications preparing
+ nodemasks to specify memory policies using this flag should
+ disregard their current, actual cpuset imposed memory placement
+ and prepare the nodemask as if they were always located on
+ memory nodes 0 to N-1, where N is the number of memory nodes the
+ policy is intended to manage. Let the kernel then remap to the
+ set of memory nodes allowed by the task's cpuset, as that may
+ change over time.
+
+ MPOL_F_RELATIVE_NODES cannot be combined with the
+ MPOL_F_STATIC_NODES flag. It also cannot be used for
+ MPOL_PREFERRED policies that were created with an empty nodemask
+ (local allocation).
+
+MEMORY POLICY REFERENCE COUNTING
+
+To resolve use/free races, struct mempolicy contains an atomic reference
+count field. Internal interfaces, mpol_get()/mpol_put() increment and
+decrement this reference count, respectively. mpol_put() will only free
+the structure back to the mempolicy kmem cache when the reference count
+goes to zero.
+
+When a new memory policy is allocated, it's reference count is initialized
+to '1', representing the reference held by the task that is installing the
+new policy. When a pointer to a memory policy structure is stored in another
+structure, another reference is added, as the task's reference will be dropped
+on completion of the policy installation.
+
+During run-time "usage" of the policy, we attempt to minimize atomic operations
+on the reference count, as this can lead to cache lines bouncing between cpus
+and NUMA nodes. "Usage" here means one of the following:
+
+1) querying of the policy, either by the task itself [using the get_mempolicy()
+ API discussed below] or by another task using the /proc/<pid>/numa_maps
+ interface.
+
+2) examination of the policy to determine the policy mode and associated node
+ or node lists, if any, for page allocation. This is considered a "hot
+ path". Note that for MPOL_BIND, the "usage" extends across the entire
+ allocation process, which may sleep during page reclaimation, because the
+ BIND policy nodemask is used, by reference, to filter ineligible nodes.
+
+We can avoid taking an extra reference during the usages listed above as
+follows:
+
+1) we never need to get/free the system default policy as this is never
+ changed nor freed, once the system is up and running.
+
+2) for querying the policy, we do not need to take an extra reference on the
+ target task's task policy nor vma policies because we always acquire the
+ task's mm's mmap_sem for read during the query. The set_mempolicy() and
+ mbind() APIs [see below] always acquire the mmap_sem for write when
+ installing or replacing task or vma policies. Thus, there is no possibility
+ of a task or thread freeing a policy while another task or thread is
+ querying it.
+
+3) Page allocation usage of task or vma policy occurs in the fault path where
+ we hold them mmap_sem for read. Again, because replacing the task or vma
+ policy requires that the mmap_sem be held for write, the policy can't be
+ freed out from under us while we're using it for page allocation.
+
+4) Shared policies require special consideration. One task can replace a
+ shared memory policy while another task, with a distinct mmap_sem, is
+ querying or allocating a page based on the policy. To resolve this
+ potential race, the shared policy infrastructure adds an extra reference
+ to the shared policy during lookup while holding a spin lock on the shared
+ policy management structure. This requires that we drop this extra
+ reference when we're finished "using" the policy. We must drop the
+ extra reference on shared policies in the same query/allocation paths
+ used for non-shared policies. For this reason, shared policies are marked
+ as such, and the extra reference is dropped "conditionally"--i.e., only
+ for shared policies.
+
+ Because of this extra reference counting, and because we must lookup
+ shared policies in a tree structure under spinlock, shared policies are
+ more expensive to use in the page allocation path. This is expecially
+ true for shared policies on shared memory regions shared by tasks running
+ on different NUMA nodes. This extra overhead can be avoided by always
+ falling back to task or system default policy for shared memory regions,
+ or by prefaulting the entire shared memory region into memory and locking
+ it down. However, this might not be appropriate for all applications.
+
MEMORY POLICY APIs
Linux supports 3 system calls for controlling memory policy. These APIS
@@ -251,7 +380,9 @@ Set [Task] Memory Policy:
Set's the calling task's "task/process memory policy" to mode
specified by the 'mode' argument and the set of nodes defined
by 'nmask'. 'nmask' points to a bit mask of node ids containing
- at least 'maxnode' ids.
+ at least 'maxnode' ids. Optional mode flags may be passed by
+ combining the 'mode' argument with the flag (for example:
+ MPOL_INTERLEAVE | MPOL_F_STATIC_NODES).
See the set_mempolicy(2) man page for more details
@@ -303,29 +434,19 @@ MEMORY POLICIES AND CPUSETS
Memory policies work within cpusets as described above. For memory policies
that require a node or set of nodes, the nodes are restricted to the set of
nodes whose memories are allowed by the cpuset constraints. If the nodemask
-specified for the policy contains nodes that are not allowed by the cpuset, or
-the intersection of the set of nodes specified for the policy and the set of
-nodes with memory is the empty set, the policy is considered invalid
-and cannot be installed.
-
-The interaction of memory policies and cpusets can be problematic for a
-couple of reasons:
-
-1) the memory policy APIs take physical node id's as arguments. As mentioned
- above, it is illegal to specify nodes that are not allowed in the cpuset.
- The application must query the allowed nodes using the get_mempolicy()
- API with the MPOL_F_MEMS_ALLOWED flag to determine the allowed nodes and
- restrict itself to those nodes. However, the resources available to a
- cpuset can be changed by the system administrator, or a workload manager
- application, at any time. So, a task may still get errors attempting to
- specify policy nodes, and must query the allowed memories again.
-
-2) when tasks in two cpusets share access to a memory region, such as shared
- memory segments created by shmget() of mmap() with the MAP_ANONYMOUS and
- MAP_SHARED flags, and any of the tasks install shared policy on the region,
- only nodes whose memories are allowed in both cpusets may be used in the
- policies. Obtaining this information requires "stepping outside" the
- memory policy APIs to use the cpuset information and requires that one
- know in what cpusets other task might be attaching to the shared region.
- Furthermore, if the cpusets' allowed memory sets are disjoint, "local"
- allocation is the only valid policy.
+specified for the policy contains nodes that are not allowed by the cpuset and
+MPOL_F_RELATIVE_NODES is not used, the intersection of the set of nodes
+specified for the policy and the set of nodes with memory is used. If the
+result is the empty set, the policy is considered invalid and cannot be
+installed. If MPOL_F_RELATIVE_NODES is used, the policy's nodes are mapped
+onto and folded into the task's set of allowed nodes as previously described.
+
+The interaction of memory policies and cpusets can be problematic when tasks
+in two cpusets share access to a memory region, such as shared memory segments
+created by shmget() of mmap() with the MAP_ANONYMOUS and MAP_SHARED flags, and
+any of the tasks install shared policy on the region, only nodes whose
+memories are allowed in both cpusets may be used in the policies. Obtaining
+this information requires "stepping outside" the memory policy APIs to use the
+cpuset information and requires that one know in what cpusets other task might
+be attaching to the shared region. Furthermore, if the cpusets' allowed
+memory sets are disjoint, "local" allocation is the only valid policy.
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c
index 22d7e3e4d60c..d3ce295bffac 100644
--- a/Documentation/vm/slabinfo.c
+++ b/Documentation/vm/slabinfo.c
@@ -31,7 +31,7 @@ struct slabinfo {
int hwcache_align, object_size, objs_per_slab;
int sanity_checks, slab_size, store_user, trace;
int order, poison, reclaim_account, red_zone;
- unsigned long partial, objects, slabs;
+ unsigned long partial, objects, slabs, objects_partial, objects_total;
unsigned long alloc_fastpath, alloc_slowpath;
unsigned long free_fastpath, free_slowpath;
unsigned long free_frozen, free_add_partial, free_remove_partial;
@@ -540,7 +540,8 @@ void slabcache(struct slabinfo *s)
return;
store_size(size_str, slab_size(s));
- snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs);
+ snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
+ s->partial, s->cpu_slabs);
if (!line++)
first_line();
@@ -776,7 +777,6 @@ void totals(void)
unsigned long used;
unsigned long long wasted;
unsigned long long objwaste;
- long long objects_in_partial_slabs;
unsigned long percentage_partial_slabs;
unsigned long percentage_partial_objs;
@@ -790,18 +790,11 @@ void totals(void)
wasted = size - used;
objwaste = s->slab_size - s->object_size;
- objects_in_partial_slabs = s->objects -
- (s->slabs - s->partial - s ->cpu_slabs) *
- s->objs_per_slab;
-
- if (objects_in_partial_slabs < 0)
- objects_in_partial_slabs = 0;
-
percentage_partial_slabs = s->partial * 100 / s->slabs;
if (percentage_partial_slabs > 100)
percentage_partial_slabs = 100;
- percentage_partial_objs = objects_in_partial_slabs * 100
+ percentage_partial_objs = s->objects_partial * 100
/ s->objects;
if (percentage_partial_objs > 100)
@@ -823,8 +816,8 @@ void totals(void)
min_objects = s->objects;
if (used < min_used)
min_used = used;
- if (objects_in_partial_slabs < min_partobj)
- min_partobj = objects_in_partial_slabs;
+ if (s->objects_partial < min_partobj)
+ min_partobj = s->objects_partial;
if (percentage_partial_slabs < min_ppart)
min_ppart = percentage_partial_slabs;
if (percentage_partial_objs < min_ppartobj)
@@ -848,8 +841,8 @@ void totals(void)
max_objects = s->objects;
if (used > max_used)
max_used = used;
- if (objects_in_partial_slabs > max_partobj)
- max_partobj = objects_in_partial_slabs;
+ if (s->objects_partial > max_partobj)
+ max_partobj = s->objects_partial;
if (percentage_partial_slabs > max_ppart)
max_ppart = percentage_partial_slabs;
if (percentage_partial_objs > max_ppartobj)
@@ -864,7 +857,7 @@ void totals(void)
total_objects += s->objects;
total_used += used;
- total_partobj += objects_in_partial_slabs;
+ total_partobj += s->objects_partial;
total_ppart += percentage_partial_slabs;
total_ppartobj += percentage_partial_objs;
@@ -1160,6 +1153,8 @@ void read_slab_dir(void)
slab->hwcache_align = get_obj("hwcache_align");
slab->object_size = get_obj("object_size");
slab->objects = get_obj("objects");
+ slab->objects_partial = get_obj("objects_partial");
+ slab->objects_total = get_obj("objects_total");
slab->objs_per_slab = get_obj("objs_per_slab");
slab->order = get_obj("order");
slab->partial = get_obj("partial");
diff --git a/Kbuild b/Kbuild
index 1570d248ad92..32f19c5c9bb0 100644
--- a/Kbuild
+++ b/Kbuild
@@ -1,26 +1,61 @@
#
# Kbuild for top-level directory of the kernel
# This file takes care of the following:
-# 1) Generate asm-offsets.h
-# 2) Check for missing system calls
+# 1) Generate bounds.h
+# 2) Generate asm-offsets.h (may need bounds.h)
+# 3) Check for missing system calls
#####
-# 1) Generate asm-offsets.h
+# 1) Generate bounds.h
+
+bounds-file := include/linux/bounds.h
+
+always := $(bounds-file)
+targets := $(bounds-file) kernel/bounds.s
+
+quiet_cmd_bounds = GEN $@
+define cmd_bounds
+ (set -e; \
+ echo "#ifndef __LINUX_BOUNDS_H__"; \
+ echo "#define __LINUX_BOUNDS_H__"; \
+ echo "/*"; \
+ echo " * DO NOT MODIFY."; \
+ echo " *"; \
+ echo " * This file was generated by Kbuild"; \
+ echo " *"; \
+ echo " */"; \
+ echo ""; \
+ sed -ne $(sed-y) $<; \
+ echo ""; \
+ echo "#endif" ) > $@
+endef
+
+# We use internal kbuild rules to avoid the "is up to date" message from make
+kernel/bounds.s: kernel/bounds.c FORCE
+ $(Q)mkdir -p $(dir $@)
+ $(call if_changed_dep,cc_s_c)
+
+$(obj)/$(bounds-file): kernel/bounds.s Kbuild
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,bounds)
+
+#####
+# 2) Generate asm-offsets.h
#
offsets-file := include/asm-$(SRCARCH)/asm-offsets.h
-always := $(offsets-file)
-targets := $(offsets-file)
+always += $(offsets-file)
+targets += $(offsets-file)
targets += arch/$(SRCARCH)/kernel/asm-offsets.s
-clean-files := $(addprefix $(objtree)/,$(targets))
+
# Default sed regexp - multiline due to syntax constraints
define sed-y
- "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
+ "/^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:->::; p;}"
endef
-# Override default regexp for specific architectures
-sed-$(CONFIG_MIPS) := "/^@@@/{s/^@@@//; s/ \#.*\$$//; p;}"
quiet_cmd_offsets = GEN $@
define cmd_offsets
@@ -40,7 +75,8 @@ define cmd_offsets
endef
# We use internal kbuild rules to avoid the "is up to date" message from make
-arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c FORCE
+arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c \
+ $(obj)/$(bounds-file) FORCE
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cc_s_c)
@@ -49,7 +85,7 @@ $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s Kbuild
$(call cmd,offsets)
#####
-# 2) Check for missing system calls
+# 3) Check for missing system calls
#
quiet_cmd_syscalls = CALL $<
@@ -58,3 +94,7 @@ quiet_cmd_syscalls = CALL $<
PHONY += missing-syscalls
missing-syscalls: scripts/checksyscalls.sh FORCE
$(call cmd,syscalls)
+
+# Delete all targets during make clean
+clean-files := $(addprefix $(objtree)/,$(targets))
+
diff --git a/MAINTAINERS b/MAINTAINERS
index f50e927a1189..37debda36661 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1106,6 +1106,12 @@ M: kernel@wantstofly.org
L: linux-usb@vger.kernel.org
S: Maintained
+CIRRUS LOGIC CS4270 SOUND DRIVER
+P: Timur Tabi
+M: timur@freescale.com
+L: alsa-devel@alsa-project.org
+S: Supported
+
CIRRUS LOGIC CS4280/CS461x SOUNDDRIVER
P: Cirrus Logic Corporation (kernel 2.2 driver)
M: Cirrus Logic Corporation, Thomas Woller <twoller@crystal.cirrus.com>
@@ -1525,6 +1531,13 @@ L: bluesmoke-devel@lists.sourceforge.net
W: bluesmoke.sourceforge.net
S: Maintained
+EEEPC LAPTOP EXTRAS DRIVER
+P: Corentin Chary
+M: corentincj@iksaif.net
+L: acpi4asus-user@lists.sourceforge.net
+W: http://sourceforge.net/projects/acpi4asus
+S: Maintained
+
EEPRO100 NETWORK DRIVER
P: Andrey V. Savochkin
M: saw@saw.sw.com.sg
@@ -1628,6 +1641,12 @@ L: linuxppc-dev@ozlabs.org
L: netdev@vger.kernel.org
S: Maintained
+FREESCALE QUICC ENGINE LIBRARY
+P: Timur Tabi
+M: timur@freescale.com
+L: linuxppc-dev@ozlabs.org
+S: Supported
+
FREESCALE HIGHSPEED USB DEVICE DRIVER
P: Li Yang
M: leoli@freescale.com
@@ -1642,6 +1661,19 @@ L: netdev@vger.kernel.org
L: linuxppc-dev@ozlabs.org
S: Maintained
+FREESCALE QUICC ENGINE UCC UART DRIVER
+P: Timur Tabi
+M: timur@freescale.com
+L: linuxppc-dev@ozlabs.org
+S: Supported
+
+FREESCALE SOC SOUND DRIVERS
+P: Timur Tabi
+M: timur@freescale.com
+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
@@ -2304,6 +2336,13 @@ L: kvm-devel@lists.sourceforge.net
W: kvm.sourceforge.net
S: Supported
+KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
+P: Hollis Blanchard
+M: hollisb@us.ibm.com
+L: kvm-ppc-devel@lists.sourceforge.net
+W: kvm.sourceforge.net
+S: Supported
+
KERNEL VIRTUAL MACHINE For Itanium(KVM/IA64)
P: Anthony Xu
M: anthony.xu@intel.com
@@ -2313,6 +2352,16 @@ L: kvm-ia64-devel@lists.sourceforge.net
W: kvm.sourceforge.net
S: Supported
+KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
+P: Carsten Otte
+M: cotte@de.ibm.com
+P: Christian Borntraeger
+M: borntraeger@de.ibm.com
+M: linux390@de.ibm.com
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+
KEXEC
P: Eric Biederman
M: ebiederm@xmission.com
@@ -4356,6 +4405,16 @@ L: linux-wireless@vger.kernel.org
W: http://oops.ghostprotocols.net:81/blog
S: Maintained
+WM97XX TOUCHSCREEN DRIVERS
+P: Mark Brown
+M: broonie@opensource.wolfsonmicro.com
+P: Liam Girdwood
+M: liam.girdwood@wolfsonmicro.com
+L: linux-input@vger.kernel.org
+T: git git://opensource.wolfsonmicro.com/linux-2.6-touch
+W: http://opensource.wolfsonmicro.com/node/7
+S: Supported
+
X.25 NETWORK LAYER
P: Henner Eisen
M: eis@baty.hanse.de
diff --git a/Makefile b/Makefile
index 3dbc826bb8e6..d3634cd6fe35 100644
--- a/Makefile
+++ b/Makefile
@@ -507,6 +507,10 @@ else
KBUILD_CFLAGS += -O2
endif
+ifneq (CONFIG_FRAME_WARN,0)
+KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
+endif
+
# Force gcc to behave correct even for buggy distributions
# Arch Makefiles may override this setting
KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
@@ -1170,8 +1174,10 @@ rpm: include/config/kernel.release FORCE
# Brief documentation of the typical targets used
# ---------------------------------------------------------------------------
-boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig)
+boards := $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*_defconfig)
boards := $(notdir $(boards))
+board-dirs := $(dir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*/*_defconfig))
+board-dirs := $(sort $(notdir $(board-dirs:/=)))
help:
@echo 'Cleaning targets:'
@@ -1217,14 +1223,19 @@ help:
@echo 'Documentation targets:'
@$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp
@echo ''
- @echo 'Architecture specific targets ($(ARCH)):'
+ @echo 'Architecture specific targets ($(SRCARCH)):'
@$(if $(archhelp),$(archhelp),\
- echo ' No architecture specific help defined for $(ARCH)')
+ echo ' No architecture specific help defined for $(SRCARCH)')
@echo ''
@$(if $(boards), \
$(foreach b, $(boards), \
printf " %-24s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \
echo '')
+ @$(if $(board-dirs), \
+ $(foreach b, $(board-dirs), \
+ printf " %-16s - Show %s-specific targets\\n" help-$(b) $(b);) \
+ printf " %-16s - Show all of the above\\n" help-boards; \
+ echo '')
@echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
@echo ' make V=2 [targets] 2 => give reason for rebuild of target'
@@ -1236,6 +1247,20 @@ help:
@echo 'For further info see the ./README file'
+help-board-dirs := $(addprefix help-,$(board-dirs))
+
+help-boards: $(help-board-dirs)
+
+boards-per-dir = $(notdir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/$*/*_defconfig))
+
+$(help-board-dirs): help-%:
+ @echo 'Architecture specific targets ($(SRCARCH) $*):'
+ @$(if $(boards-per-dir), \
+ $(foreach b, $(boards-per-dir), \
+ printf " %-24s - Build for %s\\n" $*/$(b) $(subst _defconfig,,$(b));) \
+ echo '')
+
+
# Documentation targets
# ---------------------------------------------------------------------------
%docs: scripts_basic FORCE
@@ -1396,7 +1421,7 @@ define xtags
$(all-kconfigs) | xargs $1 -a \
--langdef=kconfig \
--language-force=kconfig \
- --regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \
+ --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/'; \
$(all-defconfigs) | xargs -r $1 -a \
--langdef=dotconfig \
--language-force=dotconfig \
@@ -1404,7 +1429,7 @@ define xtags
elif $1 --version 2>&1 | grep -iq emacs; then \
$(all-sources) | xargs $1 -a; \
$(all-kconfigs) | xargs $1 -a \
- --regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
+ --regex='/^[ \t]*(menu|)config[ \t]+\([a-zA-Z0-9_]+\)/\2/'; \
$(all-defconfigs) | xargs -r $1 -a \
--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
else \
@@ -1539,7 +1564,6 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files))
cmd_rmfiles = rm -f $(rm-files)
# Run depmod only if we have System.map and depmod is executable
-# and we build for the host arch
quiet_cmd_depmod = DEPMOD $(KERNELRELEASE)
cmd_depmod = \
if [ -r System.map -a -x $(DEPMOD) ]; then \
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
index f10d2eddd2c3..b04f1feb1dda 100644
--- a/arch/alpha/kernel/core_marvel.c
+++ b/arch/alpha/kernel/core_marvel.c
@@ -994,7 +994,7 @@ marvel_agp_configure(alpha_agp_info *agp)
* rate, but warn the user.
*/
printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
- __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
+ __func__, IO7_PLL_RNGB(agp_pll), agp_pll);
break;
}
@@ -1044,13 +1044,13 @@ marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
if (addr < agp->aperture.bus_base ||
addr >= agp->aperture.bus_base + agp->aperture.size) {
- printk("%s: addr out of range\n", __FUNCTION__);
+ printk("%s: addr out of range\n", __func__);
return -EINVAL;
}
pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
if (!(pte & 1)) {
- printk("%s: pte not valid\n", __FUNCTION__);
+ printk("%s: pte not valid\n", __func__);
return -EINVAL;
}
return (pte >> 1) << PAGE_SHIFT;
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
index f5ca5255eb06..c0750291b44a 100644
--- a/arch/alpha/kernel/core_t2.c
+++ b/arch/alpha/kernel/core_t2.c
@@ -336,10 +336,7 @@ t2_direct_map_window1(unsigned long base, unsigned long length)
#if DEBUG_PRINT_FINAL_SETTINGS
printk("%s: setting WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
- __FUNCTION__,
- *(vulp)T2_WBASE1,
- *(vulp)T2_WMASK1,
- *(vulp)T2_TBASE1);
+ __func__, *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
#endif
}
@@ -366,10 +363,7 @@ t2_sg_map_window2(struct pci_controller *hose,
#if DEBUG_PRINT_FINAL_SETTINGS
printk("%s: setting WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
- __FUNCTION__,
- *(vulp)T2_WBASE2,
- *(vulp)T2_WMASK2,
- *(vulp)T2_TBASE2);
+ __func__, *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
#endif
}
@@ -377,15 +371,15 @@ static void __init
t2_save_configuration(void)
{
#if DEBUG_PRINT_INITIAL_SETTINGS
- printk("%s: HAE_1 was 0x%lx\n", __FUNCTION__, srm_hae); /* HW is 0 */
- printk("%s: HAE_2 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_2);
- printk("%s: HAE_3 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_3);
- printk("%s: HAE_4 was 0x%lx\n", __FUNCTION__, *(vulp)T2_HAE_4);
- printk("%s: HBASE was 0x%lx\n", __FUNCTION__, *(vulp)T2_HBASE);
+ printk("%s: HAE_1 was 0x%lx\n", __func__, srm_hae); /* HW is 0 */
+ printk("%s: HAE_2 was 0x%lx\n", __func__, *(vulp)T2_HAE_2);
+ printk("%s: HAE_3 was 0x%lx\n", __func__, *(vulp)T2_HAE_3);
+ printk("%s: HAE_4 was 0x%lx\n", __func__, *(vulp)T2_HAE_4);
+ printk("%s: HBASE was 0x%lx\n", __func__, *(vulp)T2_HBASE);
- printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __FUNCTION__,
+ printk("%s: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n", __func__,
*(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
- printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __FUNCTION__,
+ printk("%s: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n", __func__,
*(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
#endif
diff --git a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c
index 819326627b96..319fcb74611e 100644
--- a/arch/alpha/kernel/core_titan.c
+++ b/arch/alpha/kernel/core_titan.c
@@ -365,21 +365,21 @@ void __init
titan_init_arch(void)
{
#if 0
- printk("%s: titan_init_arch()\n", __FUNCTION__);
- printk("%s: CChip registers:\n", __FUNCTION__);
- printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr);
- printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr);
- printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr);
- printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr);
- printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr);
- printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr);
- printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr);
- printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr);
-
- printk("%s: DChip registers:\n", __FUNCTION__);
- printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr);
- printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr);
- printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr);
+ printk("%s: titan_init_arch()\n", __func__);
+ printk("%s: CChip registers:\n", __func__);
+ printk("%s: CSR_CSC 0x%lx\n", __func__, TITAN_cchip->csc.csr);
+ printk("%s: CSR_MTR 0x%lx\n", __func__, TITAN_cchip->mtr.csr);
+ printk("%s: CSR_MISC 0x%lx\n", __func__, TITAN_cchip->misc.csr);
+ printk("%s: CSR_DIM0 0x%lx\n", __func__, TITAN_cchip->dim0.csr);
+ printk("%s: CSR_DIM1 0x%lx\n", __func__, TITAN_cchip->dim1.csr);
+ printk("%s: CSR_DIR0 0x%lx\n", __func__, TITAN_cchip->dir0.csr);
+ printk("%s: CSR_DIR1 0x%lx\n", __func__, TITAN_cchip->dir1.csr);
+ printk("%s: CSR_DRIR 0x%lx\n", __func__, TITAN_cchip->drir.csr);
+
+ printk("%s: DChip registers:\n", __func__);
+ printk("%s: CSR_DSC 0x%lx\n", __func__, TITAN_dchip->dsc.csr);
+ printk("%s: CSR_STR 0x%lx\n", __func__, TITAN_dchip->str.csr);
+ printk("%s: CSR_DREV 0x%lx\n", __func__, TITAN_dchip->drev.csr);
#endif
boot_cpuid = __hard_smp_processor_id();
@@ -700,13 +700,13 @@ titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
if (addr < agp->aperture.bus_base ||
addr >= agp->aperture.bus_base + agp->aperture.size) {
- printk("%s: addr out of range\n", __FUNCTION__);
+ printk("%s: addr out of range\n", __func__);
return -EINVAL;
}
pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
if (!(pte & 1)) {
- printk("%s: pte not valid\n", __FUNCTION__);
+ printk("%s: pte not valid\n", __func__);
return -EINVAL;
}
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index ef91e09590d4..5e7c28f92f19 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -241,8 +241,6 @@ tsunami_probe_write(volatile unsigned long *vaddr)
#define tsunami_probe_read(ADDR) 1
#endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */
-#define FN __FUNCTION__
-
static void __init
tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
{
@@ -383,27 +381,27 @@ tsunami_init_arch(void)
/* NXMs just don't matter to Tsunami--unless they make it
choke completely. */
tmp = (unsigned long)(TSUNAMI_cchip - 1);
- printk("%s: probing bogus address: 0x%016lx\n", FN, bogus_addr);
+ printk("%s: probing bogus address: 0x%016lx\n", __func__, bogus_addr);
printk("\tprobe %s\n",
tsunami_probe_write((unsigned long *)bogus_addr)
? "succeeded" : "failed");
#endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */
#if 0
- printk("%s: CChip registers:\n", FN);
- printk("%s: CSR_CSC 0x%lx\n", FN, TSUNAMI_cchip->csc.csr);
- printk("%s: CSR_MTR 0x%lx\n", FN, TSUNAMI_cchip.mtr.csr);
- printk("%s: CSR_MISC 0x%lx\n", FN, TSUNAMI_cchip->misc.csr);
- printk("%s: CSR_DIM0 0x%lx\n", FN, TSUNAMI_cchip->dim0.csr);
- printk("%s: CSR_DIM1 0x%lx\n", FN, TSUNAMI_cchip->dim1.csr);
- printk("%s: CSR_DIR0 0x%lx\n", FN, TSUNAMI_cchip->dir0.csr);
- printk("%s: CSR_DIR1 0x%lx\n", FN, TSUNAMI_cchip->dir1.csr);
- printk("%s: CSR_DRIR 0x%lx\n", FN, TSUNAMI_cchip->drir.csr);
+ printk("%s: CChip registers:\n", __func__);
+ printk("%s: CSR_CSC 0x%lx\n", __func__, TSUNAMI_cchip->csc.csr);
+ printk("%s: CSR_MTR 0x%lx\n", __func__, TSUNAMI_cchip.mtr.csr);
+ printk("%s: CSR_MISC 0x%lx\n", __func__, TSUNAMI_cchip->misc.csr);
+ printk("%s: CSR_DIM0 0x%lx\n", __func__, TSUNAMI_cchip->dim0.csr);
+ printk("%s: CSR_DIM1 0x%lx\n", __func__, TSUNAMI_cchip->dim1.csr);
+ printk("%s: CSR_DIR0 0x%lx\n", __func__, TSUNAMI_cchip->dir0.csr);
+ printk("%s: CSR_DIR1 0x%lx\n", __func__, TSUNAMI_cchip->dir1.csr);
+ printk("%s: CSR_DRIR 0x%lx\n", __func__, TSUNAMI_cchip->drir.csr);
printk("%s: DChip registers:\n");
- printk("%s: CSR_DSC 0x%lx\n", FN, TSUNAMI_dchip->dsc.csr);
- printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr);
- printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr);
+ printk("%s: CSR_DSC 0x%lx\n", __func__, TSUNAMI_dchip->dsc.csr);
+ printk("%s: CSR_STR 0x%lx\n", __func__, TSUNAMI_dchip->str.csr);
+ printk("%s: CSR_DREV 0x%lx\n", __func__, TSUNAMI_dchip->drev.csr);
#endif
/* With multiple PCI busses, we play with I/O as physical addrs. */
ioport_resource.end = ~0UL;
diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c
index 026ba9af6d6a..ebc3c894b5a2 100644
--- a/arch/alpha/kernel/module.c
+++ b/arch/alpha/kernel/module.c
@@ -120,6 +120,12 @@ module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs,
nsyms = symtab->sh_size / sizeof(Elf64_Sym);
chains = kcalloc(nsyms, sizeof(struct got_entry), GFP_KERNEL);
+ if (!chains) {
+ printk(KERN_ERR
+ "module %s: no memory for symbol chain buffer\n",
+ me->name);
+ return -ENOMEM;
+ }
got->sh_size = 0;
got->sh_addralign = 8;
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 78357798b6fd..baf57563b14c 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -208,7 +208,7 @@ pdev_save_srm_config(struct pci_dev *dev)
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
- printk(KERN_ERR "%s: kmalloc() failed!\n", __FUNCTION__);
+ printk(KERN_ERR "%s: kmalloc() failed!\n", __func__);
return;
}
tmp->next = srm_saved_configs;
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index dd6e334ab9e1..2179c602032a 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -79,25 +79,21 @@ iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base,
#ifdef CONFIG_DISCONTIGMEM
- if (!NODE_DATA(nid) ||
- (NULL == (arena = alloc_bootmem_node(NODE_DATA(nid),
- sizeof(*arena))))) {
- printk("%s: couldn't allocate arena from node %d\n"
- " falling back to system-wide allocation\n",
- __FUNCTION__, nid);
- arena = alloc_bootmem(sizeof(*arena));
- }
-
- if (!NODE_DATA(nid) ||
- (NULL == (arena->ptes = __alloc_bootmem_node(NODE_DATA(nid),
- mem_size,
- align,
- 0)))) {
- printk("%s: couldn't allocate arena ptes from node %d\n"
- " falling back to system-wide allocation\n",
- __FUNCTION__, nid);
- arena->ptes = __alloc_bootmem(mem_size, align, 0);
- }
+ arena = alloc_bootmem_node(NODE_DATA(nid), sizeof(*arena));
+ if (!NODE_DATA(nid) || !arena) {
+ printk("%s: couldn't allocate arena from node %d\n"
+ " falling back to system-wide allocation\n",
+ __func__, nid);
+ arena = alloc_bootmem(sizeof(*arena));
+ }
+
+ arena->ptes = __alloc_bootmem_node(NODE_DATA(nid), mem_size, align, 0);
+ if (!NODE_DATA(nid) || !arena->ptes) {
+ printk("%s: couldn't allocate arena ptes from node %d\n"
+ " falling back to system-wide allocation\n",
+ __func__, nid);
+ arena->ptes = __alloc_bootmem(mem_size, align, 0);
+ }
#else /* CONFIG_DISCONTIGMEM */
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 63c2073401ee..2525692db0ab 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -755,7 +755,7 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
if (atomic_read(&data.unstarted_count) > 0) {
long start_time = jiffies;
printk(KERN_ERR "%s: initial timeout -- trying long wait\n",
- __FUNCTION__);
+ __func__);
timeout = jiffies + 30 * HZ;
while (atomic_read(&data.unstarted_count) > 0
&& time_before(jiffies, timeout))
@@ -764,7 +764,7 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
long delta = jiffies - start_time;
printk(KERN_ERR
"%s: response %ld.%ld seconds into long wait\n",
- __FUNCTION__, delta / HZ,
+ __func__, delta / HZ,
(100 * (delta - ((delta / HZ) * HZ))) / HZ);
}
}
diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c
index f7dd081d57ff..78ad7cd1bbd6 100644
--- a/arch/alpha/kernel/srm_env.c
+++ b/arch/alpha/kernel/srm_env.c
@@ -199,7 +199,7 @@ srm_env_init(void)
printk(KERN_INFO "%s: This Alpha system doesn't "
"know about SRM (or you've booted "
"SRM->MILO->Linux, which gets "
- "misdetected)...\n", __FUNCTION__);
+ "misdetected)...\n", __func__);
return -ENODEV;
}
diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
index d187d01d2a17..e53a1e1c2f21 100644
--- a/arch/alpha/kernel/sys_alcor.c
+++ b/arch/alpha/kernel/sys_alcor.c
@@ -259,7 +259,7 @@ alcor_init_pci(void)
if (dev && dev->devfn == PCI_DEVFN(6,0)) {
alpha_mv.sys.cia.gru_int_req_bits = XLT_GRU_INT_REQ_BITS;
printk(KERN_INFO "%s: Detected AS500 or XLT motherboard.\n",
- __FUNCTION__);
+ __func__);
}
pci_dev_put(dev);
}
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 922143ea1cdb..828449cd2636 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -80,7 +80,7 @@ io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
if (!(io7 = marvel_find_io7(pid))) {
printk(KERN_ERR
"%s for nonexistent io7 -- vec %x, pid %d\n",
- __FUNCTION__, irq, pid);
+ __func__, irq, pid);
return NULL;
}
@@ -90,7 +90,7 @@ io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
if (irq >= 0x180) {
printk(KERN_ERR
"%s for invalid irq -- pid %d adjusted irq %x\n",
- __FUNCTION__, pid, irq);
+ __func__, pid, irq);
return NULL;
}
@@ -110,8 +110,8 @@ io7_enable_irq(unsigned int irq)
ctl = io7_get_irq_ctl(irq, &io7);
if (!ctl || !io7) {
- printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
- __FUNCTION__, irq);
+ printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
+ __func__, irq);
return;
}
@@ -130,8 +130,8 @@ io7_disable_irq(unsigned int irq)
ctl = io7_get_irq_ctl(irq, &io7);
if (!ctl || !io7) {
- printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
- __FUNCTION__, irq);
+ printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
+ __func__, irq);
return;
}
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
index 906019cfa681..99a7f19da13a 100644
--- a/arch/alpha/kernel/sys_sable.c
+++ b/arch/alpha/kernel/sys_sable.c
@@ -454,7 +454,7 @@ sable_lynx_enable_irq(unsigned int irq)
spin_unlock(&sable_lynx_irq_lock);
#if 0
printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
- __FUNCTION__, mask, bit, irq);
+ __func__, mask, bit, irq);
#endif
}
@@ -470,7 +470,7 @@ sable_lynx_disable_irq(unsigned int irq)
spin_unlock(&sable_lynx_irq_lock);
#if 0
printk("%s: mask 0x%lx bit 0x%x irq 0x%x\n",
- __FUNCTION__, mask, bit, irq);
+ __func__, mask, bit, irq);
#endif
}
@@ -524,7 +524,7 @@ sable_lynx_srm_device_interrupt(unsigned long vector)
irq = sable_lynx_irq_swizzle->mask_to_irq[bit];
#if 0
printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n",
- __FUNCTION__, vector, bit, irq);
+ __func__, vector, bit, irq);
#endif
handle_irq(irq);
}
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
index ee7b9009ebb4..d4327e461c22 100644
--- a/arch/alpha/kernel/sys_sio.c
+++ b/arch/alpha/kernel/sys_sio.c
@@ -89,7 +89,7 @@ sio_pci_route(void)
/* First, ALWAYS read and print the original setting. */
pci_bus_read_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60,
&orig_route_tab);
- printk("%s: PIRQ original 0x%x new 0x%x\n", __FUNCTION__,
+ printk("%s: PIRQ original 0x%x new 0x%x\n", __func__,
orig_route_tab, alpha_mv.sys.sio.route_tab);
#if defined(ALPHA_RESTORE_SRM_SETUP)
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 2dc7f9fed213..dc57790250d2 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -8,6 +8,7 @@
* This file initializes the trap entry points
*/
+#include <linux/jiffies.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -770,7 +771,7 @@ do_entUnaUser(void __user * va, unsigned long opcode,
unsigned long reg, struct pt_regs *regs)
{
static int cnt = 0;
- static long last_time = 0;
+ static unsigned long last_time;
unsigned long tmp1, tmp2, tmp3, tmp4;
unsigned long fake_reg, *reg_addr = &fake_reg;
@@ -781,7 +782,7 @@ do_entUnaUser(void __user * va, unsigned long opcode,
with the unaliged access. */
if (!test_thread_flag (TIF_UAC_NOPRINT)) {
- if (cnt >= 5 && jiffies - last_time > 5*HZ) {
+ if (cnt >= 5 && time_after(jiffies, last_time + 5 * HZ)) {
cnt = 0;
}
if (++cnt < 5) {
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d8d253285a94..b786e68914d4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
config ARM
bool
default y
+ select HAVE_IDE
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
select HAVE_OPROFILE
@@ -223,7 +224,6 @@ config ARCH_CLPS7500
select TIMER_ACORN
select ISA
select NO_IOPORT
- select HAVE_IDE
help
Support for the Cirrus Logic PS7500FE system-on-a-chip.
@@ -236,7 +236,6 @@ config ARCH_CO285
bool "Co-EBSA285"
select FOOTBRIDGE
select FOOTBRIDGE_ADDIN
- select HAVE_IDE
help
Support for Intel's EBSA285 companion chip.
@@ -262,7 +261,6 @@ config ARCH_EP93XX
config ARCH_FOOTBRIDGE
bool "FootBridge"
select FOOTBRIDGE
- select HAVE_IDE
help
Support for systems based on the DC21285 companion chip
("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
@@ -301,7 +299,6 @@ config ARCH_IOP32X
depends on MMU
select PLAT_IOP
select PCI
- select HAVE_IDE
help
Support for Intel's 80219 and IOP32X (XScale) family of
processors.
@@ -311,14 +308,12 @@ config ARCH_IOP33X
depends on MMU
select PLAT_IOP
select PCI
- select HAVE_IDE
help
Support for Intel's IOP33X (XScale) family of processors.
config ARCH_IXP23XX
bool "IXP23XX-based"
depends on MMU
- select HAVE_IDE
select PCI
help
Support for Intel's IXP23xx (XScale) family of processors.
@@ -336,14 +331,12 @@ config ARCH_IXP4XX
select GENERIC_GPIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
- select HAVE_IDE
help
Support for Intel's IXP4XX (XScale) family of processors.
config ARCH_L7200
bool "LinkUp-L7200"
select FIQ
- select HAVE_IDE
help
Say Y here if you intend to run this kernel on a LinkUp Systems
L7200 Software Development Board which uses an ARM720T processor.
@@ -400,7 +393,6 @@ config ARCH_PXA
depends on MMU
select ARCH_MTD_XIP
select GENERIC_GPIO
- select HAVE_IDE
select HAVE_GPIO_LIB
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
@@ -416,7 +408,6 @@ config ARCH_RPC
select ARCH_MAY_HAVE_PC_FDC
select ISA_DMA_API
select NO_IOPORT
- select HAVE_IDE
help
On the Acorn Risc-PC, Linux can support the internal IDE disk and
CD-ROM interface, serial and parallel port, and the floppy drive.
@@ -432,7 +423,6 @@ config ARCH_SA1100
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select TICK_ONESHOT
- select HAVE_IDE
select HAVE_GPIO_LIB
help
Support for StrongARM 11x0 based boards.
@@ -440,7 +430,6 @@ config ARCH_SA1100
config ARCH_S3C2410
bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
select GENERIC_GPIO
- select HAVE_IDE
help
Samsung S3C2410X CPU based systems, such as the Simtec Electronics
BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
@@ -448,7 +437,6 @@ config ARCH_S3C2410
config ARCH_SHARK
bool "Shark"
- select HAVE_IDE
select ISA
select ISA_DMA
select PCI
@@ -458,7 +446,6 @@ config ARCH_SHARK
config ARCH_LH7A40X
bool "Sharp LH7A40X"
- select HAVE_IDE
help
Say Y here for systems based on one of the Sharp LH7A40X
System on a Chip processors. These CPUs include an ARM922T
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 37cd547855b1..728bb8f39441 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -539,6 +539,17 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */
#endif
+ if (ARRAY_SIZE(lcdc_resources) > 2) {
+ void __iomem *fb;
+ struct resource *fb_res = &lcdc_resources[2];
+ size_t fb_len = fb_res->end - fb_res->start + 1;
+
+ fb = ioremap_writecombine(fb_res->start, fb_len);
+ if (fb) {
+ memset(fb, 0, fb_len);
+ iounmap(fb, fb_len);
+ }
+ }
lcdc_data = *data;
platform_device_register(&at91_lcdc_device);
}
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index dbb9a5fc2090..054689804e77 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -381,6 +381,20 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
at91_set_B_periph(AT91_PIN_PC24, 0); /* LCDD22 */
at91_set_B_periph(AT91_PIN_PC25, 0); /* LCDD23 */
+#ifdef CONFIG_FB_INTSRAM
+ {
+ void __iomem *fb;
+ struct resource *fb_res = &lcdc_resources[2];
+ size_t fb_len = fb_res->end - fb_res->start + 1;
+
+ fb = ioremap_writecombine(fb_res->start, fb_len);
+ if (fb) {
+ memset(fb, 0, fb_len);
+ iounmap(fb, fb_len);
+ }
+ }
+#endif
+
lcdc_data = *data;
platform_device_register(&at91_lcdc_device);
}
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index 2687b730e2d0..ce48c14f4349 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -274,6 +274,8 @@ static int __init early_parse_fbmem(char *p)
printk(KERN_WARNING
"Failed to allocate framebuffer memory\n");
fbmem_size = 0;
+ } else {
+ memset(__va(fbmem_start), 0, fbmem_size);
}
}
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
index 4207a2b52750..5b06ffa15e34 100644
--- a/arch/cris/mm/init.c
+++ b/arch/cris/mm/init.c
@@ -27,7 +27,6 @@ show_mem(void)
printk("\nMem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
while (i-- > 0) {
total++;
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index c57ce3f1f2e2..73f3aeefd203 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -163,14 +163,11 @@ static int sysctl_pm_do_suspend(ctl_table *ctl, int write, struct file *filp,
if ((mode != 1) && (mode != 5))
return -EINVAL;
- retval = pm_send_all(PM_SUSPEND, (void *)3);
-
if (retval == 0) {
if (mode == 5)
retval = pm_do_bus_sleep();
else
retval = pm_do_suspend();
- pm_send_all(PM_RESUME, (void *)0);
}
return retval;
@@ -183,9 +180,6 @@ static int try_set_cmode(int new_cmode)
if (!(clock_cmodes_permitted & (1<<new_cmode)))
return -EINVAL;
- /* tell all the drivers we're suspending */
- pm_send_all(PM_SUSPEND, (void *)3);
-
/* now change cmode */
local_irq_disable();
frv_dma_pause_all();
@@ -201,8 +195,6 @@ static int try_set_cmode(int new_cmode)
frv_dma_resume_all();
local_irq_enable();
- /* tell all the drivers we're resuming */
- pm_send_all(PM_RESUME, (void *)0);
return 0;
}
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index 7089c2428b3f..a40df80b2ebd 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -49,7 +49,7 @@ asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsi
info.si_signo = SIGSEGV;
info.si_code = SEGV_ACCERR;
info.si_errno = 0;
- info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
+ info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
force_sig_info(info.si_signo, &info, current);
} /* end insn_access_error() */
@@ -73,7 +73,7 @@ asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, un
epcr0, esr0, esfr1);
info.si_errno = 0;
- info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
+ info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
switch (__frame->tbr & TBR_TT) {
case TBR_TT_ILLEGAL_INSTR:
@@ -111,7 +111,8 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
unsigned long esr0)
{
static DEFINE_SPINLOCK(atomic_op_lock);
- unsigned long x, y, z, *p;
+ unsigned long x, y, z;
+ unsigned long __user *p;
mm_segment_t oldfs;
siginfo_t info;
int ret;
@@ -128,7 +129,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
*/
case TBR_TT_ATOMIC_CMPXCHG32:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
x = __frame->gr9;
y = __frame->gr10;
@@ -158,7 +159,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* u32 __atomic_kernel_xchg32(void *v, u32 new)
*/
case TBR_TT_ATOMIC_XCHG32:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
y = __frame->gr9;
for (;;) {
@@ -181,7 +182,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
*/
case TBR_TT_ATOMIC_XOR:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
x = __frame->gr9;
for (;;) {
@@ -205,7 +206,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* ulong __atomic_kernel_OR_return(ulong i, ulong *v)
*/
case TBR_TT_ATOMIC_OR:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
x = __frame->gr9;
for (;;) {
@@ -229,7 +230,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* ulong __atomic_kernel_AND_return(ulong i, ulong *v)
*/
case TBR_TT_ATOMIC_AND:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
x = __frame->gr9;
for (;;) {
@@ -253,7 +254,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* int __atomic_user_sub_return(atomic_t *v, int i)
*/
case TBR_TT_ATOMIC_SUB:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
x = __frame->gr9;
for (;;) {
@@ -277,7 +278,7 @@ asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
* int __atomic_user_add_return(atomic_t *v, int i)
*/
case TBR_TT_ATOMIC_ADD:
- p = (unsigned long *) __frame->gr8;
+ p = (unsigned long __user *) __frame->gr8;
x = __frame->gr9;
for (;;) {
@@ -322,7 +323,7 @@ error:
info.si_signo = SIGSEGV;
info.si_code = SEGV_ACCERR;
info.si_errno = 0;
- info.si_addr = (void *) __frame->pc;
+ info.si_addr = (void __user *) __frame->pc;
force_sig_info(info.si_signo, &info, current);
}
@@ -343,7 +344,7 @@ asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
info.si_signo = SIGFPE;
info.si_code = FPE_MDAOVF;
info.si_errno = 0;
- info.si_addr = (void *) __frame->pc;
+ info.si_addr = (void __user *) __frame->pc;
force_sig_info(info.si_signo, &info, current);
} /* end media_exception() */
@@ -383,7 +384,7 @@ asmlinkage void memory_access_exception(unsigned long esr0,
info.si_addr = NULL;
if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
- info.si_addr = (void *) ear0;
+ info.si_addr = (void __user *) ear0;
force_sig_info(info.si_signo, &info, current);
@@ -412,7 +413,7 @@ asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsi
info.si_signo = SIGSEGV;
info.si_code = SEGV_ACCERR;
info.si_errno = 0;
- info.si_addr = (void *)
+ info.si_addr = (void __user *)
(((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
force_sig_info(info.si_signo, &info, current);
@@ -446,7 +447,7 @@ asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsi
info.si_signo = SIGFPE;
info.si_code = FPE_INTDIV;
info.si_errno = 0;
- info.si_addr = (void *) __frame->pc;
+ info.si_addr = (void __user *) __frame->pc;
force_sig_info(info.si_signo, &info, current);
} /* end division_exception() */
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index cd13e138bd03..3aa6c821449a 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -19,6 +19,7 @@ config IA64
select HAVE_OPROFILE
select HAVE_KPROBES
select HAVE_KRETPROBES
+ select HAVE_KVM
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
@@ -589,6 +590,8 @@ config MSPEC
source "fs/Kconfig"
+source "arch/ia64/kvm/Kconfig"
+
source "lib/Kconfig"
#
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index f1645c4f7039..ec4cca477f49 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -57,6 +57,7 @@ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/
core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/
+core-$(CONFIG_KVM) += arch/ia64/kvm/
drivers-$(CONFIG_PCI) += arch/ia64/pci/
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig
new file mode 100644
index 000000000000..7914e4828504
--- /dev/null
+++ b/arch/ia64/kvm/Kconfig
@@ -0,0 +1,49 @@
+#
+# KVM configuration
+#
+config HAVE_KVM
+ bool
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ depends on HAVE_KVM || IA64
+ default y
+ ---help---
+ Say Y here to get to see options for using your Linux host to run other
+ operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ tristate "Kernel-based Virtual Machine (KVM) support"
+ depends on HAVE_KVM && EXPERIMENTAL
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ ---help---
+ Support hosting fully virtualized guest machines using hardware
+ virtualization extensions. You will need a fairly recent
+ processor equipped with virtualization extensions. You will also
+ need to select one or more of the processor modules below.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ To compile this as a module, choose M here: the module
+ will be called kvm.
+
+ If unsure, say N.
+
+config KVM_INTEL
+ tristate "KVM for Intel Itanium 2 processors support"
+ depends on KVM && m
+ ---help---
+ Provides support for KVM on Itanium 2 processors equipped with the VT
+ extensions.
+
+config KVM_TRACE
+ bool
+
+endif # VIRTUALIZATION
diff --git a/arch/ia64/kvm/Makefile b/arch/ia64/kvm/Makefile
new file mode 100644
index 000000000000..52353397a1a4
--- /dev/null
+++ b/arch/ia64/kvm/Makefile
@@ -0,0 +1,58 @@
+#This Make file is to generate asm-offsets.h and build source.
+#
+
+#Generate asm-offsets.h for vmm module build
+offsets-file := asm-offsets.h
+
+always := $(offsets-file)
+targets := $(offsets-file)
+targets += arch/ia64/kvm/asm-offsets.s
+clean-files := $(addprefix $(objtree)/,$(targets) $(obj)/memcpy.S $(obj)/memset.S)
+
+# Default sed regexp - multiline due to syntax constraints
+define sed-y
+ "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
+endef
+
+quiet_cmd_offsets = GEN $@
+define cmd_offsets
+ (set -e; \
+ echo "#ifndef __ASM_KVM_OFFSETS_H__"; \
+ echo "#define __ASM_KVM_OFFSETS_H__"; \
+ echo "/*"; \
+ echo " * DO NOT MODIFY."; \
+ echo " *"; \
+ echo " * This file was generated by Makefile"; \
+ echo " *"; \
+ echo " */"; \
+ echo ""; \
+ sed -ne $(sed-y) $<; \
+ echo ""; \
+ echo "#endif" ) > $@
+endef
+# We use internal rules to avoid the "is up to date" message from make
+arch/ia64/kvm/asm-offsets.s: arch/ia64/kvm/asm-offsets.c
+ $(call if_changed_dep,cc_s_c)
+
+$(obj)/$(offsets-file): arch/ia64/kvm/asm-offsets.s
+ $(call cmd,offsets)
+
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
+EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
+
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o)
+
+kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o
+obj-$(CONFIG_KVM) += kvm.o
+
+FORCE : $(obj)/$(offsets-file)
+EXTRA_CFLAGS_vcpu.o += -mfixed-range=f2-f5,f12-f127
+kvm-intel-objs = vmm.o vmm_ivt.o trampoline.o vcpu.o optvfault.o mmio.o \
+ vtlb.o process.o
+#Add link memcpy and memset to avoid possible structure assignment error
+kvm-intel-objs += ../lib/memset.o ../lib/memcpy.o
+obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/arch/ia64/kvm/asm-offsets.c b/arch/ia64/kvm/asm-offsets.c
new file mode 100644
index 000000000000..4e3dc13a619c
--- /dev/null
+++ b/arch/ia64/kvm/asm-offsets.c
@@ -0,0 +1,251 @@
+/*
+ * asm-offsets.c Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ *
+ * Anthony Xu <anthony.xu@intel.com>
+ * Xiantao Zhang <xiantao.zhang@intel.com>
+ * Copyright (c) 2007 Intel Corporation KVM support.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/autoconf.h>
+#include <linux/kvm_host.h>
+
+#include "vcpu.h"
+
+#define task_struct kvm_vcpu
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " (%0) " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : :)
+
+#define OFFSET(_sym, _str, _mem) \
+ DEFINE(_sym, offsetof(_str, _mem));
+
+void foo(void)
+{
+ DEFINE(VMM_TASK_SIZE, sizeof(struct kvm_vcpu));
+ DEFINE(VMM_PT_REGS_SIZE, sizeof(struct kvm_pt_regs));
+
+ BLANK();
+
+ DEFINE(VMM_VCPU_META_RR0_OFFSET,
+ offsetof(struct kvm_vcpu, arch.metaphysical_rr0));
+ DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET,
+ offsetof(struct kvm_vcpu,
+ arch.metaphysical_saved_rr0));
+ DEFINE(VMM_VCPU_VRR0_OFFSET,
+ offsetof(struct kvm_vcpu, arch.vrr[0]));
+ DEFINE(VMM_VPD_IRR0_OFFSET,
+ offsetof(struct vpd, irr[0]));
+ DEFINE(VMM_VCPU_ITC_CHECK_OFFSET,
+ offsetof(struct kvm_vcpu, arch.itc_check));
+ DEFINE(VMM_VCPU_IRQ_CHECK_OFFSET,
+ offsetof(struct kvm_vcpu, arch.irq_check));
+ DEFINE(VMM_VPD_VHPI_OFFSET,
+ offsetof(struct vpd, vhpi));
+ DEFINE(VMM_VCPU_VSA_BASE_OFFSET,
+ offsetof(struct kvm_vcpu, arch.vsa_base));
+ DEFINE(VMM_VCPU_VPD_OFFSET,
+ offsetof(struct kvm_vcpu, arch.vpd));
+ DEFINE(VMM_VCPU_IRQ_CHECK,
+ offsetof(struct kvm_vcpu, arch.irq_check));
+ DEFINE(VMM_VCPU_TIMER_PENDING,
+ offsetof(struct kvm_vcpu, arch.timer_pending));
+ DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET,
+ offsetof(struct kvm_vcpu, arch.metaphysical_saved_rr0));
+ DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET,
+ offsetof(struct kvm_vcpu, arch.mode_flags));
+ DEFINE(VMM_VCPU_ITC_OFS_OFFSET,
+ offsetof(struct kvm_vcpu, arch.itc_offset));
+ DEFINE(VMM_VCPU_LAST_ITC_OFFSET,
+ offsetof(struct kvm_vcpu, arch.last_itc));
+ DEFINE(VMM_VCPU_SAVED_GP_OFFSET,
+ offsetof(struct kvm_vcpu, arch.saved_gp));
+
+ BLANK();
+
+ DEFINE(VMM_PT_REGS_B6_OFFSET,
+ offsetof(struct kvm_pt_regs, b6));
+ DEFINE(VMM_PT_REGS_B7_OFFSET,
+ offsetof(struct kvm_pt_regs, b7));
+ DEFINE(VMM_PT_REGS_AR_CSD_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_csd));
+ DEFINE(VMM_PT_REGS_AR_SSD_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_ssd));
+ DEFINE(VMM_PT_REGS_R8_OFFSET,
+ offsetof(struct kvm_pt_regs, r8));
+ DEFINE(VMM_PT_REGS_R9_OFFSET,
+ offsetof(struct kvm_pt_regs, r9));
+ DEFINE(VMM_PT_REGS_R10_OFFSET,
+ offsetof(struct kvm_pt_regs, r10));
+ DEFINE(VMM_PT_REGS_R11_OFFSET,
+ offsetof(struct kvm_pt_regs, r11));
+ DEFINE(VMM_PT_REGS_CR_IPSR_OFFSET,
+ offsetof(struct kvm_pt_regs, cr_ipsr));
+ DEFINE(VMM_PT_REGS_CR_IIP_OFFSET,
+ offsetof(struct kvm_pt_regs, cr_iip));
+ DEFINE(VMM_PT_REGS_CR_IFS_OFFSET,
+ offsetof(struct kvm_pt_regs, cr_ifs));
+ DEFINE(VMM_PT_REGS_AR_UNAT_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_unat));
+ DEFINE(VMM_PT_REGS_AR_PFS_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_pfs));
+ DEFINE(VMM_PT_REGS_AR_RSC_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_rsc));
+ DEFINE(VMM_PT_REGS_AR_RNAT_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_rnat));
+
+ DEFINE(VMM_PT_REGS_AR_BSPSTORE_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_bspstore));
+ DEFINE(VMM_PT_REGS_PR_OFFSET,
+ offsetof(struct kvm_pt_regs, pr));
+ DEFINE(VMM_PT_REGS_B0_OFFSET,
+ offsetof(struct kvm_pt_regs, b0));
+ DEFINE(VMM_PT_REGS_LOADRS_OFFSET,
+ offsetof(struct kvm_pt_regs, loadrs));
+ DEFINE(VMM_PT_REGS_R1_OFFSET,
+ offsetof(struct kvm_pt_regs, r1));
+ DEFINE(VMM_PT_REGS_R12_OFFSET,
+ offsetof(struct kvm_pt_regs, r12));
+ DEFINE(VMM_PT_REGS_R13_OFFSET,
+ offsetof(struct kvm_pt_regs, r13));
+ DEFINE(VMM_PT_REGS_AR_FPSR_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_fpsr));
+ DEFINE(VMM_PT_REGS_R15_OFFSET,
+ offsetof(struct kvm_pt_regs, r15));
+ DEFINE(VMM_PT_REGS_R14_OFFSET,
+ offsetof(struct kvm_pt_regs, r14));
+ DEFINE(VMM_PT_REGS_R2_OFFSET,
+ offsetof(struct kvm_pt_regs, r2));
+ DEFINE(VMM_PT_REGS_R3_OFFSET,
+ offsetof(struct kvm_pt_regs, r3));
+ DEFINE(VMM_PT_REGS_R16_OFFSET,
+ offsetof(struct kvm_pt_regs, r16));
+ DEFINE(VMM_PT_REGS_R17_OFFSET,
+ offsetof(struct kvm_pt_regs, r17));
+ DEFINE(VMM_PT_REGS_R18_OFFSET,
+ offsetof(struct kvm_pt_regs, r18));
+ DEFINE(VMM_PT_REGS_R19_OFFSET,
+ offsetof(struct kvm_pt_regs, r19));
+ DEFINE(VMM_PT_REGS_R20_OFFSET,
+ offsetof(struct kvm_pt_regs, r20));
+ DEFINE(VMM_PT_REGS_R21_OFFSET,
+ offsetof(struct kvm_pt_regs, r21));
+ DEFINE(VMM_PT_REGS_R22_OFFSET,
+ offsetof(struct kvm_pt_regs, r22));
+ DEFINE(VMM_PT_REGS_R23_OFFSET,
+ offsetof(struct kvm_pt_regs, r23));
+ DEFINE(VMM_PT_REGS_R24_OFFSET,
+ offsetof(struct kvm_pt_regs, r24));
+ DEFINE(VMM_PT_REGS_R25_OFFSET,
+ offsetof(struct kvm_pt_regs, r25));
+ DEFINE(VMM_PT_REGS_R26_OFFSET,
+ offsetof(struct kvm_pt_regs, r26));
+ DEFINE(VMM_PT_REGS_R27_OFFSET,
+ offsetof(struct kvm_pt_regs, r27));
+ DEFINE(VMM_PT_REGS_R28_OFFSET,
+ offsetof(struct kvm_pt_regs, r28));
+ DEFINE(VMM_PT_REGS_R29_OFFSET,
+ offsetof(struct kvm_pt_regs, r29));
+ DEFINE(VMM_PT_REGS_R30_OFFSET,
+ offsetof(struct kvm_pt_regs, r30));
+ DEFINE(VMM_PT_REGS_R31_OFFSET,
+ offsetof(struct kvm_pt_regs, r31));
+ DEFINE(VMM_PT_REGS_AR_CCV_OFFSET,
+ offsetof(struct kvm_pt_regs, ar_ccv));
+ DEFINE(VMM_PT_REGS_F6_OFFSET,
+ offsetof(struct kvm_pt_regs, f6));
+ DEFINE(VMM_PT_REGS_F7_OFFSET,
+ offsetof(struct kvm_pt_regs, f7));
+ DEFINE(VMM_PT_REGS_F8_OFFSET,
+ offsetof(struct kvm_pt_regs, f8));
+ DEFINE(VMM_PT_REGS_F9_OFFSET,
+ offsetof(struct kvm_pt_regs, f9));
+ DEFINE(VMM_PT_REGS_F10_OFFSET,
+ offsetof(struct kvm_pt_regs, f10));
+ DEFINE(VMM_PT_REGS_F11_OFFSET,
+ offsetof(struct kvm_pt_regs, f11));
+ DEFINE(VMM_PT_REGS_R4_OFFSET,
+ offsetof(struct kvm_pt_regs, r4));
+ DEFINE(VMM_PT_REGS_R5_OFFSET,
+ offsetof(struct kvm_pt_regs, r5));
+ DEFINE(VMM_PT_REGS_R6_OFFSET,
+ offsetof(struct kvm_pt_regs, r6));
+ DEFINE(VMM_PT_REGS_R7_OFFSET,
+ offsetof(struct kvm_pt_regs, r7));
+ DEFINE(VMM_PT_REGS_EML_UNAT_OFFSET,
+ offsetof(struct kvm_pt_regs, eml_unat));
+ DEFINE(VMM_VCPU_IIPA_OFFSET,
+ offsetof(struct kvm_vcpu, arch.cr_iipa));
+ DEFINE(VMM_VCPU_OPCODE_OFFSET,
+ offsetof(struct kvm_vcpu, arch.opcode));
+ DEFINE(VMM_VCPU_CAUSE_OFFSET, offsetof(struct kvm_vcpu, arch.cause));
+ DEFINE(VMM_VCPU_ISR_OFFSET,
+ offsetof(struct kvm_vcpu, arch.cr_isr));
+ DEFINE(VMM_PT_REGS_R16_SLOT,
+ (((offsetof(struct kvm_pt_regs, r16)
+ - sizeof(struct kvm_pt_regs)) >> 3) & 0x3f));
+ DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET,
+ offsetof(struct kvm_vcpu, arch.mode_flags));
+ DEFINE(VMM_VCPU_GP_OFFSET, offsetof(struct kvm_vcpu, arch.__gp));
+ BLANK();
+
+ DEFINE(VMM_VPD_BASE_OFFSET, offsetof(struct kvm_vcpu, arch.vpd));
+ DEFINE(VMM_VPD_VIFS_OFFSET, offsetof(struct vpd, ifs));
+ DEFINE(VMM_VLSAPIC_INSVC_BASE_OFFSET,
+ offsetof(struct kvm_vcpu, arch.insvc[0]));
+ DEFINE(VMM_VPD_VPTA_OFFSET, offsetof(struct vpd, pta));
+ DEFINE(VMM_VPD_VPSR_OFFSET, offsetof(struct vpd, vpsr));
+
+ DEFINE(VMM_CTX_R4_OFFSET, offsetof(union context, gr[4]));
+ DEFINE(VMM_CTX_R5_OFFSET, offsetof(union context, gr[5]));
+ DEFINE(VMM_CTX_R12_OFFSET, offsetof(union context, gr[12]));
+ DEFINE(VMM_CTX_R13_OFFSET, offsetof(union context, gr[13]));
+ DEFINE(VMM_CTX_KR0_OFFSET, offsetof(union context, ar[0]));
+ DEFINE(VMM_CTX_KR1_OFFSET, offsetof(union context, ar[1]));
+ DEFINE(VMM_CTX_B0_OFFSET, offsetof(union context, br[0]));
+ DEFINE(VMM_CTX_B1_OFFSET, offsetof(union context, br[1]));
+ DEFINE(VMM_CTX_B2_OFFSET, offsetof(union context, br[2]));
+ DEFINE(VMM_CTX_RR0_OFFSET, offsetof(union context, rr[0]));
+ DEFINE(VMM_CTX_RSC_OFFSET, offsetof(union context, ar[16]));
+ DEFINE(VMM_CTX_BSPSTORE_OFFSET, offsetof(union context, ar[18]));
+ DEFINE(VMM_CTX_RNAT_OFFSET, offsetof(union context, ar[19]));
+ DEFINE(VMM_CTX_FCR_OFFSET, offsetof(union context, ar[21]));
+ DEFINE(VMM_CTX_EFLAG_OFFSET, offsetof(union context, ar[24]));
+ DEFINE(VMM_CTX_CFLG_OFFSET, offsetof(union context, ar[27]));
+ DEFINE(VMM_CTX_FSR_OFFSET, offsetof(union context, ar[28]));
+ DEFINE(VMM_CTX_FIR_OFFSET, offsetof(union context, ar[29]));
+ DEFINE(VMM_CTX_FDR_OFFSET, offsetof(union context, ar[30]));
+ DEFINE(VMM_CTX_UNAT_OFFSET, offsetof(union context, ar[36]));
+ DEFINE(VMM_CTX_FPSR_OFFSET, offsetof(union context, ar[40]));
+ DEFINE(VMM_CTX_PFS_OFFSET, offsetof(union context, ar[64]));
+ DEFINE(VMM_CTX_LC_OFFSET, offsetof(union context, ar[65]));
+ DEFINE(VMM_CTX_DCR_OFFSET, offsetof(union context, cr[0]));
+ DEFINE(VMM_CTX_IVA_OFFSET, offsetof(union context, cr[2]));
+ DEFINE(VMM_CTX_PTA_OFFSET, offsetof(union context, cr[8]));
+ DEFINE(VMM_CTX_IBR0_OFFSET, offsetof(union context, ibr[0]));
+ DEFINE(VMM_CTX_DBR0_OFFSET, offsetof(union context, dbr[0]));
+ DEFINE(VMM_CTX_F2_OFFSET, offsetof(union context, fr[2]));
+ DEFINE(VMM_CTX_F3_OFFSET, offsetof(union context, fr[3]));
+ DEFINE(VMM_CTX_F32_OFFSET, offsetof(union context, fr[32]));
+ DEFINE(VMM_CTX_F33_OFFSET, offsetof(union context, fr[33]));
+ DEFINE(VMM_CTX_PKR0_OFFSET, offsetof(union context, pkr[0]));
+ DEFINE(VMM_CTX_PSR_OFFSET, offsetof(union context, psr));
+ BLANK();
+}
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
new file mode 100644
index 000000000000..6df073240135
--- /dev/null
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -0,0 +1,1806 @@
+
+/*
+ * kvm_ia64.c: Basic KVM suppport On Itanium series processors
+ *
+ *
+ * Copyright (C) 2007, Intel Corporation.
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/gfp.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/bitops.h>
+#include <linux/hrtimer.h>
+#include <linux/uaccess.h>
+
+#include <asm/pgtable.h>
+#include <asm/gcc_intrin.h>
+#include <asm/pal.h>
+#include <asm/cacheflush.h>
+#include <asm/div64.h>
+#include <asm/tlb.h>
+
+#include "misc.h"
+#include "vti.h"
+#include "iodev.h"
+#include "ioapic.h"
+#include "lapic.h"
+
+static unsigned long kvm_vmm_base;
+static unsigned long kvm_vsa_base;
+static unsigned long kvm_vm_buffer;
+static unsigned long kvm_vm_buffer_size;
+unsigned long kvm_vmm_gp;
+
+static long vp_env_info;
+
+static struct kvm_vmm_info *kvm_vmm_info;
+
+static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu);
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+ { NULL }
+};
+
+
+struct fdesc{
+ unsigned long ip;
+ unsigned long gp;
+};
+
+static void kvm_flush_icache(unsigned long start, unsigned long len)
+{
+ int l;
+
+ for (l = 0; l < (len + 32); l += 32)
+ ia64_fc(start + l);
+
+ ia64_sync_i();
+ ia64_srlz_i();
+}
+
+static void kvm_flush_tlb_all(void)
+{
+ unsigned long i, j, count0, count1, stride0, stride1, addr;
+ long flags;
+
+ addr = local_cpu_data->ptce_base;
+ count0 = local_cpu_data->ptce_count[0];
+ count1 = local_cpu_data->ptce_count[1];
+ stride0 = local_cpu_data->ptce_stride[0];
+ stride1 = local_cpu_data->ptce_stride[1];
+
+ local_irq_save(flags);
+ for (i = 0; i < count0; ++i) {
+ for (j = 0; j < count1; ++j) {
+ ia64_ptce(addr);
+ addr += stride1;
+ }
+ addr += stride0;
+ }
+ local_irq_restore(flags);
+ ia64_srlz_i(); /* srlz.i implies srlz.d */
+}
+
+long ia64_pal_vp_create(u64 *vpd, u64 *host_iva, u64 *opt_handler)
+{
+ struct ia64_pal_retval iprv;
+
+ PAL_CALL_STK(iprv, PAL_VP_CREATE, (u64)vpd, (u64)host_iva,
+ (u64)opt_handler);
+
+ return iprv.status;
+}
+
+static DEFINE_SPINLOCK(vp_lock);
+
+void kvm_arch_hardware_enable(void *garbage)
+{
+ long status;
+ long tmp_base;
+ unsigned long pte;
+ unsigned long saved_psr;
+ int slot;
+
+ pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base),
+ PAGE_KERNEL));
+ local_irq_save(saved_psr);
+ slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
+ if (slot < 0)
+ return;
+ local_irq_restore(saved_psr);
+
+ spin_lock(&vp_lock);
+ status = ia64_pal_vp_init_env(kvm_vsa_base ?
+ VP_INIT_ENV : VP_INIT_ENV_INITALIZE,
+ __pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base);
+ if (status != 0) {
+ printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n");
+ return ;
+ }
+
+ if (!kvm_vsa_base) {
+ kvm_vsa_base = tmp_base;
+ printk(KERN_INFO"kvm: kvm_vsa_base:0x%lx\n", kvm_vsa_base);
+ }
+ spin_unlock(&vp_lock);
+ ia64_ptr_entry(0x3, slot);
+}
+
+void kvm_arch_hardware_disable(void *garbage)
+{
+
+ long status;
+ int slot;
+ unsigned long pte;
+ unsigned long saved_psr;
+ unsigned long host_iva = ia64_getreg(_IA64_REG_CR_IVA);
+
+ pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base),
+ PAGE_KERNEL));
+
+ local_irq_save(saved_psr);
+ slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
+ if (slot < 0)
+ return;
+ local_irq_restore(saved_psr);
+
+ status = ia64_pal_vp_exit_env(host_iva);
+ if (status)
+ printk(KERN_DEBUG"kvm: Failed to disable VT support! :%ld\n",
+ status);
+ ia64_ptr_entry(0x3, slot);
+}
+
+void kvm_arch_check_processor_compat(void *rtn)
+{
+ *(int *)rtn = 0;
+}
+
+int kvm_dev_ioctl_check_extension(long ext)
+{
+
+ int r;
+
+ switch (ext) {
+ case KVM_CAP_IRQCHIP:
+ case KVM_CAP_USER_MEMORY:
+
+ r = 1;
+ break;
+ default:
+ r = 0;
+ }
+ return r;
+
+}
+
+static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ struct kvm_io_device *dev;
+
+ dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+
+ return dev;
+}
+
+static int handle_vm_error(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ kvm_run->hw.hardware_exit_reason = 1;
+ return 0;
+}
+
+static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct kvm_mmio_req *p;
+ struct kvm_io_device *mmio_dev;
+
+ p = kvm_get_vcpu_ioreq(vcpu);
+
+ if ((p->addr & PAGE_MASK) == IOAPIC_DEFAULT_BASE_ADDRESS)
+ goto mmio;
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_phys_addr = kvm_run->mmio.phys_addr = p->addr;
+ vcpu->mmio_size = kvm_run->mmio.len = p->size;
+ vcpu->mmio_is_write = kvm_run->mmio.is_write = !p->dir;
+
+ if (vcpu->mmio_is_write)
+ memcpy(vcpu->mmio_data, &p->data, p->size);
+ memcpy(kvm_run->mmio.data, &p->data, p->size);
+ kvm_run->exit_reason = KVM_EXIT_MMIO;
+ return 0;
+mmio:
+ mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr);
+ if (mmio_dev) {
+ if (!p->dir)
+ kvm_iodevice_write(mmio_dev, p->addr, p->size,
+ &p->data);
+ else
+ kvm_iodevice_read(mmio_dev, p->addr, p->size,
+ &p->data);
+
+ } else
+ printk(KERN_ERR"kvm: No iodevice found! addr:%lx\n", p->addr);
+ p->state = STATE_IORESP_READY;
+
+ return 1;
+}
+
+static int handle_pal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct exit_ctl_data *p;
+
+ p = kvm_get_exit_data(vcpu);
+
+ if (p->exit_reason == EXIT_REASON_PAL_CALL)
+ return kvm_pal_emul(vcpu, kvm_run);
+ else {
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ kvm_run->hw.hardware_exit_reason = 2;
+ return 0;
+ }
+}
+
+static int handle_sal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct exit_ctl_data *p;
+
+ p = kvm_get_exit_data(vcpu);
+
+ if (p->exit_reason == EXIT_REASON_SAL_CALL) {
+ kvm_sal_emul(vcpu);
+ return 1;
+ } else {
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ kvm_run->hw.hardware_exit_reason = 3;
+ return 0;
+ }
+
+}
+
+/*
+ * offset: address offset to IPI space.
+ * value: deliver value.
+ */
+static void vcpu_deliver_ipi(struct kvm_vcpu *vcpu, uint64_t dm,
+ uint64_t vector)
+{
+ switch (dm) {
+ case SAPIC_FIXED:
+ kvm_apic_set_irq(vcpu, vector, 0);
+ break;
+ case SAPIC_NMI:
+ kvm_apic_set_irq(vcpu, 2, 0);
+ break;
+ case SAPIC_EXTINT:
+ kvm_apic_set_irq(vcpu, 0, 0);
+ break;
+ case SAPIC_INIT:
+ case SAPIC_PMI:
+ default:
+ printk(KERN_ERR"kvm: Unimplemented Deliver reserved IPI!\n");
+ break;
+ }
+}
+
+static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id,
+ unsigned long eid)
+{
+ union ia64_lid lid;
+ int i;
+
+ for (i = 0; i < KVM_MAX_VCPUS; i++) {
+ if (kvm->vcpus[i]) {
+ lid.val = VCPU_LID(kvm->vcpus[i]);
+ if (lid.id == id && lid.eid == eid)
+ return kvm->vcpus[i];
+ }
+ }
+
+ return NULL;
+}
+
+static int handle_ipi(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct exit_ctl_data *p = kvm_get_exit_data(vcpu);
+ struct kvm_vcpu *target_vcpu;
+ struct kvm_pt_regs *regs;
+ union ia64_ipi_a addr = p->u.ipi_data.addr;
+ union ia64_ipi_d data = p->u.ipi_data.data;
+
+ target_vcpu = lid_to_vcpu(vcpu->kvm, addr.id, addr.eid);
+ if (!target_vcpu)
+ return handle_vm_error(vcpu, kvm_run);
+
+ if (!target_vcpu->arch.launched) {
+ regs = vcpu_regs(target_vcpu);
+
+ regs->cr_iip = vcpu->kvm->arch.rdv_sal_data.boot_ip;
+ regs->r1 = vcpu->kvm->arch.rdv_sal_data.boot_gp;
+
+ target_vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+ if (waitqueue_active(&target_vcpu->wq))
+ wake_up_interruptible(&target_vcpu->wq);
+ } else {
+ vcpu_deliver_ipi(target_vcpu, data.dm, data.vector);
+ if (target_vcpu != vcpu)
+ kvm_vcpu_kick(target_vcpu);
+ }
+
+ return 1;
+}
+
+struct call_data {
+ struct kvm_ptc_g ptc_g_data;
+ struct kvm_vcpu *vcpu;
+};
+
+static void vcpu_global_purge(void *info)
+{
+ struct call_data *p = (struct call_data *)info;
+ struct kvm_vcpu *vcpu = p->vcpu;
+
+ if (test_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
+ return;
+
+ set_bit(KVM_REQ_PTC_G, &vcpu->requests);
+ if (vcpu->arch.ptc_g_count < MAX_PTC_G_NUM) {
+ vcpu->arch.ptc_g_data[vcpu->arch.ptc_g_count++] =
+ p->ptc_g_data;
+ } else {
+ clear_bit(KVM_REQ_PTC_G, &vcpu->requests);
+ vcpu->arch.ptc_g_count = 0;
+ set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests);
+ }
+}
+
+static int handle_global_purge(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct exit_ctl_data *p = kvm_get_exit_data(vcpu);
+ struct kvm *kvm = vcpu->kvm;
+ struct call_data call_data;
+ int i;
+ call_data.ptc_g_data = p->u.ptc_g_data;
+
+ for (i = 0; i < KVM_MAX_VCPUS; i++) {
+ if (!kvm->vcpus[i] || kvm->vcpus[i]->arch.mp_state ==
+ KVM_MP_STATE_UNINITIALIZED ||
+ vcpu == kvm->vcpus[i])
+ continue;
+
+ if (waitqueue_active(&kvm->vcpus[i]->wq))
+ wake_up_interruptible(&kvm->vcpus[i]->wq);
+
+ if (kvm->vcpus[i]->cpu != -1) {
+ call_data.vcpu = kvm->vcpus[i];
+ smp_call_function_single(kvm->vcpus[i]->cpu,
+ vcpu_global_purge, &call_data, 0, 1);
+ } else
+ printk(KERN_WARNING"kvm: Uninit vcpu received ipi!\n");
+
+ }
+ return 1;
+}
+
+static int handle_switch_rr6(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ return 1;
+}
+
+int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+{
+
+ ktime_t kt;
+ long itc_diff;
+ unsigned long vcpu_now_itc;
+
+ unsigned long expires;
+ struct hrtimer *p_ht = &vcpu->arch.hlt_timer;
+ unsigned long cyc_per_usec = local_cpu_data->cyc_per_usec;
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+
+ vcpu_now_itc = ia64_getreg(_IA64_REG_AR_ITC) + vcpu->arch.itc_offset;
+
+ if (time_after(vcpu_now_itc, vpd->itm)) {
+ vcpu->arch.timer_check = 1;
+ return 1;
+ }
+ itc_diff = vpd->itm - vcpu_now_itc;
+ if (itc_diff < 0)
+ itc_diff = -itc_diff;
+
+ expires = div64_64(itc_diff, cyc_per_usec);
+ kt = ktime_set(0, 1000 * expires);
+ vcpu->arch.ht_active = 1;
+ hrtimer_start(p_ht, kt, HRTIMER_MODE_ABS);
+
+ if (irqchip_in_kernel(vcpu->kvm)) {
+ vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
+ kvm_vcpu_block(vcpu);
+ hrtimer_cancel(p_ht);
+ vcpu->arch.ht_active = 0;
+
+ if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE)
+ return -EINTR;
+ return 1;
+ } else {
+ printk(KERN_ERR"kvm: Unsupported userspace halt!");
+ return 0;
+ }
+}
+
+static int handle_vm_shutdown(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ return 0;
+}
+
+static int handle_external_interrupt(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ return 1;
+}
+
+static int (*kvm_vti_exit_handlers[])(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run) = {
+ [EXIT_REASON_VM_PANIC] = handle_vm_error,
+ [EXIT_REASON_MMIO_INSTRUCTION] = handle_mmio,
+ [EXIT_REASON_PAL_CALL] = handle_pal_call,
+ [EXIT_REASON_SAL_CALL] = handle_sal_call,
+ [EXIT_REASON_SWITCH_RR6] = handle_switch_rr6,
+ [EXIT_REASON_VM_DESTROY] = handle_vm_shutdown,
+ [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt,
+ [EXIT_REASON_IPI] = handle_ipi,
+ [EXIT_REASON_PTC_G] = handle_global_purge,
+
+};
+
+static const int kvm_vti_max_exit_handlers =
+ sizeof(kvm_vti_exit_handlers)/sizeof(*kvm_vti_exit_handlers);
+
+static void kvm_prepare_guest_switch(struct kvm_vcpu *vcpu)
+{
+}
+
+static uint32_t kvm_get_exit_reason(struct kvm_vcpu *vcpu)
+{
+ struct exit_ctl_data *p_exit_data;
+
+ p_exit_data = kvm_get_exit_data(vcpu);
+ return p_exit_data->exit_reason;
+}
+
+/*
+ * The guest has exited. See if we can fix it or if we need userspace
+ * assistance.
+ */
+static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+{
+ u32 exit_reason = kvm_get_exit_reason(vcpu);
+ vcpu->arch.last_exit = exit_reason;
+
+ if (exit_reason < kvm_vti_max_exit_handlers
+ && kvm_vti_exit_handlers[exit_reason])
+ return kvm_vti_exit_handlers[exit_reason](vcpu, kvm_run);
+ else {
+ kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+ kvm_run->hw.hardware_exit_reason = exit_reason;
+ }
+ return 0;
+}
+
+static inline void vti_set_rr6(unsigned long rr6)
+{
+ ia64_set_rr(RR6, rr6);
+ ia64_srlz_i();
+}
+
+static int kvm_insert_vmm_mapping(struct kvm_vcpu *vcpu)
+{
+ unsigned long pte;
+ struct kvm *kvm = vcpu->kvm;
+ int r;
+
+ /*Insert a pair of tr to map vmm*/
+ pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base), PAGE_KERNEL));
+ r = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
+ if (r < 0)
+ goto out;
+ vcpu->arch.vmm_tr_slot = r;
+ /*Insert a pairt of tr to map data of vm*/
+ pte = pte_val(mk_pte_phys(__pa(kvm->arch.vm_base), PAGE_KERNEL));
+ r = ia64_itr_entry(0x3, KVM_VM_DATA_BASE,
+ pte, KVM_VM_DATA_SHIFT);
+ if (r < 0)
+ goto out;
+ vcpu->arch.vm_tr_slot = r;
+ r = 0;
+out:
+ return r;
+
+}
+
+static void kvm_purge_vmm_mapping(struct kvm_vcpu *vcpu)
+{
+
+ ia64_ptr_entry(0x3, vcpu->arch.vmm_tr_slot);
+ ia64_ptr_entry(0x3, vcpu->arch.vm_tr_slot);
+
+}
+
+static int kvm_vcpu_pre_transition(struct kvm_vcpu *vcpu)
+{
+ int cpu = smp_processor_id();
+
+ if (vcpu->arch.last_run_cpu != cpu ||
+ per_cpu(last_vcpu, cpu) != vcpu) {
+ per_cpu(last_vcpu, cpu) = vcpu;
+ vcpu->arch.last_run_cpu = cpu;
+ kvm_flush_tlb_all();
+ }
+
+ vcpu->arch.host_rr6 = ia64_get_rr(RR6);
+ vti_set_rr6(vcpu->arch.vmm_rr);
+ return kvm_insert_vmm_mapping(vcpu);
+}
+static void kvm_vcpu_post_transition(struct kvm_vcpu *vcpu)
+{
+ kvm_purge_vmm_mapping(vcpu);
+ vti_set_rr6(vcpu->arch.host_rr6);
+}
+
+static int vti_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ union context *host_ctx, *guest_ctx;
+ int r;
+
+ /*Get host and guest context with guest address space.*/
+ host_ctx = kvm_get_host_context(vcpu);
+ guest_ctx = kvm_get_guest_context(vcpu);
+
+ r = kvm_vcpu_pre_transition(vcpu);
+ if (r < 0)
+ goto out;
+ kvm_vmm_info->tramp_entry(host_ctx, guest_ctx);
+ kvm_vcpu_post_transition(vcpu);
+ r = 0;
+out:
+ return r;
+}
+
+static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ int r;
+
+again:
+ preempt_disable();
+
+ kvm_prepare_guest_switch(vcpu);
+ local_irq_disable();
+
+ if (signal_pending(current)) {
+ local_irq_enable();
+ preempt_enable();
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ goto out;
+ }
+
+ vcpu->guest_mode = 1;
+ kvm_guest_enter();
+
+ r = vti_vcpu_run(vcpu, kvm_run);
+ if (r < 0) {
+ local_irq_enable();
+ preempt_enable();
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ goto out;
+ }
+
+ vcpu->arch.launched = 1;
+ vcpu->guest_mode = 0;
+ local_irq_enable();
+
+ /*
+ * We must have an instruction between local_irq_enable() and
+ * kvm_guest_exit(), so the timer interrupt isn't delayed by
+ * the interrupt shadow. The stat.exits increment will do nicely.
+ * But we need to prevent reordering, hence this barrier():
+ */
+ barrier();
+
+ kvm_guest_exit();
+
+ preempt_enable();
+
+ r = kvm_handle_exit(kvm_run, vcpu);
+
+ if (r > 0) {
+ if (!need_resched())
+ goto again;
+ }
+
+out:
+ if (r > 0) {
+ kvm_resched(vcpu);
+ goto again;
+ }
+
+ return r;
+}
+
+static void kvm_set_mmio_data(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmio_req *p = kvm_get_vcpu_ioreq(vcpu);
+
+ if (!vcpu->mmio_is_write)
+ memcpy(&p->data, vcpu->mmio_data, 8);
+ p->state = STATE_IORESP_READY;
+}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ int r;
+ sigset_t sigsaved;
+
+ vcpu_load(vcpu);
+
+ if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
+ kvm_vcpu_block(vcpu);
+ vcpu_put(vcpu);
+ return -EAGAIN;
+ }
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
+ if (vcpu->mmio_needed) {
+ memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
+ kvm_set_mmio_data(vcpu);
+ vcpu->mmio_read_completed = 1;
+ vcpu->mmio_needed = 0;
+ }
+ r = __vcpu_run(vcpu, kvm_run);
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+ vcpu_put(vcpu);
+ return r;
+}
+
+/*
+ * Allocate 16M memory for every vm to hold its specific data.
+ * Its memory map is defined in kvm_host.h.
+ */
+static struct kvm *kvm_alloc_kvm(void)
+{
+
+ struct kvm *kvm;
+ uint64_t vm_base;
+
+ vm_base = __get_free_pages(GFP_KERNEL, get_order(KVM_VM_DATA_SIZE));
+
+ if (!vm_base)
+ return ERR_PTR(-ENOMEM);
+ printk(KERN_DEBUG"kvm: VM data's base Address:0x%lx\n", vm_base);
+
+ /* Zero all pages before use! */
+ memset((void *)vm_base, 0, KVM_VM_DATA_SIZE);
+
+ kvm = (struct kvm *)(vm_base + KVM_VM_OFS);
+ kvm->arch.vm_base = vm_base;
+
+ return kvm;
+}
+
+struct kvm_io_range {
+ unsigned long start;
+ unsigned long size;
+ unsigned long type;
+};
+
+static const struct kvm_io_range io_ranges[] = {
+ {VGA_IO_START, VGA_IO_SIZE, GPFN_FRAME_BUFFER},
+ {MMIO_START, MMIO_SIZE, GPFN_LOW_MMIO},
+ {LEGACY_IO_START, LEGACY_IO_SIZE, GPFN_LEGACY_IO},
+ {IO_SAPIC_START, IO_SAPIC_SIZE, GPFN_IOSAPIC},
+ {PIB_START, PIB_SIZE, GPFN_PIB},
+};
+
+static void kvm_build_io_pmt(struct kvm *kvm)
+{
+ unsigned long i, j;
+
+ /* Mark I/O ranges */
+ for (i = 0; i < (sizeof(io_ranges) / sizeof(struct kvm_io_range));
+ i++) {
+ for (j = io_ranges[i].start;
+ j < io_ranges[i].start + io_ranges[i].size;
+ j += PAGE_SIZE)
+ kvm_set_pmt_entry(kvm, j >> PAGE_SHIFT,
+ io_ranges[i].type, 0);
+ }
+
+}
+
+/*Use unused rids to virtualize guest rid.*/
+#define GUEST_PHYSICAL_RR0 0x1739
+#define GUEST_PHYSICAL_RR4 0x2739
+#define VMM_INIT_RR 0x1660
+
+static void kvm_init_vm(struct kvm *kvm)
+{
+ long vm_base;
+
+ BUG_ON(!kvm);
+
+ kvm->arch.metaphysical_rr0 = GUEST_PHYSICAL_RR0;
+ kvm->arch.metaphysical_rr4 = GUEST_PHYSICAL_RR4;
+ kvm->arch.vmm_init_rr = VMM_INIT_RR;
+
+ vm_base = kvm->arch.vm_base;
+ if (vm_base) {
+ kvm->arch.vhpt_base = vm_base + KVM_VHPT_OFS;
+ kvm->arch.vtlb_base = vm_base + KVM_VTLB_OFS;
+ kvm->arch.vpd_base = vm_base + KVM_VPD_OFS;
+ }
+
+ /*
+ *Fill P2M entries for MMIO/IO ranges
+ */
+ kvm_build_io_pmt(kvm);
+
+}
+
+struct kvm *kvm_arch_create_vm(void)
+{
+ struct kvm *kvm = kvm_alloc_kvm();
+
+ if (IS_ERR(kvm))
+ return ERR_PTR(-ENOMEM);
+ kvm_init_vm(kvm);
+
+ return kvm;
+
+}
+
+static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm,
+ struct kvm_irqchip *chip)
+{
+ int r;
+
+ r = 0;
+ switch (chip->chip_id) {
+ case KVM_IRQCHIP_IOAPIC:
+ memcpy(&chip->chip.ioapic, ioapic_irqchip(kvm),
+ sizeof(struct kvm_ioapic_state));
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
+static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+ int r;
+
+ r = 0;
+ switch (chip->chip_id) {
+ case KVM_IRQCHIP_IOAPIC:
+ memcpy(ioapic_irqchip(kvm),
+ &chip->chip.ioapic,
+ sizeof(struct kvm_ioapic_state));
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
+#define RESTORE_REGS(_x) vcpu->arch._x = regs->_x
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ int i;
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+ int r;
+
+ vcpu_load(vcpu);
+
+ for (i = 0; i < 16; i++) {
+ vpd->vgr[i] = regs->vpd.vgr[i];
+ vpd->vbgr[i] = regs->vpd.vbgr[i];
+ }
+ for (i = 0; i < 128; i++)
+ vpd->vcr[i] = regs->vpd.vcr[i];
+ vpd->vhpi = regs->vpd.vhpi;
+ vpd->vnat = regs->vpd.vnat;
+ vpd->vbnat = regs->vpd.vbnat;
+ vpd->vpsr = regs->vpd.vpsr;
+
+ vpd->vpr = regs->vpd.vpr;
+
+ r = -EFAULT;
+ r = copy_from_user(&vcpu->arch.guest, regs->saved_guest,
+ sizeof(union context));
+ if (r)
+ goto out;
+ r = copy_from_user(vcpu + 1, regs->saved_stack +
+ sizeof(struct kvm_vcpu),
+ IA64_STK_OFFSET - sizeof(struct kvm_vcpu));
+ if (r)
+ goto out;
+ vcpu->arch.exit_data =
+ ((struct kvm_vcpu *)(regs->saved_stack))->arch.exit_data;
+
+ RESTORE_REGS(mp_state);
+ RESTORE_REGS(vmm_rr);
+ memcpy(vcpu->arch.itrs, regs->itrs, sizeof(struct thash_data) * NITRS);
+ memcpy(vcpu->arch.dtrs, regs->dtrs, sizeof(struct thash_data) * NDTRS);
+ RESTORE_REGS(itr_regions);
+ RESTORE_REGS(dtr_regions);
+ RESTORE_REGS(tc_regions);
+ RESTORE_REGS(irq_check);
+ RESTORE_REGS(itc_check);
+ RESTORE_REGS(timer_check);
+ RESTORE_REGS(timer_pending);
+ RESTORE_REGS(last_itc);
+ for (i = 0; i < 8; i++) {
+ vcpu->arch.vrr[i] = regs->vrr[i];
+ vcpu->arch.ibr[i] = regs->ibr[i];
+ vcpu->arch.dbr[i] = regs->dbr[i];
+ }
+ for (i = 0; i < 4; i++)
+ vcpu->arch.insvc[i] = regs->insvc[i];
+ RESTORE_REGS(xtp);
+ RESTORE_REGS(metaphysical_rr0);
+ RESTORE_REGS(metaphysical_rr4);
+ RESTORE_REGS(metaphysical_saved_rr0);
+ RESTORE_REGS(metaphysical_saved_rr4);
+ RESTORE_REGS(fp_psr);
+ RESTORE_REGS(saved_gp);
+
+ vcpu->arch.irq_new_pending = 1;
+ vcpu->arch.itc_offset = regs->saved_itc - ia64_getreg(_IA64_REG_AR_ITC);
+ set_bit(KVM_REQ_RESUME, &vcpu->requests);
+
+ vcpu_put(vcpu);
+ r = 0;
+out:
+ return r;
+}
+
+long kvm_arch_vm_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ int r = -EINVAL;
+
+ switch (ioctl) {
+ case KVM_SET_MEMORY_REGION: {
+ struct kvm_memory_region kvm_mem;
+ struct kvm_userspace_memory_region kvm_userspace_mem;
+
+ r = -EFAULT;
+ if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
+ goto out;
+ kvm_userspace_mem.slot = kvm_mem.slot;
+ kvm_userspace_mem.flags = kvm_mem.flags;
+ kvm_userspace_mem.guest_phys_addr =
+ kvm_mem.guest_phys_addr;
+ kvm_userspace_mem.memory_size = kvm_mem.memory_size;
+ r = kvm_vm_ioctl_set_memory_region(kvm,
+ &kvm_userspace_mem, 0);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_CREATE_IRQCHIP:
+ r = -EFAULT;
+ r = kvm_ioapic_init(kvm);
+ if (r)
+ goto out;
+ break;
+ case KVM_IRQ_LINE: {
+ struct kvm_irq_level irq_event;
+
+ r = -EFAULT;
+ if (copy_from_user(&irq_event, argp, sizeof irq_event))
+ goto out;
+ if (irqchip_in_kernel(kvm)) {
+ mutex_lock(&kvm->lock);
+ kvm_ioapic_set_irq(kvm->arch.vioapic,
+ irq_event.irq,
+ irq_event.level);
+ mutex_unlock(&kvm->lock);
+ r = 0;
+ }
+ break;
+ }
+ case KVM_GET_IRQCHIP: {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_irqchip chip;
+
+ r = -EFAULT;
+ if (copy_from_user(&chip, argp, sizeof chip))
+ goto out;
+ r = -ENXIO;
+ if (!irqchip_in_kernel(kvm))
+ goto out;
+ r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &chip, sizeof chip))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_IRQCHIP: {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_irqchip chip;
+
+ r = -EFAULT;
+ if (copy_from_user(&chip, argp, sizeof chip))
+ goto out;
+ r = -ENXIO;
+ if (!irqchip_in_kernel(kvm))
+ goto out;
+ r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
+ default:
+ ;
+ }
+out:
+ return r;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+
+}
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+
+ return -EINVAL;
+}
+
+static int kvm_alloc_vmm_area(void)
+{
+ if (!kvm_vmm_base && (kvm_vm_buffer_size < KVM_VM_BUFFER_SIZE)) {
+ kvm_vmm_base = __get_free_pages(GFP_KERNEL,
+ get_order(KVM_VMM_SIZE));
+ if (!kvm_vmm_base)
+ return -ENOMEM;
+
+ memset((void *)kvm_vmm_base, 0, KVM_VMM_SIZE);
+ kvm_vm_buffer = kvm_vmm_base + VMM_SIZE;
+
+ printk(KERN_DEBUG"kvm:VMM's Base Addr:0x%lx, vm_buffer:0x%lx\n",
+ kvm_vmm_base, kvm_vm_buffer);
+ }
+
+ return 0;
+}
+
+static void kvm_free_vmm_area(void)
+{
+ if (kvm_vmm_base) {
+ /*Zero this area before free to avoid bits leak!!*/
+ memset((void *)kvm_vmm_base, 0, KVM_VMM_SIZE);
+ free_pages(kvm_vmm_base, get_order(KVM_VMM_SIZE));
+ kvm_vmm_base = 0;
+ kvm_vm_buffer = 0;
+ kvm_vsa_base = 0;
+ }
+}
+
+/*
+ * Make sure that a cpu that is being hot-unplugged does not have any vcpus
+ * cached on it. Leave it as blank for IA64.
+ */
+void decache_vcpus_on_cpu(int cpu)
+{
+}
+
+static void vti_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+}
+
+static int vti_init_vpd(struct kvm_vcpu *vcpu)
+{
+ int i;
+ union cpuid3_t cpuid3;
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+
+ if (IS_ERR(vpd))
+ return PTR_ERR(vpd);
+
+ /* CPUID init */
+ for (i = 0; i < 5; i++)
+ vpd->vcpuid[i] = ia64_get_cpuid(i);
+
+ /* Limit the CPUID number to 5 */
+ cpuid3.value = vpd->vcpuid[3];
+ cpuid3.number = 4; /* 5 - 1 */
+ vpd->vcpuid[3] = cpuid3.value;
+
+ /*Set vac and vdc fields*/
+ vpd->vac.a_from_int_cr = 1;
+ vpd->vac.a_to_int_cr = 1;
+ vpd->vac.a_from_psr = 1;
+ vpd->vac.a_from_cpuid = 1;
+ vpd->vac.a_cover = 1;
+ vpd->vac.a_bsw = 1;
+ vpd->vac.a_int = 1;
+ vpd->vdc.d_vmsw = 1;
+
+ /*Set virtual buffer*/
+ vpd->virt_env_vaddr = KVM_VM_BUFFER_BASE;
+
+ return 0;
+}
+
+static int vti_create_vp(struct kvm_vcpu *vcpu)
+{
+ long ret;
+ struct vpd *vpd = vcpu->arch.vpd;
+ unsigned long vmm_ivt;
+
+ vmm_ivt = kvm_vmm_info->vmm_ivt;
+
+ printk(KERN_DEBUG "kvm: vcpu:%p,ivt: 0x%lx\n", vcpu, vmm_ivt);
+
+ ret = ia64_pal_vp_create((u64 *)vpd, (u64 *)vmm_ivt, 0);
+
+ if (ret) {
+ printk(KERN_ERR"kvm: ia64_pal_vp_create failed!\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void init_ptce_info(struct kvm_vcpu *vcpu)
+{
+ ia64_ptce_info_t ptce = {0};
+
+ ia64_get_ptce(&ptce);
+ vcpu->arch.ptce_base = ptce.base;
+ vcpu->arch.ptce_count[0] = ptce.count[0];
+ vcpu->arch.ptce_count[1] = ptce.count[1];
+ vcpu->arch.ptce_stride[0] = ptce.stride[0];
+ vcpu->arch.ptce_stride[1] = ptce.stride[1];
+}
+
+static void kvm_migrate_hlt_timer(struct kvm_vcpu *vcpu)
+{
+ struct hrtimer *p_ht = &vcpu->arch.hlt_timer;
+
+ if (hrtimer_cancel(p_ht))
+ hrtimer_start(p_ht, p_ht->expires, HRTIMER_MODE_ABS);
+}
+
+static enum hrtimer_restart hlt_timer_fn(struct hrtimer *data)
+{
+ struct kvm_vcpu *vcpu;
+ wait_queue_head_t *q;
+
+ vcpu = container_of(data, struct kvm_vcpu, arch.hlt_timer);
+ if (vcpu->arch.mp_state != KVM_MP_STATE_HALTED)
+ goto out;
+
+ q = &vcpu->wq;
+ if (waitqueue_active(q)) {
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+ wake_up_interruptible(q);
+ }
+out:
+ vcpu->arch.timer_check = 1;
+ return HRTIMER_NORESTART;
+}
+
+#define PALE_RESET_ENTRY 0x80000000ffffffb0UL
+
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu *v;
+ int r;
+ int i;
+ long itc_offset;
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ union context *p_ctx = &vcpu->arch.guest;
+ struct kvm_vcpu *vmm_vcpu = to_guest(vcpu->kvm, vcpu);
+
+ /*Init vcpu context for first run.*/
+ if (IS_ERR(vmm_vcpu))
+ return PTR_ERR(vmm_vcpu);
+
+ if (vcpu->vcpu_id == 0) {
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+
+ /*Set entry address for first run.*/
+ regs->cr_iip = PALE_RESET_ENTRY;
+
+ /*Initilize itc offset for vcpus*/
+ itc_offset = 0UL - ia64_getreg(_IA64_REG_AR_ITC);
+ for (i = 0; i < MAX_VCPU_NUM; i++) {
+ v = (struct kvm_vcpu *)((char *)vcpu + VCPU_SIZE * i);
+ v->arch.itc_offset = itc_offset;
+ v->arch.last_itc = 0;
+ }
+ } else
+ vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
+
+ r = -ENOMEM;
+ vcpu->arch.apic = kzalloc(sizeof(struct kvm_lapic), GFP_KERNEL);
+ if (!vcpu->arch.apic)
+ goto out;
+ vcpu->arch.apic->vcpu = vcpu;
+
+ p_ctx->gr[1] = 0;
+ p_ctx->gr[12] = (unsigned long)((char *)vmm_vcpu + IA64_STK_OFFSET);
+ p_ctx->gr[13] = (unsigned long)vmm_vcpu;
+ p_ctx->psr = 0x1008522000UL;
+ p_ctx->ar[40] = FPSR_DEFAULT; /*fpsr*/
+ p_ctx->caller_unat = 0;
+ p_ctx->pr = 0x0;
+ p_ctx->ar[36] = 0x0; /*unat*/
+ p_ctx->ar[19] = 0x0; /*rnat*/
+ p_ctx->ar[18] = (unsigned long)vmm_vcpu +
+ ((sizeof(struct kvm_vcpu)+15) & ~15);
+ p_ctx->ar[64] = 0x0; /*pfs*/
+ p_ctx->cr[0] = 0x7e04UL;
+ p_ctx->cr[2] = (unsigned long)kvm_vmm_info->vmm_ivt;
+ p_ctx->cr[8] = 0x3c;
+
+ /*Initilize region register*/
+ p_ctx->rr[0] = 0x30;
+ p_ctx->rr[1] = 0x30;
+ p_ctx->rr[2] = 0x30;
+ p_ctx->rr[3] = 0x30;
+ p_ctx->rr[4] = 0x30;
+ p_ctx->rr[5] = 0x30;
+ p_ctx->rr[7] = 0x30;
+
+ /*Initilize branch register 0*/
+ p_ctx->br[0] = *(unsigned long *)kvm_vmm_info->vmm_entry;
+
+ vcpu->arch.vmm_rr = kvm->arch.vmm_init_rr;
+ vcpu->arch.metaphysical_rr0 = kvm->arch.metaphysical_rr0;
+ vcpu->arch.metaphysical_rr4 = kvm->arch.metaphysical_rr4;
+
+ hrtimer_init(&vcpu->arch.hlt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ vcpu->arch.hlt_timer.function = hlt_timer_fn;
+
+ vcpu->arch.last_run_cpu = -1;
+ vcpu->arch.vpd = (struct vpd *)VPD_ADDR(vcpu->vcpu_id);
+ vcpu->arch.vsa_base = kvm_vsa_base;
+ vcpu->arch.__gp = kvm_vmm_gp;
+ vcpu->arch.dirty_log_lock_pa = __pa(&kvm->arch.dirty_log_lock);
+ vcpu->arch.vhpt.hash = (struct thash_data *)VHPT_ADDR(vcpu->vcpu_id);
+ vcpu->arch.vtlb.hash = (struct thash_data *)VTLB_ADDR(vcpu->vcpu_id);
+ init_ptce_info(vcpu);
+
+ r = 0;
+out:
+ return r;
+}
+
+static int vti_vcpu_setup(struct kvm_vcpu *vcpu, int id)
+{
+ unsigned long psr;
+ int r;
+
+ local_irq_save(psr);
+ r = kvm_insert_vmm_mapping(vcpu);
+ if (r)
+ goto fail;
+ r = kvm_vcpu_init(vcpu, vcpu->kvm, id);
+ if (r)
+ goto fail;
+
+ r = vti_init_vpd(vcpu);
+ if (r) {
+ printk(KERN_DEBUG"kvm: vpd init error!!\n");
+ goto uninit;
+ }
+
+ r = vti_create_vp(vcpu);
+ if (r)
+ goto uninit;
+
+ kvm_purge_vmm_mapping(vcpu);
+ local_irq_restore(psr);
+
+ return 0;
+uninit:
+ kvm_vcpu_uninit(vcpu);
+fail:
+ return r;
+}
+
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
+ unsigned int id)
+{
+ struct kvm_vcpu *vcpu;
+ unsigned long vm_base = kvm->arch.vm_base;
+ int r;
+ int cpu;
+
+ r = -ENOMEM;
+ if (!vm_base) {
+ printk(KERN_ERR"kvm: Create vcpu[%d] error!\n", id);
+ goto fail;
+ }
+ vcpu = (struct kvm_vcpu *)(vm_base + KVM_VCPU_OFS + VCPU_SIZE * id);
+ vcpu->kvm = kvm;
+
+ cpu = get_cpu();
+ vti_vcpu_load(vcpu, cpu);
+ r = vti_vcpu_setup(vcpu, id);
+ put_cpu();
+
+ if (r) {
+ printk(KERN_DEBUG"kvm: vcpu_setup error!!\n");
+ goto fail;
+ }
+
+ return vcpu;
+fail:
+ return ERR_PTR(r);
+}
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
+ struct kvm_debug_guest *dbg)
+{
+ return -EINVAL;
+}
+
+static void free_kvm(struct kvm *kvm)
+{
+ unsigned long vm_base = kvm->arch.vm_base;
+
+ if (vm_base) {
+ memset((void *)vm_base, 0, KVM_VM_DATA_SIZE);
+ free_pages(vm_base, get_order(KVM_VM_DATA_SIZE));
+ }
+
+}
+
+static void kvm_release_vm_pages(struct kvm *kvm)
+{
+ struct kvm_memory_slot *memslot;
+ int i, j;
+ unsigned long base_gfn;
+
+ for (i = 0; i < kvm->nmemslots; i++) {
+ memslot = &kvm->memslots[i];
+ base_gfn = memslot->base_gfn;
+
+ for (j = 0; j < memslot->npages; j++) {
+ if (memslot->rmap[j])
+ put_page((struct page *)memslot->rmap[j]);
+ }
+ }
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ kfree(kvm->arch.vioapic);
+ kvm_release_vm_pages(kvm);
+ kvm_free_physmem(kvm);
+ free_kvm(kvm);
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+ if (cpu != vcpu->cpu) {
+ vcpu->cpu = cpu;
+ if (vcpu->arch.ht_active)
+ kvm_migrate_hlt_timer(vcpu);
+ }
+}
+
+#define SAVE_REGS(_x) regs->_x = vcpu->arch._x
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ int i;
+ int r;
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+ vcpu_load(vcpu);
+
+ for (i = 0; i < 16; i++) {
+ regs->vpd.vgr[i] = vpd->vgr[i];
+ regs->vpd.vbgr[i] = vpd->vbgr[i];
+ }
+ for (i = 0; i < 128; i++)
+ regs->vpd.vcr[i] = vpd->vcr[i];
+ regs->vpd.vhpi = vpd->vhpi;
+ regs->vpd.vnat = vpd->vnat;
+ regs->vpd.vbnat = vpd->vbnat;
+ regs->vpd.vpsr = vpd->vpsr;
+ regs->vpd.vpr = vpd->vpr;
+
+ r = -EFAULT;
+ r = copy_to_user(regs->saved_guest, &vcpu->arch.guest,
+ sizeof(union context));
+ if (r)
+ goto out;
+ r = copy_to_user(regs->saved_stack, (void *)vcpu, IA64_STK_OFFSET);
+ if (r)
+ goto out;
+ SAVE_REGS(mp_state);
+ SAVE_REGS(vmm_rr);
+ memcpy(regs->itrs, vcpu->arch.itrs, sizeof(struct thash_data) * NITRS);
+ memcpy(regs->dtrs, vcpu->arch.dtrs, sizeof(struct thash_data) * NDTRS);
+ SAVE_REGS(itr_regions);
+ SAVE_REGS(dtr_regions);
+ SAVE_REGS(tc_regions);
+ SAVE_REGS(irq_check);
+ SAVE_REGS(itc_check);
+ SAVE_REGS(timer_check);
+ SAVE_REGS(timer_pending);
+ SAVE_REGS(last_itc);
+ for (i = 0; i < 8; i++) {
+ regs->vrr[i] = vcpu->arch.vrr[i];
+ regs->ibr[i] = vcpu->arch.ibr[i];
+ regs->dbr[i] = vcpu->arch.dbr[i];
+ }
+ for (i = 0; i < 4; i++)
+ regs->insvc[i] = vcpu->arch.insvc[i];
+ regs->saved_itc = vcpu->arch.itc_offset + ia64_getreg(_IA64_REG_AR_ITC);
+ SAVE_REGS(xtp);
+ SAVE_REGS(metaphysical_rr0);
+ SAVE_REGS(metaphysical_rr4);
+ SAVE_REGS(metaphysical_saved_rr0);
+ SAVE_REGS(metaphysical_saved_rr4);
+ SAVE_REGS(fp_psr);
+ SAVE_REGS(saved_gp);
+ vcpu_put(vcpu);
+ r = 0;
+out:
+ return r;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+
+ hrtimer_cancel(&vcpu->arch.hlt_timer);
+ kfree(vcpu->arch.apic);
+}
+
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_set_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+ unsigned long i;
+ struct page *page;
+ int npages = mem->memory_size >> PAGE_SHIFT;
+ struct kvm_memory_slot *memslot = &kvm->memslots[mem->slot];
+ unsigned long base_gfn = memslot->base_gfn;
+
+ for (i = 0; i < npages; i++) {
+ page = gfn_to_page(kvm, base_gfn + i);
+ kvm_set_pmt_entry(kvm, base_gfn + i,
+ page_to_pfn(page) << PAGE_SHIFT,
+ _PAGE_AR_RWX|_PAGE_MA_WB);
+ memslot->rmap[i] = (unsigned long)page;
+ }
+
+ return 0;
+}
+
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ kvm_vcpu_uninit(vcpu);
+}
+
+static int vti_cpu_has_kvm_support(void)
+{
+ long avail = 1, status = 1, control = 1;
+ long ret;
+
+ ret = ia64_pal_proc_get_features(&avail, &status, &control, 0);
+ if (ret)
+ goto out;
+
+ if (!(avail & PAL_PROC_VM_BIT))
+ goto out;
+
+ printk(KERN_DEBUG"kvm: Hardware Supports VT\n");
+
+ ret = ia64_pal_vp_env_info(&kvm_vm_buffer_size, &vp_env_info);
+ if (ret)
+ goto out;
+ printk(KERN_DEBUG"kvm: VM Buffer Size:0x%lx\n", kvm_vm_buffer_size);
+
+ if (!(vp_env_info & VP_OPCODE)) {
+ printk(KERN_WARNING"kvm: No opcode ability on hardware, "
+ "vm_env_info:0x%lx\n", vp_env_info);
+ }
+
+ return 1;
+out:
+ return 0;
+}
+
+static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info,
+ struct module *module)
+{
+ unsigned long module_base;
+ unsigned long vmm_size;
+
+ unsigned long vmm_offset, func_offset, fdesc_offset;
+ struct fdesc *p_fdesc;
+
+ BUG_ON(!module);
+
+ if (!kvm_vmm_base) {
+ printk("kvm: kvm area hasn't been initilized yet!!\n");
+ return -EFAULT;
+ }
+
+ /*Calculate new position of relocated vmm module.*/
+ module_base = (unsigned long)module->module_core;
+ vmm_size = module->core_size;
+ if (unlikely(vmm_size > KVM_VMM_SIZE))
+ return -EFAULT;
+
+ memcpy((void *)kvm_vmm_base, (void *)module_base, vmm_size);
+ kvm_flush_icache(kvm_vmm_base, vmm_size);
+
+ /*Recalculate kvm_vmm_info based on new VMM*/
+ vmm_offset = vmm_info->vmm_ivt - module_base;
+ kvm_vmm_info->vmm_ivt = KVM_VMM_BASE + vmm_offset;
+ printk(KERN_DEBUG"kvm: Relocated VMM's IVT Base Addr:%lx\n",
+ kvm_vmm_info->vmm_ivt);
+
+ fdesc_offset = (unsigned long)vmm_info->vmm_entry - module_base;
+ kvm_vmm_info->vmm_entry = (kvm_vmm_entry *)(KVM_VMM_BASE +
+ fdesc_offset);
+ func_offset = *(unsigned long *)vmm_info->vmm_entry - module_base;
+ p_fdesc = (struct fdesc *)(kvm_vmm_base + fdesc_offset);
+ p_fdesc->ip = KVM_VMM_BASE + func_offset;
+ p_fdesc->gp = KVM_VMM_BASE+(p_fdesc->gp - module_base);
+
+ printk(KERN_DEBUG"kvm: Relocated VMM's Init Entry Addr:%lx\n",
+ KVM_VMM_BASE+func_offset);
+
+ fdesc_offset = (unsigned long)vmm_info->tramp_entry - module_base;
+ kvm_vmm_info->tramp_entry = (kvm_tramp_entry *)(KVM_VMM_BASE +
+ fdesc_offset);
+ func_offset = *(unsigned long *)vmm_info->tramp_entry - module_base;
+ p_fdesc = (struct fdesc *)(kvm_vmm_base + fdesc_offset);
+ p_fdesc->ip = KVM_VMM_BASE + func_offset;
+ p_fdesc->gp = KVM_VMM_BASE + (p_fdesc->gp - module_base);
+
+ kvm_vmm_gp = p_fdesc->gp;
+
+ printk(KERN_DEBUG"kvm: Relocated VMM's Entry IP:%p\n",
+ kvm_vmm_info->vmm_entry);
+ printk(KERN_DEBUG"kvm: Relocated VMM's Trampoline Entry IP:0x%lx\n",
+ KVM_VMM_BASE + func_offset);
+
+ return 0;
+}
+
+int kvm_arch_init(void *opaque)
+{
+ int r;
+ struct kvm_vmm_info *vmm_info = (struct kvm_vmm_info *)opaque;
+
+ if (!vti_cpu_has_kvm_support()) {
+ printk(KERN_ERR "kvm: No Hardware Virtualization Support!\n");
+ r = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (kvm_vmm_info) {
+ printk(KERN_ERR "kvm: Already loaded VMM module!\n");
+ r = -EEXIST;
+ goto out;
+ }
+
+ r = -ENOMEM;
+ kvm_vmm_info = kzalloc(sizeof(struct kvm_vmm_info), GFP_KERNEL);
+ if (!kvm_vmm_info)
+ goto out;
+
+ if (kvm_alloc_vmm_area())
+ goto out_free0;
+
+ r = kvm_relocate_vmm(vmm_info, vmm_info->module);
+ if (r)
+ goto out_free1;
+
+ return 0;
+
+out_free1:
+ kvm_free_vmm_area();
+out_free0:
+ kfree(kvm_vmm_info);
+out:
+ return r;
+}
+
+void kvm_arch_exit(void)
+{
+ kvm_free_vmm_area();
+ kfree(kvm_vmm_info);
+ kvm_vmm_info = NULL;
+}
+
+static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
+ struct kvm_dirty_log *log)
+{
+ struct kvm_memory_slot *memslot;
+ int r, i;
+ long n, base;
+ unsigned long *dirty_bitmap = (unsigned long *)((void *)kvm - KVM_VM_OFS
+ + KVM_MEM_DIRTY_LOG_OFS);
+
+ r = -EINVAL;
+ if (log->slot >= KVM_MEMORY_SLOTS)
+ goto out;
+
+ memslot = &kvm->memslots[log->slot];
+ r = -ENOENT;
+ if (!memslot->dirty_bitmap)
+ goto out;
+
+ n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ base = memslot->base_gfn / BITS_PER_LONG;
+
+ for (i = 0; i < n/sizeof(long); ++i) {
+ memslot->dirty_bitmap[i] = dirty_bitmap[base + i];
+ dirty_bitmap[base + i] = 0;
+ }
+ r = 0;
+out:
+ return r;
+}
+
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+ struct kvm_dirty_log *log)
+{
+ int r;
+ int n;
+ struct kvm_memory_slot *memslot;
+ int is_dirty = 0;
+
+ spin_lock(&kvm->arch.dirty_log_lock);
+
+ r = kvm_ia64_sync_dirty_log(kvm, log);
+ if (r)
+ goto out;
+
+ r = kvm_get_dirty_log(kvm, log, &is_dirty);
+ if (r)
+ goto out;
+
+ /* If nothing is dirty, don't bother messing with page tables. */
+ if (is_dirty) {
+ kvm_flush_remote_tlbs(kvm);
+ memslot = &kvm->memslots[log->slot];
+ n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ memset(memslot->dirty_bitmap, 0, n);
+ }
+ r = 0;
+out:
+ spin_unlock(&kvm->arch.dirty_log_lock);
+ return r;
+}
+
+int kvm_arch_hardware_setup(void)
+{
+ return 0;
+}
+
+void kvm_arch_hardware_unsetup(void)
+{
+}
+
+static void vcpu_kick_intr(void *info)
+{
+#ifdef DEBUG
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
+ printk(KERN_DEBUG"vcpu_kick_intr %p \n", vcpu);
+#endif
+}
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+ int ipi_pcpu = vcpu->cpu;
+
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
+
+ if (vcpu->guest_mode)
+ smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
+}
+
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
+{
+
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+
+ if (!test_and_set_bit(vec, &vpd->irr[0])) {
+ vcpu->arch.irq_new_pending = 1;
+ if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
+ kvm_vcpu_kick(vcpu);
+ else if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED) {
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
+{
+ return apic->vcpu->vcpu_id == dest;
+}
+
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
+{
+ return 0;
+}
+
+struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
+ unsigned long bitmap)
+{
+ struct kvm_vcpu *lvcpu = kvm->vcpus[0];
+ int i;
+
+ for (i = 1; i < KVM_MAX_VCPUS; i++) {
+ if (!kvm->vcpus[i])
+ continue;
+ if (lvcpu->arch.xtp > kvm->vcpus[i]->arch.xtp)
+ lvcpu = kvm->vcpus[i];
+ }
+
+ return lvcpu;
+}
+
+static int find_highest_bits(int *dat)
+{
+ u32 bits, bitnum;
+ int i;
+
+ /* loop for all 256 bits */
+ for (i = 7; i >= 0 ; i--) {
+ bits = dat[i];
+ if (bits) {
+ bitnum = fls(bits);
+ return i * 32 + bitnum - 1;
+ }
+ }
+
+ return -1;
+}
+
+int kvm_highest_pending_irq(struct kvm_vcpu *vcpu)
+{
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+
+ if (vpd->irr[0] & (1UL << NMI_VECTOR))
+ return NMI_VECTOR;
+ if (vpd->irr[0] & (1UL << ExtINT_VECTOR))
+ return ExtINT_VECTOR;
+
+ return find_highest_bits((int *)&vpd->irr[0]);
+}
+
+int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
+{
+ if (kvm_highest_pending_irq(vcpu) != -1)
+ return 1;
+ return 0;
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
+{
+ return gfn;
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE;
+}
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
diff --git a/arch/ia64/kvm/kvm_fw.c b/arch/ia64/kvm/kvm_fw.c
new file mode 100644
index 000000000000..091f936c4485
--- /dev/null
+++ b/arch/ia64/kvm/kvm_fw.c
@@ -0,0 +1,500 @@
+/*
+ * PAL/SAL call delegation
+ *
+ * Copyright (c) 2004 Li Susie <susie.li@intel.com>
+ * Copyright (c) 2005 Yu Ke <ke.yu@intel.com>
+ * Copyright (c) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/kvm_host.h>
+#include <linux/smp.h>
+
+#include "vti.h"
+#include "misc.h"
+
+#include <asm/pal.h>
+#include <asm/sal.h>
+#include <asm/tlb.h>
+
+/*
+ * Handy macros to make sure that the PAL return values start out
+ * as something meaningful.
+ */
+#define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
+ { \
+ x.status = PAL_STATUS_UNIMPLEMENTED; \
+ x.v0 = 0; \
+ x.v1 = 0; \
+ x.v2 = 0; \
+ }
+
+#define INIT_PAL_STATUS_SUCCESS(x) \
+ { \
+ x.status = PAL_STATUS_SUCCESS; \
+ x.v0 = 0; \
+ x.v1 = 0; \
+ x.v2 = 0; \
+ }
+
+static void kvm_get_pal_call_data(struct kvm_vcpu *vcpu,
+ u64 *gr28, u64 *gr29, u64 *gr30, u64 *gr31) {
+ struct exit_ctl_data *p;
+
+ if (vcpu) {
+ p = &vcpu->arch.exit_data;
+ if (p->exit_reason == EXIT_REASON_PAL_CALL) {
+ *gr28 = p->u.pal_data.gr28;
+ *gr29 = p->u.pal_data.gr29;
+ *gr30 = p->u.pal_data.gr30;
+ *gr31 = p->u.pal_data.gr31;
+ return ;
+ }
+ }
+ printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n");
+}
+
+static void set_pal_result(struct kvm_vcpu *vcpu,
+ struct ia64_pal_retval result) {
+
+ struct exit_ctl_data *p;
+
+ p = kvm_get_exit_data(vcpu);
+ if (p && p->exit_reason == EXIT_REASON_PAL_CALL) {
+ p->u.pal_data.ret = result;
+ return ;
+ }
+ INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret);
+}
+
+static void set_sal_result(struct kvm_vcpu *vcpu,
+ struct sal_ret_values result) {
+ struct exit_ctl_data *p;
+
+ p = kvm_get_exit_data(vcpu);
+ if (p && p->exit_reason == EXIT_REASON_SAL_CALL) {
+ p->u.sal_data.ret = result;
+ return ;
+ }
+ printk(KERN_WARNING"Failed to set sal result!!\n");
+}
+
+struct cache_flush_args {
+ u64 cache_type;
+ u64 operation;
+ u64 progress;
+ long status;
+};
+
+cpumask_t cpu_cache_coherent_map;
+
+static void remote_pal_cache_flush(void *data)
+{
+ struct cache_flush_args *args = data;
+ long status;
+ u64 progress = args->progress;
+
+ status = ia64_pal_cache_flush(args->cache_type, args->operation,
+ &progress, NULL);
+ if (status != 0)
+ args->status = status;
+}
+
+static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu)
+{
+ u64 gr28, gr29, gr30, gr31;
+ struct ia64_pal_retval result = {0, 0, 0, 0};
+ struct cache_flush_args args = {0, 0, 0, 0};
+ long psr;
+
+ gr28 = gr29 = gr30 = gr31 = 0;
+ kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31);
+
+ if (gr31 != 0)
+ printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu);
+
+ /* Always call Host Pal in int=1 */
+ gr30 &= ~PAL_CACHE_FLUSH_CHK_INTRS;
+ args.cache_type = gr29;
+ args.operation = gr30;
+ smp_call_function(remote_pal_cache_flush,
+ (void *)&args, 1, 1);
+ if (args.status != 0)
+ printk(KERN_ERR"pal_cache_flush error!,"
+ "status:0x%lx\n", args.status);
+ /*
+ * Call Host PAL cache flush
+ * Clear psr.ic when call PAL_CACHE_FLUSH
+ */
+ local_irq_save(psr);
+ result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1,
+ &result.v0);
+ local_irq_restore(psr);
+ if (result.status != 0)
+ printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld"
+ "in1:%lx,in2:%lx\n",
+ vcpu, result.status, gr29, gr30);
+
+#if 0
+ if (gr29 == PAL_CACHE_TYPE_COHERENT) {
+ cpus_setall(vcpu->arch.cache_coherent_map);
+ cpu_clear(vcpu->cpu, vcpu->arch.cache_coherent_map);
+ cpus_setall(cpu_cache_coherent_map);
+ cpu_clear(vcpu->cpu, cpu_cache_coherent_map);
+ }
+#endif
+ return result;
+}
+
+struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu)
+{
+
+ struct ia64_pal_retval result;
+
+ PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0);
+ return result;
+}
+
+static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
+{
+
+ struct ia64_pal_retval result;
+
+ PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);
+
+ /*
+ * PAL_FREQ_BASE may not be implemented in some platforms,
+ * call SAL instead.
+ */
+ if (result.v0 == 0) {
+ result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
+ &result.v0,
+ &result.v1);
+ result.v2 = 0;
+ }
+
+ return result;
+}
+
+static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
+{
+
+ struct ia64_pal_retval result;
+
+ PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
+ return result;
+}
+
+static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu)
+{
+ struct ia64_pal_retval result;
+
+ INIT_PAL_STATUS_UNIMPLEMENTED(result);
+ return result;
+}
+
+static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu)
+{
+
+ struct ia64_pal_retval result;
+
+ INIT_PAL_STATUS_SUCCESS(result);
+ return result;
+}
+
+static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu)
+{
+
+ struct ia64_pal_retval result = {0, 0, 0, 0};
+ long in0, in1, in2, in3;
+
+ kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
+ result.status = ia64_pal_proc_get_features(&result.v0, &result.v1,
+ &result.v2, in2);
+
+ return result;
+}
+
+static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu)
+{
+
+ pal_cache_config_info_t ci;
+ long status;
+ unsigned long in0, in1, in2, in3, r9, r10;
+
+ kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
+ status = ia64_pal_cache_config_info(in1, in2, &ci);
+ r9 = ci.pcci_info_1.pcci1_data;
+ r10 = ci.pcci_info_2.pcci2_data;
+ return ((struct ia64_pal_retval){status, r9, r10, 0});
+}
+
+#define GUEST_IMPL_VA_MSB 59
+#define GUEST_RID_BITS 18
+
+static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
+{
+
+ pal_vm_info_1_u_t vminfo1;
+ pal_vm_info_2_u_t vminfo2;
+ struct ia64_pal_retval result;
+
+ PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
+ if (!result.status) {
+ vminfo1.pvi1_val = result.v0;
+ vminfo1.pal_vm_info_1_s.max_itr_entry = 8;
+ vminfo1.pal_vm_info_1_s.max_dtr_entry = 8;
+ result.v0 = vminfo1.pvi1_val;
+ vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
+ vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS;
+ result.v1 = vminfo2.pvi2_val;
+ }
+
+ return result;
+}
+
+static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
+{
+ struct ia64_pal_retval result;
+
+ INIT_PAL_STATUS_UNIMPLEMENTED(result);
+
+ return result;
+}
+
+static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
+{
+ u64 index = 0;
+ struct exit_ctl_data *p;
+
+ p = kvm_get_exit_data(vcpu);
+ if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
+ index = p->u.pal_data.gr28;
+
+ return index;
+}
+
+int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+
+ u64 gr28;
+ struct ia64_pal_retval result;
+ int ret = 1;
+
+ gr28 = kvm_get_pal_call_index(vcpu);
+ /*printk("pal_call index:%lx\n",gr28);*/
+ switch (gr28) {
+ case PAL_CACHE_FLUSH:
+ result = pal_cache_flush(vcpu);
+ break;
+ case PAL_CACHE_SUMMARY:
+ result = pal_cache_summary(vcpu);
+ break;
+ case PAL_HALT_LIGHT:
+ {
+ vcpu->arch.timer_pending = 1;
+ INIT_PAL_STATUS_SUCCESS(result);
+ if (kvm_highest_pending_irq(vcpu) == -1)
+ ret = kvm_emulate_halt(vcpu);
+
+ }
+ break;
+
+ case PAL_FREQ_RATIOS:
+ result = pal_freq_ratios(vcpu);
+ break;
+
+ case PAL_FREQ_BASE:
+ result = pal_freq_base(vcpu);
+ break;
+
+ case PAL_LOGICAL_TO_PHYSICAL :
+ result = pal_logical_to_physica(vcpu);
+ break;
+
+ case PAL_VM_SUMMARY :
+ result = pal_vm_summary(vcpu);
+ break;
+
+ case PAL_VM_INFO :
+ result = pal_vm_info(vcpu);
+ break;
+ case PAL_PLATFORM_ADDR :
+ result = pal_platform_addr(vcpu);
+ break;
+ case PAL_CACHE_INFO:
+ result = pal_cache_info(vcpu);
+ break;
+ case PAL_PTCE_INFO:
+ INIT_PAL_STATUS_SUCCESS(result);
+ result.v1 = (1L << 32) | 1L;
+ break;
+ case PAL_VM_PAGE_SIZE:
+ result.status = ia64_pal_vm_page_size(&result.v0,
+ &result.v1);
+ break;
+ case PAL_RSE_INFO:
+ result.status = ia64_pal_rse_info(&result.v0,
+ (pal_hints_u_t *)&result.v1);
+ break;
+ case PAL_PROC_GET_FEATURES:
+ result = pal_proc_get_features(vcpu);
+ break;
+ case PAL_DEBUG_INFO:
+ result.status = ia64_pal_debug_info(&result.v0,
+ &result.v1);
+ break;
+ case PAL_VERSION:
+ result.status = ia64_pal_version(
+ (pal_version_u_t *)&result.v0,
+ (pal_version_u_t *)&result.v1);
+
+ break;
+ case PAL_FIXED_ADDR:
+ result.status = PAL_STATUS_SUCCESS;
+ result.v0 = vcpu->vcpu_id;
+ break;
+ default:
+ INIT_PAL_STATUS_UNIMPLEMENTED(result);
+ printk(KERN_WARNING"kvm: Unsupported pal call,"
+ " index:0x%lx\n", gr28);
+ }
+ set_pal_result(vcpu, result);
+ return ret;
+}
+
+static struct sal_ret_values sal_emulator(struct kvm *kvm,
+ long index, unsigned long in1,
+ unsigned long in2, unsigned long in3,
+ unsigned long in4, unsigned long in5,
+ unsigned long in6, unsigned long in7)
+{
+ unsigned long r9 = 0;
+ unsigned long r10 = 0;
+ long r11 = 0;
+ long status;
+
+ status = 0;
+ switch (index) {
+ case SAL_FREQ_BASE:
+ status = ia64_sal_freq_base(in1, &r9, &r10);
+ break;
+ case SAL_PCI_CONFIG_READ:
+ printk(KERN_WARNING"kvm: Not allowed to call here!"
+ " SAL_PCI_CONFIG_READ\n");
+ break;
+ case SAL_PCI_CONFIG_WRITE:
+ printk(KERN_WARNING"kvm: Not allowed to call here!"
+ " SAL_PCI_CONFIG_WRITE\n");
+ break;
+ case SAL_SET_VECTORS:
+ if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
+ if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
+ status = -2;
+ } else {
+ kvm->arch.rdv_sal_data.boot_ip = in2;
+ kvm->arch.rdv_sal_data.boot_gp = in3;
+ }
+ printk("Rendvous called! iip:%lx\n\n", in2);
+ } else
+ printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
+ "ignored...\n", in1);
+ break;
+ case SAL_GET_STATE_INFO:
+ /* No more info. */
+ status = -5;
+ r9 = 0;
+ break;
+ case SAL_GET_STATE_INFO_SIZE:
+ /* Return a dummy size. */
+ status = 0;
+ r9 = 128;
+ break;
+ case SAL_CLEAR_STATE_INFO:
+ /* Noop. */
+ break;
+ case SAL_MC_RENDEZ:
+ printk(KERN_WARNING
+ "kvm: called SAL_MC_RENDEZ. ignored...\n");
+ break;
+ case SAL_MC_SET_PARAMS:
+ printk(KERN_WARNING
+ "kvm: called SAL_MC_SET_PARAMS.ignored!\n");
+ break;
+ case SAL_CACHE_FLUSH:
+ if (1) {
+ /*Flush using SAL.
+ This method is faster but has a side
+ effect on other vcpu running on
+ this cpu. */
+ status = ia64_sal_cache_flush(in1);
+ } else {
+ /*Maybe need to implement the method
+ without side effect!*/
+ status = 0;
+ }
+ break;
+ case SAL_CACHE_INIT:
+ printk(KERN_WARNING
+ "kvm: called SAL_CACHE_INIT. ignored...\n");
+ break;
+ case SAL_UPDATE_PAL:
+ printk(KERN_WARNING
+ "kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
+ break;
+ default:
+ printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
+ " index:%ld\n", index);
+ status = -1;
+ break;
+ }
+ return ((struct sal_ret_values) {status, r9, r10, r11});
+}
+
+static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1,
+ u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){
+
+ struct exit_ctl_data *p;
+
+ p = kvm_get_exit_data(vcpu);
+
+ if (p) {
+ if (p->exit_reason == EXIT_REASON_SAL_CALL) {
+ *in0 = p->u.sal_data.in0;
+ *in1 = p->u.sal_data.in1;
+ *in2 = p->u.sal_data.in2;
+ *in3 = p->u.sal_data.in3;
+ *in4 = p->u.sal_data.in4;
+ *in5 = p->u.sal_data.in5;
+ *in6 = p->u.sal_data.in6;
+ *in7 = p->u.sal_data.in7;
+ return ;
+ }
+ }
+ *in0 = 0;
+}
+
+void kvm_sal_emul(struct kvm_vcpu *vcpu)
+{
+
+ struct sal_ret_values result;
+ u64 index, in1, in2, in3, in4, in5, in6, in7;
+
+ kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
+ &in3, &in4, &in5, &in6, &in7);
+ result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
+ in4, in5, in6, in7);
+ set_sal_result(vcpu, result);
+}
diff --git a/arch/ia64/kvm/kvm_minstate.h b/arch/ia64/kvm/kvm_minstate.h
new file mode 100644
index 000000000000..13980d9b8bcf
--- /dev/null
+++ b/arch/ia64/kvm/kvm_minstate.h
@@ -0,0 +1,273 @@
+/*
+ * kvm_minstate.h: min save macros
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+
+#include <asm/asmmacro.h>
+#include <asm/types.h>
+#include <asm/kregs.h>
+#include "asm-offsets.h"
+
+#define KVM_MINSTATE_START_SAVE_MIN \
+ mov ar.rsc = 0;/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */\
+ ;; \
+ mov.m r28 = ar.rnat; \
+ addl r22 = VMM_RBS_OFFSET,r1; /* compute base of RBS */ \
+ ;; \
+ lfetch.fault.excl.nt1 [r22]; \
+ addl r1 = IA64_STK_OFFSET-VMM_PT_REGS_SIZE,r1; /* compute base of memory stack */ \
+ mov r23 = ar.bspstore; /* save ar.bspstore */ \
+ ;; \
+ mov ar.bspstore = r22; /* switch to kernel RBS */\
+ ;; \
+ mov r18 = ar.bsp; \
+ mov ar.rsc = 0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */
+
+
+
+#define KVM_MINSTATE_END_SAVE_MIN \
+ bsw.1; /* switch back to bank 1 (must be last in insn group) */\
+ ;;
+
+
+#define PAL_VSA_SYNC_READ \
+ /* begin to call pal vps sync_read */ \
+ add r25 = VMM_VPD_BASE_OFFSET, r21; \
+ adds r20 = VMM_VCPU_VSA_BASE_OFFSET, r21; /* entry point */ \
+ ;; \
+ ld8 r25 = [r25]; /* read vpd base */ \
+ ld8 r20 = [r20]; \
+ ;; \
+ add r20 = PAL_VPS_SYNC_READ,r20; \
+ ;; \
+{ .mii; \
+ nop 0x0; \
+ mov r24 = ip; \
+ mov b0 = r20; \
+ ;; \
+}; \
+{ .mmb; \
+ add r24 = 0x20, r24; \
+ nop 0x0; \
+ br.cond.sptk b0; /* call the service */ \
+ ;; \
+};
+
+
+
+#define KVM_MINSTATE_GET_CURRENT(reg) mov reg=r21
+
+/*
+ * KVM_DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
+ * the minimum state necessary that allows us to turn psr.ic back
+ * on.
+ *
+ * Assumed state upon entry:
+ * psr.ic: off
+ * r31: contains saved predicates (pr)
+ *
+ * Upon exit, the state is as follows:
+ * psr.ic: off
+ * r2 = points to &pt_regs.r16
+ * r8 = contents of ar.ccv
+ * r9 = contents of ar.csd
+ * r10 = contents of ar.ssd
+ * r11 = FPSR_DEFAULT
+ * r12 = kernel sp (kernel virtual address)
+ * r13 = points to current task_struct (kernel virtual address)
+ * p15 = TRUE if psr.i is set in cr.ipsr
+ * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15:
+ * preserved
+ *
+ * Note that psr.ic is NOT turned on by this macro. This is so that
+ * we can pass interruption state as arguments to a handler.
+ */
+
+
+#define PT(f) (VMM_PT_REGS_##f##_OFFSET)
+
+#define KVM_DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \
+ KVM_MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \
+ mov r27 = ar.rsc; /* M */ \
+ mov r20 = r1; /* A */ \
+ mov r25 = ar.unat; /* M */ \
+ mov r29 = cr.ipsr; /* M */ \
+ mov r26 = ar.pfs; /* I */ \
+ mov r18 = cr.isr; \
+ COVER; /* B;; (or nothing) */ \
+ ;; \
+ tbit.z p0,p15 = r29,IA64_PSR_I_BIT; \
+ mov r1 = r16; \
+/* mov r21=r16; */ \
+ /* switch from user to kernel RBS: */ \
+ ;; \
+ invala; /* M */ \
+ SAVE_IFS; \
+ ;; \
+ KVM_MINSTATE_START_SAVE_MIN \
+ adds r17 = 2*L1_CACHE_BYTES,r1;/* cache-line size */ \
+ adds r16 = PT(CR_IPSR),r1; \
+ ;; \
+ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \
+ st8 [r16] = r29; /* save cr.ipsr */ \
+ ;; \
+ lfetch.fault.excl.nt1 [r17]; \
+ tbit.nz p15,p0 = r29,IA64_PSR_I_BIT; \
+ mov r29 = b0 \
+ ;; \
+ adds r16 = PT(R8),r1; /* initialize first base pointer */\
+ adds r17 = PT(R9),r1; /* initialize second base pointer */\
+ ;; \
+.mem.offset 0,0; st8.spill [r16] = r8,16; \
+.mem.offset 8,0; st8.spill [r17] = r9,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r16] = r10,24; \
+.mem.offset 8,0; st8.spill [r17] = r11,24; \
+ ;; \
+ mov r9 = cr.iip; /* M */ \
+ mov r10 = ar.fpsr; /* M */ \
+ ;; \
+ st8 [r16] = r9,16; /* save cr.iip */ \
+ st8 [r17] = r30,16; /* save cr.ifs */ \
+ sub r18 = r18,r22; /* r18=RSE.ndirty*8 */ \
+ ;; \
+ st8 [r16] = r25,16; /* save ar.unat */ \
+ st8 [r17] = r26,16; /* save ar.pfs */ \
+ shl r18 = r18,16; /* calu ar.rsc used for "loadrs" */\
+ ;; \
+ st8 [r16] = r27,16; /* save ar.rsc */ \
+ st8 [r17] = r28,16; /* save ar.rnat */ \
+ ;; /* avoid RAW on r16 & r17 */ \
+ st8 [r16] = r23,16; /* save ar.bspstore */ \
+ st8 [r17] = r31,16; /* save predicates */ \
+ ;; \
+ st8 [r16] = r29,16; /* save b0 */ \
+ st8 [r17] = r18,16; /* save ar.rsc value for "loadrs" */\
+ ;; \
+.mem.offset 0,0; st8.spill [r16] = r20,16;/* save original r1 */ \
+.mem.offset 8,0; st8.spill [r17] = r12,16; \
+ adds r12 = -16,r1; /* switch to kernel memory stack */ \
+ ;; \
+.mem.offset 0,0; st8.spill [r16] = r13,16; \
+.mem.offset 8,0; st8.spill [r17] = r10,16; /* save ar.fpsr */\
+ mov r13 = r21; /* establish `current' */ \
+ ;; \
+.mem.offset 0,0; st8.spill [r16] = r15,16; \
+.mem.offset 8,0; st8.spill [r17] = r14,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r16] = r2,16; \
+.mem.offset 8,0; st8.spill [r17] = r3,16; \
+ adds r2 = VMM_PT_REGS_R16_OFFSET,r1; \
+ ;; \
+ adds r16 = VMM_VCPU_IIPA_OFFSET,r13; \
+ adds r17 = VMM_VCPU_ISR_OFFSET,r13; \
+ mov r26 = cr.iipa; \
+ mov r27 = cr.isr; \
+ ;; \
+ st8 [r16] = r26; \
+ st8 [r17] = r27; \
+ ;; \
+ EXTRA; \
+ mov r8 = ar.ccv; \
+ mov r9 = ar.csd; \
+ mov r10 = ar.ssd; \
+ movl r11 = FPSR_DEFAULT; /* L-unit */ \
+ adds r17 = VMM_VCPU_GP_OFFSET,r13; \
+ ;; \
+ ld8 r1 = [r17];/* establish kernel global pointer */ \
+ ;; \
+ PAL_VSA_SYNC_READ \
+ KVM_MINSTATE_END_SAVE_MIN
+
+/*
+ * SAVE_REST saves the remainder of pt_regs (with psr.ic on).
+ *
+ * Assumed state upon entry:
+ * psr.ic: on
+ * r2: points to &pt_regs.f6
+ * r3: points to &pt_regs.f7
+ * r8: contents of ar.ccv
+ * r9: contents of ar.csd
+ * r10: contents of ar.ssd
+ * r11: FPSR_DEFAULT
+ *
+ * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST.
+ */
+#define KVM_SAVE_REST \
+.mem.offset 0,0; st8.spill [r2] = r16,16; \
+.mem.offset 8,0; st8.spill [r3] = r17,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r18,16; \
+.mem.offset 8,0; st8.spill [r3] = r19,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r20,16; \
+.mem.offset 8,0; st8.spill [r3] = r21,16; \
+ mov r18=b6; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r22,16; \
+.mem.offset 8,0; st8.spill [r3] = r23,16; \
+ mov r19 = b7; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r24,16; \
+.mem.offset 8,0; st8.spill [r3] = r25,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r26,16; \
+.mem.offset 8,0; st8.spill [r3] = r27,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r28,16; \
+.mem.offset 8,0; st8.spill [r3] = r29,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r30,16; \
+.mem.offset 8,0; st8.spill [r3] = r31,32; \
+ ;; \
+ mov ar.fpsr = r11; \
+ st8 [r2] = r8,8; \
+ adds r24 = PT(B6)-PT(F7),r3; \
+ adds r25 = PT(B7)-PT(F7),r3; \
+ ;; \
+ st8 [r24] = r18,16; /* b6 */ \
+ st8 [r25] = r19,16; /* b7 */ \
+ adds r2 = PT(R4)-PT(F6),r2; \
+ adds r3 = PT(R5)-PT(F7),r3; \
+ ;; \
+ st8 [r24] = r9; /* ar.csd */ \
+ st8 [r25] = r10; /* ar.ssd */ \
+ ;; \
+ mov r18 = ar.unat; \
+ adds r19 = PT(EML_UNAT)-PT(R4),r2; \
+ ;; \
+ st8 [r19] = r18; /* eml_unat */ \
+
+
+#define KVM_SAVE_EXTRA \
+.mem.offset 0,0; st8.spill [r2] = r4,16; \
+.mem.offset 8,0; st8.spill [r3] = r5,16; \
+ ;; \
+.mem.offset 0,0; st8.spill [r2] = r6,16; \
+.mem.offset 8,0; st8.spill [r3] = r7; \
+ ;; \
+ mov r26 = ar.unat; \
+ ;; \
+ st8 [r2] = r26;/* eml_unat */ \
+
+#define KVM_SAVE_MIN_WITH_COVER KVM_DO_SAVE_MIN(cover, mov r30 = cr.ifs,)
+#define KVM_SAVE_MIN_WITH_COVER_R19 KVM_DO_SAVE_MIN(cover, mov r30 = cr.ifs, mov r15 = r19)
+#define KVM_SAVE_MIN KVM_DO_SAVE_MIN( , mov r30 = r0, )
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
new file mode 100644
index 000000000000..6d6cbcb14893
--- /dev/null
+++ b/arch/ia64/kvm/lapic.h
@@ -0,0 +1,25 @@
+#ifndef __KVM_IA64_LAPIC_H
+#define __KVM_IA64_LAPIC_H
+
+#include <linux/kvm_host.h>
+
+/*
+ * vlsapic
+ */
+struct kvm_lapic{
+ struct kvm_vcpu *vcpu;
+ uint64_t insvc[4];
+ uint64_t vhpi;
+ uint8_t xtp;
+ uint8_t pal_init_pending;
+ uint8_t pad[2];
+};
+
+int kvm_create_lapic(struct kvm_vcpu *vcpu);
+void kvm_free_lapic(struct kvm_vcpu *vcpu);
+
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig);
+
+#endif
diff --git a/arch/ia64/kvm/misc.h b/arch/ia64/kvm/misc.h
new file mode 100644
index 000000000000..e585c4607344
--- /dev/null
+++ b/arch/ia64/kvm/misc.h
@@ -0,0 +1,93 @@
+#ifndef __KVM_IA64_MISC_H
+#define __KVM_IA64_MISC_H
+
+#include <linux/kvm_host.h>
+/*
+ * misc.h
+ * Copyright (C) 2007, Intel Corporation.
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+
+/*
+ *Return p2m base address at host side!
+ */
+static inline uint64_t *kvm_host_get_pmt(struct kvm *kvm)
+{
+ return (uint64_t *)(kvm->arch.vm_base + KVM_P2M_OFS);
+}
+
+static inline void kvm_set_pmt_entry(struct kvm *kvm, gfn_t gfn,
+ u64 paddr, u64 mem_flags)
+{
+ uint64_t *pmt_base = kvm_host_get_pmt(kvm);
+ unsigned long pte;
+
+ pte = PAGE_ALIGN(paddr) | mem_flags;
+ pmt_base[gfn] = pte;
+}
+
+/*Function for translating host address to guest address*/
+
+static inline void *to_guest(struct kvm *kvm, void *addr)
+{
+ return (void *)((unsigned long)(addr) - kvm->arch.vm_base +
+ KVM_VM_DATA_BASE);
+}
+
+/*Function for translating guest address to host address*/
+
+static inline void *to_host(struct kvm *kvm, void *addr)
+{
+ return (void *)((unsigned long)addr - KVM_VM_DATA_BASE
+ + kvm->arch.vm_base);
+}
+
+/* Get host context of the vcpu */
+static inline union context *kvm_get_host_context(struct kvm_vcpu *vcpu)
+{
+ union context *ctx = &vcpu->arch.host;
+ return to_guest(vcpu->kvm, ctx);
+}
+
+/* Get guest context of the vcpu */
+static inline union context *kvm_get_guest_context(struct kvm_vcpu *vcpu)
+{
+ union context *ctx = &vcpu->arch.guest;
+ return to_guest(vcpu->kvm, ctx);
+}
+
+/* kvm get exit data from gvmm! */
+static inline struct exit_ctl_data *kvm_get_exit_data(struct kvm_vcpu *vcpu)
+{
+ return &vcpu->arch.exit_data;
+}
+
+/*kvm get vcpu ioreq for kvm module!*/
+static inline struct kvm_mmio_req *kvm_get_vcpu_ioreq(struct kvm_vcpu *vcpu)
+{
+ struct exit_ctl_data *p_ctl_data;
+
+ if (vcpu) {
+ p_ctl_data = kvm_get_exit_data(vcpu);
+ if (p_ctl_data->exit_reason == EXIT_REASON_MMIO_INSTRUCTION)
+ return &p_ctl_data->u.ioreq;
+ }
+
+ return NULL;
+}
+
+#endif
diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c
new file mode 100644
index 000000000000..351bf70da463
--- /dev/null
+++ b/arch/ia64/kvm/mmio.c
@@ -0,0 +1,341 @@
+/*
+ * mmio.c: MMIO emulation components.
+ * Copyright (c) 2004, Intel Corporation.
+ * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
+ * Kun Tian (Kevin Tian) (Kevin.tian@intel.com)
+ *
+ * Copyright (c) 2007 Intel Corporation KVM support.
+ * Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/kvm_host.h>
+
+#include "vcpu.h"
+
+static void vlsapic_write_xtp(struct kvm_vcpu *v, uint8_t val)
+{
+ VLSAPIC_XTP(v) = val;
+}
+
+/*
+ * LSAPIC OFFSET
+ */
+#define PIB_LOW_HALF(ofst) !(ofst & (1 << 20))
+#define PIB_OFST_INTA 0x1E0000
+#define PIB_OFST_XTP 0x1E0008
+
+/*
+ * execute write IPI op.
+ */
+static void vlsapic_write_ipi(struct kvm_vcpu *vcpu,
+ uint64_t addr, uint64_t data)
+{
+ struct exit_ctl_data *p = &current_vcpu->arch.exit_data;
+ unsigned long psr;
+
+ local_irq_save(psr);
+
+ p->exit_reason = EXIT_REASON_IPI;
+ p->u.ipi_data.addr.val = addr;
+ p->u.ipi_data.data.val = data;
+ vmm_transition(current_vcpu);
+
+ local_irq_restore(psr);
+
+}
+
+void lsapic_write(struct kvm_vcpu *v, unsigned long addr,
+ unsigned long length, unsigned long val)
+{
+ addr &= (PIB_SIZE - 1);
+
+ switch (addr) {
+ case PIB_OFST_INTA:
+ /*panic_domain(NULL, "Undefined write on PIB INTA\n");*/
+ panic_vm(v);
+ break;
+ case PIB_OFST_XTP:
+ if (length == 1) {
+ vlsapic_write_xtp(v, val);
+ } else {
+ /*panic_domain(NULL,
+ "Undefined write on PIB XTP\n");*/
+ panic_vm(v);
+ }
+ break;
+ default:
+ if (PIB_LOW_HALF(addr)) {
+ /*lower half */
+ if (length != 8)
+ /*panic_domain(NULL,
+ "Can't LHF write with size %ld!\n",
+ length);*/
+ panic_vm(v);
+ else
+ vlsapic_write_ipi(v, addr, val);
+ } else { /* upper half
+ printk("IPI-UHF write %lx\n",addr);*/
+ panic_vm(v);
+ }
+ break;
+ }
+}
+
+unsigned long lsapic_read(struct kvm_vcpu *v, unsigned long addr,
+ unsigned long length)
+{
+ uint64_t result = 0;
+
+ addr &= (PIB_SIZE - 1);
+
+ switch (addr) {
+ case PIB_OFST_INTA:
+ if (length == 1) /* 1 byte load */
+ ; /* There is no i8259, there is no INTA access*/
+ else
+ /*panic_domain(NULL,"Undefined read on PIB INTA\n"); */
+ panic_vm(v);
+
+ break;
+ case PIB_OFST_XTP:
+ if (length == 1) {
+ result = VLSAPIC_XTP(v);
+ /* printk("read xtp %lx\n", result); */
+ } else {
+ /*panic_domain(NULL,
+ "Undefined read on PIB XTP\n");*/
+ panic_vm(v);
+ }
+ break;
+ default:
+ panic_vm(v);
+ break;
+ }
+ return result;
+}
+
+static void mmio_access(struct kvm_vcpu *vcpu, u64 src_pa, u64 *dest,
+ u16 s, int ma, int dir)
+{
+ unsigned long iot;
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+ unsigned long psr;
+
+ iot = __gpfn_is_io(src_pa >> PAGE_SHIFT);
+
+ local_irq_save(psr);
+
+ /*Intercept the acces for PIB range*/
+ if (iot == GPFN_PIB) {
+ if (!dir)
+ lsapic_write(vcpu, src_pa, s, *dest);
+ else
+ *dest = lsapic_read(vcpu, src_pa, s);
+ goto out;
+ }
+ p->exit_reason = EXIT_REASON_MMIO_INSTRUCTION;
+ p->u.ioreq.addr = src_pa;
+ p->u.ioreq.size = s;
+ p->u.ioreq.dir = dir;
+ if (dir == IOREQ_WRITE)
+ p->u.ioreq.data = *dest;
+ p->u.ioreq.state = STATE_IOREQ_READY;
+ vmm_transition(vcpu);
+
+ if (p->u.ioreq.state == STATE_IORESP_READY) {
+ if (dir == IOREQ_READ)
+ *dest = p->u.ioreq.data;
+ } else
+ panic_vm(vcpu);
+out:
+ local_irq_restore(psr);
+ return ;
+}
+
+/*
+ dir 1: read 0:write
+ inst_type 0:integer 1:floating point
+ */
+#define SL_INTEGER 0 /* store/load interger*/
+#define SL_FLOATING 1 /* store/load floating*/
+
+void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma)
+{
+ struct kvm_pt_regs *regs;
+ IA64_BUNDLE bundle;
+ int slot, dir = 0;
+ int inst_type = -1;
+ u16 size = 0;
+ u64 data, slot1a, slot1b, temp, update_reg;
+ s32 imm;
+ INST64 inst;
+
+ regs = vcpu_regs(vcpu);
+
+ if (fetch_code(vcpu, regs->cr_iip, &bundle)) {
+ /* if fetch code fail, return and try again */
+ return;
+ }
+ slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri;
+ if (!slot)
+ inst.inst = bundle.slot0;
+ else if (slot == 1) {
+ slot1a = bundle.slot1a;
+ slot1b = bundle.slot1b;
+ inst.inst = slot1a + (slot1b << 18);
+ } else if (slot == 2)
+ inst.inst = bundle.slot2;
+
+ /* Integer Load/Store */
+ if (inst.M1.major == 4 && inst.M1.m == 0 && inst.M1.x == 0) {
+ inst_type = SL_INTEGER;
+ size = (inst.M1.x6 & 0x3);
+ if ((inst.M1.x6 >> 2) > 0xb) {
+ /*write*/
+ dir = IOREQ_WRITE;
+ data = vcpu_get_gr(vcpu, inst.M4.r2);
+ } else if ((inst.M1.x6 >> 2) < 0xb) {
+ /*read*/
+ dir = IOREQ_READ;
+ }
+ } else if (inst.M2.major == 4 && inst.M2.m == 1 && inst.M2.x == 0) {
+ /* Integer Load + Reg update */
+ inst_type = SL_INTEGER;
+ dir = IOREQ_READ;
+ size = (inst.M2.x6 & 0x3);
+ temp = vcpu_get_gr(vcpu, inst.M2.r3);
+ update_reg = vcpu_get_gr(vcpu, inst.M2.r2);
+ temp += update_reg;
+ vcpu_set_gr(vcpu, inst.M2.r3, temp, 0);
+ } else if (inst.M3.major == 5) {
+ /*Integer Load/Store + Imm update*/
+ inst_type = SL_INTEGER;
+ size = (inst.M3.x6&0x3);
+ if ((inst.M5.x6 >> 2) > 0xb) {
+ /*write*/
+ dir = IOREQ_WRITE;
+ data = vcpu_get_gr(vcpu, inst.M5.r2);
+ temp = vcpu_get_gr(vcpu, inst.M5.r3);
+ imm = (inst.M5.s << 31) | (inst.M5.i << 30) |
+ (inst.M5.imm7 << 23);
+ temp += imm >> 23;
+ vcpu_set_gr(vcpu, inst.M5.r3, temp, 0);
+
+ } else if ((inst.M3.x6 >> 2) < 0xb) {
+ /*read*/
+ dir = IOREQ_READ;
+ temp = vcpu_get_gr(vcpu, inst.M3.r3);
+ imm = (inst.M3.s << 31) | (inst.M3.i << 30) |
+ (inst.M3.imm7 << 23);
+ temp += imm >> 23;
+ vcpu_set_gr(vcpu, inst.M3.r3, temp, 0);
+
+ }
+ } else if (inst.M9.major == 6 && inst.M9.x6 == 0x3B
+ && inst.M9.m == 0 && inst.M9.x == 0) {
+ /* Floating-point spill*/
+ struct ia64_fpreg v;
+
+ inst_type = SL_FLOATING;
+ dir = IOREQ_WRITE;
+ vcpu_get_fpreg(vcpu, inst.M9.f2, &v);
+ /* Write high word. FIXME: this is a kludge! */
+ v.u.bits[1] &= 0x3ffff;
+ mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
+ data = v.u.bits[0];
+ size = 3;
+ } else if (inst.M10.major == 7 && inst.M10.x6 == 0x3B) {
+ /* Floating-point spill + Imm update */
+ struct ia64_fpreg v;
+
+ inst_type = SL_FLOATING;
+ dir = IOREQ_WRITE;
+ vcpu_get_fpreg(vcpu, inst.M10.f2, &v);
+ temp = vcpu_get_gr(vcpu, inst.M10.r3);
+ imm = (inst.M10.s << 31) | (inst.M10.i << 30) |
+ (inst.M10.imm7 << 23);
+ temp += imm >> 23;
+ vcpu_set_gr(vcpu, inst.M10.r3, temp, 0);
+
+ /* Write high word.FIXME: this is a kludge! */
+ v.u.bits[1] &= 0x3ffff;
+ mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
+ data = v.u.bits[0];
+ size = 3;
+ } else if (inst.M10.major == 7 && inst.M10.x6 == 0x31) {
+ /* Floating-point stf8 + Imm update */
+ struct ia64_fpreg v;
+ inst_type = SL_FLOATING;
+ dir = IOREQ_WRITE;
+ size = 3;
+ vcpu_get_fpreg(vcpu, inst.M10.f2, &v);
+ data = v.u.bits[0]; /* Significand. */
+ temp = vcpu_get_gr(vcpu, inst.M10.r3);
+ imm = (inst.M10.s << 31) | (inst.M10.i << 30) |
+ (inst.M10.imm7 << 23);
+ temp += imm >> 23;
+ vcpu_set_gr(vcpu, inst.M10.r3, temp, 0);
+ } else if (inst.M15.major == 7 && inst.M15.x6 >= 0x2c
+ && inst.M15.x6 <= 0x2f) {
+ temp = vcpu_get_gr(vcpu, inst.M15.r3);
+ imm = (inst.M15.s << 31) | (inst.M15.i << 30) |
+ (inst.M15.imm7 << 23);
+ temp += imm >> 23;
+ vcpu_set_gr(vcpu, inst.M15.r3, temp, 0);
+
+ vcpu_increment_iip(vcpu);
+ return;
+ } else if (inst.M12.major == 6 && inst.M12.m == 1
+ && inst.M12.x == 1 && inst.M12.x6 == 1) {
+ /* Floating-point Load Pair + Imm ldfp8 M12*/
+ struct ia64_fpreg v;
+
+ inst_type = SL_FLOATING;
+ dir = IOREQ_READ;
+ size = 8; /*ldfd*/
+ mmio_access(vcpu, padr, &data, size, ma, dir);
+ v.u.bits[0] = data;
+ v.u.bits[1] = 0x1003E;
+ vcpu_set_fpreg(vcpu, inst.M12.f1, &v);
+ padr += 8;
+ mmio_access(vcpu, padr, &data, size, ma, dir);
+ v.u.bits[0] = data;
+ v.u.bits[1] = 0x1003E;
+ vcpu_set_fpreg(vcpu, inst.M12.f2, &v);
+ padr += 8;
+ vcpu_set_gr(vcpu, inst.M12.r3, padr, 0);
+ vcpu_increment_iip(vcpu);
+ return;
+ } else {
+ inst_type = -1;
+ panic_vm(vcpu);
+ }
+
+ size = 1 << size;
+ if (dir == IOREQ_WRITE) {
+ mmio_access(vcpu, padr, &data, size, ma, dir);
+ } else {
+ mmio_access(vcpu, padr, &data, size, ma, dir);
+ if (inst_type == SL_INTEGER)
+ vcpu_set_gr(vcpu, inst.M1.r1, data, 0);
+ else
+ panic_vm(vcpu);
+
+ }
+ vcpu_increment_iip(vcpu);
+}
diff --git a/arch/ia64/kvm/optvfault.S b/arch/ia64/kvm/optvfault.S
new file mode 100644
index 000000000000..e4f15d641b22
--- /dev/null
+++ b/arch/ia64/kvm/optvfault.S
@@ -0,0 +1,918 @@
+/*
+ * arch/ia64/vmx/optvfault.S
+ * optimize virtualization fault handler
+ *
+ * Copyright (C) 2006 Intel Co
+ * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com>
+ */
+
+#include <asm/asmmacro.h>
+#include <asm/processor.h>
+
+#include "vti.h"
+#include "asm-offsets.h"
+
+#define ACCE_MOV_FROM_AR
+#define ACCE_MOV_FROM_RR
+#define ACCE_MOV_TO_RR
+#define ACCE_RSM
+#define ACCE_SSM
+#define ACCE_MOV_TO_PSR
+#define ACCE_THASH
+
+//mov r1=ar3
+GLOBAL_ENTRY(kvm_asm_mov_from_ar)
+#ifndef ACCE_MOV_FROM_AR
+ br.many kvm_virtualization_fault_back
+#endif
+ add r18=VMM_VCPU_ITC_OFS_OFFSET, r21
+ add r16=VMM_VCPU_LAST_ITC_OFFSET,r21
+ extr.u r17=r25,6,7
+ ;;
+ ld8 r18=[r18]
+ mov r19=ar.itc
+ mov r24=b0
+ ;;
+ add r19=r19,r18
+ addl r20=@gprel(asm_mov_to_reg),gp
+ ;;
+ st8 [r16] = r19
+ adds r30=kvm_resume_to_guest-asm_mov_to_reg,r20
+ shladd r17=r17,4,r20
+ ;;
+ mov b0=r17
+ br.sptk.few b0
+ ;;
+END(kvm_asm_mov_from_ar)
+
+
+// mov r1=rr[r3]
+GLOBAL_ENTRY(kvm_asm_mov_from_rr)
+#ifndef ACCE_MOV_FROM_RR
+ br.many kvm_virtualization_fault_back
+#endif
+ extr.u r16=r25,20,7
+ extr.u r17=r25,6,7
+ addl r20=@gprel(asm_mov_from_reg),gp
+ ;;
+ adds r30=kvm_asm_mov_from_rr_back_1-asm_mov_from_reg,r20
+ shladd r16=r16,4,r20
+ mov r24=b0
+ ;;
+ add r27=VMM_VCPU_VRR0_OFFSET,r21
+ mov b0=r16
+ br.many b0
+ ;;
+kvm_asm_mov_from_rr_back_1:
+ adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20
+ adds r22=asm_mov_to_reg-asm_mov_from_reg,r20
+ shr.u r26=r19,61
+ ;;
+ shladd r17=r17,4,r22
+ shladd r27=r26,3,r27
+ ;;
+ ld8 r19=[r27]
+ mov b0=r17
+ br.many b0
+END(kvm_asm_mov_from_rr)
+
+
+// mov rr[r3]=r2
+GLOBAL_ENTRY(kvm_asm_mov_to_rr)
+#ifndef ACCE_MOV_TO_RR
+ br.many kvm_virtualization_fault_back
+#endif
+ extr.u r16=r25,20,7
+ extr.u r17=r25,13,7
+ addl r20=@gprel(asm_mov_from_reg),gp
+ ;;
+ adds r30=kvm_asm_mov_to_rr_back_1-asm_mov_from_reg,r20
+ shladd r16=r16,4,r20
+ mov r22=b0
+ ;;
+ add r27=VMM_VCPU_VRR0_OFFSET,r21
+ mov b0=r16
+ br.many b0
+ ;;
+kvm_asm_mov_to_rr_back_1:
+ adds r30=kvm_asm_mov_to_rr_back_2-asm_mov_from_reg,r20
+ shr.u r23=r19,61
+ shladd r17=r17,4,r20
+ ;;
+ //if rr6, go back
+ cmp.eq p6,p0=6,r23
+ mov b0=r22
+ (p6) br.cond.dpnt.many kvm_virtualization_fault_back
+ ;;
+ mov r28=r19
+ mov b0=r17
+ br.many b0
+kvm_asm_mov_to_rr_back_2:
+ adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20
+ shladd r27=r23,3,r27
+ ;; // vrr.rid<<4 |0xe
+ st8 [r27]=r19
+ mov b0=r30
+ ;;
+ extr.u r16=r19,8,26
+ extr.u r18 =r19,2,6
+ mov r17 =0xe
+ ;;
+ shladd r16 = r16, 4, r17
+ extr.u r19 =r19,0,8
+ ;;
+ shl r16 = r16,8
+ ;;
+ add r19 = r19, r16
+ ;; //set ve 1
+ dep r19=-1,r19,0,1
+ cmp.lt p6,p0=14,r18
+ ;;
+ (p6) mov r18=14
+ ;;
+ (p6) dep r19=r18,r19,2,6
+ ;;
+ cmp.eq p6,p0=0,r23
+ ;;
+ cmp.eq.or p6,p0=4,r23
+ ;;
+ adds r16=VMM_VCPU_MODE_FLAGS_OFFSET,r21
+ (p6) adds r17=VMM_VCPU_META_SAVED_RR0_OFFSET,r21
+ ;;
+ ld4 r16=[r16]
+ cmp.eq p7,p0=r0,r0
+ (p6) shladd r17=r23,1,r17
+ ;;
+ (p6) st8 [r17]=r19
+ (p6) tbit.nz p6,p7=r16,0
+ ;;
+ (p7) mov rr[r28]=r19
+ mov r24=r22
+ br.many b0
+END(kvm_asm_mov_to_rr)
+
+
+//rsm
+GLOBAL_ENTRY(kvm_asm_rsm)
+#ifndef ACCE_RSM
+ br.many kvm_virtualization_fault_back
+#endif
+ add r16=VMM_VPD_BASE_OFFSET,r21
+ extr.u r26=r25,6,21
+ extr.u r27=r25,31,2
+ ;;
+ ld8 r16=[r16]
+ extr.u r28=r25,36,1
+ dep r26=r27,r26,21,2
+ ;;
+ add r17=VPD_VPSR_START_OFFSET,r16
+ add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21
+ //r26 is imm24
+ dep r26=r28,r26,23,1
+ ;;
+ ld8 r18=[r17]
+ movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI
+ ld4 r23=[r22]
+ sub r27=-1,r26
+ mov r24=b0
+ ;;
+ mov r20=cr.ipsr
+ or r28=r27,r28
+ and r19=r18,r27
+ ;;
+ st8 [r17]=r19
+ and r20=r20,r28
+ /* Comment it out due to short of fp lazy alorgithm support
+ adds r27=IA64_VCPU_FP_PSR_OFFSET,r21
+ ;;
+ ld8 r27=[r27]
+ ;;
+ tbit.nz p8,p0= r27,IA64_PSR_DFH_BIT
+ ;;
+ (p8) dep r20=-1,r20,IA64_PSR_DFH_BIT,1
+ */
+ ;;
+ mov cr.ipsr=r20
+ tbit.nz p6,p0=r23,0
+ ;;
+ tbit.z.or p6,p0=r26,IA64_PSR_DT_BIT
+ (p6) br.dptk kvm_resume_to_guest
+ ;;
+ add r26=VMM_VCPU_META_RR0_OFFSET,r21
+ add r27=VMM_VCPU_META_RR0_OFFSET+8,r21
+ dep r23=-1,r23,0,1
+ ;;
+ ld8 r26=[r26]
+ ld8 r27=[r27]
+ st4 [r22]=r23
+ dep.z r28=4,61,3
+ ;;
+ mov rr[r0]=r26
+ ;;
+ mov rr[r28]=r27
+ ;;
+ srlz.d
+ br.many kvm_resume_to_guest
+END(kvm_asm_rsm)
+
+
+//ssm
+GLOBAL_ENTRY(kvm_asm_ssm)
+#ifndef ACCE_SSM
+ br.many kvm_virtualization_fault_back
+#endif
+ add r16=VMM_VPD_BASE_OFFSET,r21
+ extr.u r26=r25,6,21
+ extr.u r27=r25,31,2
+ ;;
+ ld8 r16=[r16]
+ extr.u r28=r25,36,1
+ dep r26=r27,r26,21,2
+ ;; //r26 is imm24
+ add r27=VPD_VPSR_START_OFFSET,r16
+ dep r26=r28,r26,23,1
+ ;; //r19 vpsr
+ ld8 r29=[r27]
+ mov r24=b0
+ ;;
+ add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21
+ mov r20=cr.ipsr
+ or r19=r29,r26
+ ;;
+ ld4 r23=[r22]
+ st8 [r27]=r19
+ or r20=r20,r26
+ ;;
+ mov cr.ipsr=r20
+ movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT
+ ;;
+ and r19=r28,r19
+ tbit.z p6,p0=r23,0
+ ;;
+ cmp.ne.or p6,p0=r28,r19
+ (p6) br.dptk kvm_asm_ssm_1
+ ;;
+ add r26=VMM_VCPU_META_SAVED_RR0_OFFSET,r21
+ add r27=VMM_VCPU_META_SAVED_RR0_OFFSET+8,r21
+ dep r23=0,r23,0,1
+ ;;
+ ld8 r26=[r26]
+ ld8 r27=[r27]
+ st4 [r22]=r23
+ dep.z r28=4,61,3
+ ;;
+ mov rr[r0]=r26
+ ;;
+ mov rr[r28]=r27
+ ;;
+ srlz.d
+ ;;
+kvm_asm_ssm_1:
+ tbit.nz p6,p0=r29,IA64_PSR_I_BIT
+ ;;
+ tbit.z.or p6,p0=r19,IA64_PSR_I_BIT
+ (p6) br.dptk kvm_resume_to_guest
+ ;;
+ add r29=VPD_VTPR_START_OFFSET,r16
+ add r30=VPD_VHPI_START_OFFSET,r16
+ ;;
+ ld8 r29=[r29]
+ ld8 r30=[r30]
+ ;;
+ extr.u r17=r29,4,4
+ extr.u r18=r29,16,1
+ ;;
+ dep r17=r18,r17,4,1
+ ;;
+ cmp.gt p6,p0=r30,r17
+ (p6) br.dpnt.few kvm_asm_dispatch_vexirq
+ br.many kvm_resume_to_guest
+END(kvm_asm_ssm)
+
+
+//mov psr.l=r2
+GLOBAL_ENTRY(kvm_asm_mov_to_psr)
+#ifndef ACCE_MOV_TO_PSR
+ br.many kvm_virtualization_fault_back
+#endif
+ add r16=VMM_VPD_BASE_OFFSET,r21
+ extr.u r26=r25,13,7 //r2
+ ;;
+ ld8 r16=[r16]
+ addl r20=@gprel(asm_mov_from_reg),gp
+ ;;
+ adds r30=kvm_asm_mov_to_psr_back-asm_mov_from_reg,r20
+ shladd r26=r26,4,r20
+ mov r24=b0
+ ;;
+ add r27=VPD_VPSR_START_OFFSET,r16
+ mov b0=r26
+ br.many b0
+ ;;
+kvm_asm_mov_to_psr_back:
+ ld8 r17=[r27]
+ add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21
+ dep r19=0,r19,32,32
+ ;;
+ ld4 r23=[r22]
+ dep r18=0,r17,0,32
+ ;;
+ add r30=r18,r19
+ movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT
+ ;;
+ st8 [r27]=r30
+ and r27=r28,r30
+ and r29=r28,r17
+ ;;
+ cmp.eq p5,p0=r29,r27
+ cmp.eq p6,p7=r28,r27
+ (p5) br.many kvm_asm_mov_to_psr_1
+ ;;
+ //virtual to physical
+ (p7) add r26=VMM_VCPU_META_RR0_OFFSET,r21
+ (p7) add r27=VMM_VCPU_META_RR0_OFFSET+8,r21
+ (p7) dep r23=-1,r23,0,1
+ ;;
+ //physical to virtual
+ (p6) add r26=VMM_VCPU_META_SAVED_RR0_OFFSET,r21
+ (p6) add r27=VMM_VCPU_META_SAVED_RR0_OFFSET+8,r21
+ (p6) dep r23=0,r23,0,1
+ ;;
+ ld8 r26=[r26]
+ ld8 r27=[r27]
+ st4 [r22]=r23
+ dep.z r28=4,61,3
+ ;;
+ mov rr[r0]=r26
+ ;;
+ mov rr[r28]=r27
+ ;;
+ srlz.d
+ ;;
+kvm_asm_mov_to_psr_1:
+ mov r20=cr.ipsr
+ movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI+IA64_PSR_RT
+ ;;
+ or r19=r19,r28
+ dep r20=0,r20,0,32
+ ;;
+ add r20=r19,r20
+ mov b0=r24
+ ;;
+ /* Comment it out due to short of fp lazy algorithm support
+ adds r27=IA64_VCPU_FP_PSR_OFFSET,r21
+ ;;
+ ld8 r27=[r27]
+ ;;
+ tbit.nz p8,p0=r27,IA64_PSR_DFH_BIT
+ ;;
+ (p8) dep r20=-1,r20,IA64_PSR_DFH_BIT,1
+ ;;
+ */
+ mov cr.ipsr=r20
+ cmp.ne p6,p0=r0,r0
+ ;;
+ tbit.nz.or p6,p0=r17,IA64_PSR_I_BIT
+ tbit.z.or p6,p0=r30,IA64_PSR_I_BIT
+ (p6) br.dpnt.few kvm_resume_to_guest
+ ;;
+ add r29=VPD_VTPR_START_OFFSET,r16
+ add r30=VPD_VHPI_START_OFFSET,r16
+ ;;
+ ld8 r29=[r29]
+ ld8 r30=[r30]
+ ;;
+ extr.u r17=r29,4,4
+ extr.u r18=r29,16,1
+ ;;
+ dep r17=r18,r17,4,1
+ ;;
+ cmp.gt p6,p0=r30,r17
+ (p6) br.dpnt.few kvm_asm_dispatch_vexirq
+ br.many kvm_resume_to_guest
+END(kvm_asm_mov_to_psr)
+
+
+ENTRY(kvm_asm_dispatch_vexirq)
+//increment iip
+ mov r16=cr.ipsr
+ ;;
+ extr.u r17=r16,IA64_PSR_RI_BIT,2
+ tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1
+ ;;
+ (p6) mov r18=cr.iip
+ (p6) mov r17=r0
+ (p7) add r17=1,r17
+ ;;
+ (p6) add r18=0x10,r18
+ dep r16=r17,r16,IA64_PSR_RI_BIT,2
+ ;;
+ (p6) mov cr.iip=r18
+ mov cr.ipsr=r16
+ mov r30 =1
+ br.many kvm_dispatch_vexirq
+END(kvm_asm_dispatch_vexirq)
+
+// thash
+// TODO: add support when pta.vf = 1
+GLOBAL_ENTRY(kvm_asm_thash)
+#ifndef ACCE_THASH
+ br.many kvm_virtualization_fault_back
+#endif
+ extr.u r17=r25,20,7 // get r3 from opcode in r25
+ extr.u r18=r25,6,7 // get r1 from opcode in r25
+ addl r20=@gprel(asm_mov_from_reg),gp
+ ;;
+ adds r30=kvm_asm_thash_back1-asm_mov_from_reg,r20
+ shladd r17=r17,4,r20 // get addr of MOVE_FROM_REG(r17)
+ adds r16=VMM_VPD_BASE_OFFSET,r21 // get vcpu.arch.priveregs
+ ;;
+ mov r24=b0
+ ;;
+ ld8 r16=[r16] // get VPD addr
+ mov b0=r17
+ br.many b0 // r19 return value
+ ;;
+kvm_asm_thash_back1:
+ shr.u r23=r19,61 // get RR number
+ adds r25=VMM_VCPU_VRR0_OFFSET,r21 // get vcpu->arch.vrr[0]'s addr
+ adds r16=VMM_VPD_VPTA_OFFSET,r16 // get vpta
+ ;;
+ shladd r27=r23,3,r25 // get vcpu->arch.vrr[r23]'s addr
+ ld8 r17=[r16] // get PTA
+ mov r26=1
+ ;;
+ extr.u r29=r17,2,6 // get pta.size
+ ld8 r25=[r27] // get vcpu->arch.vrr[r23]'s value
+ ;;
+ extr.u r25=r25,2,6 // get rr.ps
+ shl r22=r26,r29 // 1UL << pta.size
+ ;;
+ shr.u r23=r19,r25 // vaddr >> rr.ps
+ adds r26=3,r29 // pta.size + 3
+ shl r27=r17,3 // pta << 3
+ ;;
+ shl r23=r23,3 // (vaddr >> rr.ps) << 3
+ shr.u r27=r27,r26 // (pta << 3) >> (pta.size+3)
+ movl r16=7<<61
+ ;;
+ adds r22=-1,r22 // (1UL << pta.size) - 1
+ shl r27=r27,r29 // ((pta<<3)>>(pta.size+3))<<pta.size
+ and r19=r19,r16 // vaddr & VRN_MASK
+ ;;
+ and r22=r22,r23 // vhpt_offset
+ or r19=r19,r27 // (vadr&VRN_MASK)|(((pta<<3)>>(pta.size + 3))<<pta.size)
+ adds r26=asm_mov_to_reg-asm_mov_from_reg,r20
+ ;;
+ or r19=r19,r22 // calc pval
+ shladd r17=r18,4,r26
+ adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20
+ ;;
+ mov b0=r17
+ br.many b0
+END(kvm_asm_thash)
+
+#define MOV_TO_REG0 \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ ;; \
+};
+
+
+#define MOV_TO_REG(n) \
+{; \
+ mov r##n##=r19; \
+ mov b0=r30; \
+ br.sptk.many b0; \
+ ;; \
+};
+
+
+#define MOV_FROM_REG(n) \
+{; \
+ mov r19=r##n##; \
+ mov b0=r30; \
+ br.sptk.many b0; \
+ ;; \
+};
+
+
+#define MOV_TO_BANK0_REG(n) \
+ENTRY_MIN_ALIGN(asm_mov_to_bank0_reg##n##); \
+{; \
+ mov r26=r2; \
+ mov r2=r19; \
+ bsw.1; \
+ ;; \
+}; \
+{; \
+ mov r##n##=r2; \
+ nop.b 0x0; \
+ bsw.0; \
+ ;; \
+}; \
+{; \
+ mov r2=r26; \
+ mov b0=r30; \
+ br.sptk.many b0; \
+ ;; \
+}; \
+END(asm_mov_to_bank0_reg##n##)
+
+
+#define MOV_FROM_BANK0_REG(n) \
+ENTRY_MIN_ALIGN(asm_mov_from_bank0_reg##n##); \
+{; \
+ mov r26=r2; \
+ nop.b 0x0; \
+ bsw.1; \
+ ;; \
+}; \
+{; \
+ mov r2=r##n##; \
+ nop.b 0x0; \
+ bsw.0; \
+ ;; \
+}; \
+{; \
+ mov r19=r2; \
+ mov r2=r26; \
+ mov b0=r30; \
+}; \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ br.sptk.many b0; \
+ ;; \
+}; \
+END(asm_mov_from_bank0_reg##n##)
+
+
+#define JMP_TO_MOV_TO_BANK0_REG(n) \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ br.sptk.many asm_mov_to_bank0_reg##n##; \
+ ;; \
+}
+
+
+#define JMP_TO_MOV_FROM_BANK0_REG(n) \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ br.sptk.many asm_mov_from_bank0_reg##n##; \
+ ;; \
+}
+
+
+MOV_FROM_BANK0_REG(16)
+MOV_FROM_BANK0_REG(17)
+MOV_FROM_BANK0_REG(18)
+MOV_FROM_BANK0_REG(19)
+MOV_FROM_BANK0_REG(20)
+MOV_FROM_BANK0_REG(21)
+MOV_FROM_BANK0_REG(22)
+MOV_FROM_BANK0_REG(23)
+MOV_FROM_BANK0_REG(24)
+MOV_FROM_BANK0_REG(25)
+MOV_FROM_BANK0_REG(26)
+MOV_FROM_BANK0_REG(27)
+MOV_FROM_BANK0_REG(28)
+MOV_FROM_BANK0_REG(29)
+MOV_FROM_BANK0_REG(30)
+MOV_FROM_BANK0_REG(31)
+
+
+// mov from reg table
+ENTRY(asm_mov_from_reg)
+ MOV_FROM_REG(0)
+ MOV_FROM_REG(1)
+ MOV_FROM_REG(2)
+ MOV_FROM_REG(3)
+ MOV_FROM_REG(4)
+ MOV_FROM_REG(5)
+ MOV_FROM_REG(6)
+ MOV_FROM_REG(7)
+ MOV_FROM_REG(8)
+ MOV_FROM_REG(9)
+ MOV_FROM_REG(10)
+ MOV_FROM_REG(11)
+ MOV_FROM_REG(12)
+ MOV_FROM_REG(13)
+ MOV_FROM_REG(14)
+ MOV_FROM_REG(15)
+ JMP_TO_MOV_FROM_BANK0_REG(16)
+ JMP_TO_MOV_FROM_BANK0_REG(17)
+ JMP_TO_MOV_FROM_BANK0_REG(18)
+ JMP_TO_MOV_FROM_BANK0_REG(19)
+ JMP_TO_MOV_FROM_BANK0_REG(20)
+ JMP_TO_MOV_FROM_BANK0_REG(21)
+ JMP_TO_MOV_FROM_BANK0_REG(22)
+ JMP_TO_MOV_FROM_BANK0_REG(23)
+ JMP_TO_MOV_FROM_BANK0_REG(24)
+ JMP_TO_MOV_FROM_BANK0_REG(25)
+ JMP_TO_MOV_FROM_BANK0_REG(26)
+ JMP_TO_MOV_FROM_BANK0_REG(27)
+ JMP_TO_MOV_FROM_BANK0_REG(28)
+ JMP_TO_MOV_FROM_BANK0_REG(29)
+ JMP_TO_MOV_FROM_BANK0_REG(30)
+ JMP_TO_MOV_FROM_BANK0_REG(31)
+ MOV_FROM_REG(32)
+ MOV_FROM_REG(33)
+ MOV_FROM_REG(34)
+ MOV_FROM_REG(35)
+ MOV_FROM_REG(36)
+ MOV_FROM_REG(37)
+ MOV_FROM_REG(38)
+ MOV_FROM_REG(39)
+ MOV_FROM_REG(40)
+ MOV_FROM_REG(41)
+ MOV_FROM_REG(42)
+ MOV_FROM_REG(43)
+ MOV_FROM_REG(44)
+ MOV_FROM_REG(45)
+ MOV_FROM_REG(46)
+ MOV_FROM_REG(47)
+ MOV_FROM_REG(48)
+ MOV_FROM_REG(49)
+ MOV_FROM_REG(50)
+ MOV_FROM_REG(51)
+ MOV_FROM_REG(52)
+ MOV_FROM_REG(53)
+ MOV_FROM_REG(54)
+ MOV_FROM_REG(55)
+ MOV_FROM_REG(56)
+ MOV_FROM_REG(57)
+ MOV_FROM_REG(58)
+ MOV_FROM_REG(59)
+ MOV_FROM_REG(60)
+ MOV_FROM_REG(61)
+ MOV_FROM_REG(62)
+ MOV_FROM_REG(63)
+ MOV_FROM_REG(64)
+ MOV_FROM_REG(65)
+ MOV_FROM_REG(66)
+ MOV_FROM_REG(67)
+ MOV_FROM_REG(68)
+ MOV_FROM_REG(69)
+ MOV_FROM_REG(70)
+ MOV_FROM_REG(71)
+ MOV_FROM_REG(72)
+ MOV_FROM_REG(73)
+ MOV_FROM_REG(74)
+ MOV_FROM_REG(75)
+ MOV_FROM_REG(76)
+ MOV_FROM_REG(77)
+ MOV_FROM_REG(78)
+ MOV_FROM_REG(79)
+ MOV_FROM_REG(80)
+ MOV_FROM_REG(81)
+ MOV_FROM_REG(82)
+ MOV_FROM_REG(83)
+ MOV_FROM_REG(84)
+ MOV_FROM_REG(85)
+ MOV_FROM_REG(86)
+ MOV_FROM_REG(87)
+ MOV_FROM_REG(88)
+ MOV_FROM_REG(89)
+ MOV_FROM_REG(90)
+ MOV_FROM_REG(91)
+ MOV_FROM_REG(92)
+ MOV_FROM_REG(93)
+ MOV_FROM_REG(94)
+ MOV_FROM_REG(95)
+ MOV_FROM_REG(96)
+ MOV_FROM_REG(97)
+ MOV_FROM_REG(98)
+ MOV_FROM_REG(99)
+ MOV_FROM_REG(100)
+ MOV_FROM_REG(101)
+ MOV_FROM_REG(102)
+ MOV_FROM_REG(103)
+ MOV_FROM_REG(104)
+ MOV_FROM_REG(105)
+ MOV_FROM_REG(106)
+ MOV_FROM_REG(107)
+ MOV_FROM_REG(108)
+ MOV_FROM_REG(109)
+ MOV_FROM_REG(110)
+ MOV_FROM_REG(111)
+ MOV_FROM_REG(112)
+ MOV_FROM_REG(113)
+ MOV_FROM_REG(114)
+ MOV_FROM_REG(115)
+ MOV_FROM_REG(116)
+ MOV_FROM_REG(117)
+ MOV_FROM_REG(118)
+ MOV_FROM_REG(119)
+ MOV_FROM_REG(120)
+ MOV_FROM_REG(121)
+ MOV_FROM_REG(122)
+ MOV_FROM_REG(123)
+ MOV_FROM_REG(124)
+ MOV_FROM_REG(125)
+ MOV_FROM_REG(126)
+ MOV_FROM_REG(127)
+END(asm_mov_from_reg)
+
+
+/* must be in bank 0
+ * parameter:
+ * r31: pr
+ * r24: b0
+ */
+ENTRY(kvm_resume_to_guest)
+ adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21
+ ;;
+ ld8 r1 =[r16]
+ adds r20 = VMM_VCPU_VSA_BASE_OFFSET,r21
+ ;;
+ mov r16=cr.ipsr
+ ;;
+ ld8 r20 = [r20]
+ adds r19=VMM_VPD_BASE_OFFSET,r21
+ ;;
+ ld8 r25=[r19]
+ extr.u r17=r16,IA64_PSR_RI_BIT,2
+ tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1
+ ;;
+ (p6) mov r18=cr.iip
+ (p6) mov r17=r0
+ ;;
+ (p6) add r18=0x10,r18
+ (p7) add r17=1,r17
+ ;;
+ (p6) mov cr.iip=r18
+ dep r16=r17,r16,IA64_PSR_RI_BIT,2
+ ;;
+ mov cr.ipsr=r16
+ adds r19= VPD_VPSR_START_OFFSET,r25
+ add r28=PAL_VPS_RESUME_NORMAL,r20
+ add r29=PAL_VPS_RESUME_HANDLER,r20
+ ;;
+ ld8 r19=[r19]
+ mov b0=r29
+ cmp.ne p6,p7 = r0,r0
+ ;;
+ tbit.z p6,p7 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic
+ ;;
+ (p6) ld8 r26=[r25]
+ (p7) mov b0=r28
+ mov pr=r31,-2
+ br.sptk.many b0 // call pal service
+ ;;
+END(kvm_resume_to_guest)
+
+
+MOV_TO_BANK0_REG(16)
+MOV_TO_BANK0_REG(17)
+MOV_TO_BANK0_REG(18)
+MOV_TO_BANK0_REG(19)
+MOV_TO_BANK0_REG(20)
+MOV_TO_BANK0_REG(21)
+MOV_TO_BANK0_REG(22)
+MOV_TO_BANK0_REG(23)
+MOV_TO_BANK0_REG(24)
+MOV_TO_BANK0_REG(25)
+MOV_TO_BANK0_REG(26)
+MOV_TO_BANK0_REG(27)
+MOV_TO_BANK0_REG(28)
+MOV_TO_BANK0_REG(29)
+MOV_TO_BANK0_REG(30)
+MOV_TO_BANK0_REG(31)
+
+
+// mov to reg table
+ENTRY(asm_mov_to_reg)
+ MOV_TO_REG0
+ MOV_TO_REG(1)
+ MOV_TO_REG(2)
+ MOV_TO_REG(3)
+ MOV_TO_REG(4)
+ MOV_TO_REG(5)
+ MOV_TO_REG(6)
+ MOV_TO_REG(7)
+ MOV_TO_REG(8)
+ MOV_TO_REG(9)
+ MOV_TO_REG(10)
+ MOV_TO_REG(11)
+ MOV_TO_REG(12)
+ MOV_TO_REG(13)
+ MOV_TO_REG(14)
+ MOV_TO_REG(15)
+ JMP_TO_MOV_TO_BANK0_REG(16)
+ JMP_TO_MOV_TO_BANK0_REG(17)
+ JMP_TO_MOV_TO_BANK0_REG(18)
+ JMP_TO_MOV_TO_BANK0_REG(19)
+ JMP_TO_MOV_TO_BANK0_REG(20)
+ JMP_TO_MOV_TO_BANK0_REG(21)
+ JMP_TO_MOV_TO_BANK0_REG(22)
+ JMP_TO_MOV_TO_BANK0_REG(23)
+ JMP_TO_MOV_TO_BANK0_REG(24)
+ JMP_TO_MOV_TO_BANK0_REG(25)
+ JMP_TO_MOV_TO_BANK0_REG(26)
+ JMP_TO_MOV_TO_BANK0_REG(27)
+ JMP_TO_MOV_TO_BANK0_REG(28)
+ JMP_TO_MOV_TO_BANK0_REG(29)
+ JMP_TO_MOV_TO_BANK0_REG(30)
+ JMP_TO_MOV_TO_BANK0_REG(31)
+ MOV_TO_REG(32)
+ MOV_TO_REG(33)
+ MOV_TO_REG(34)
+ MOV_TO_REG(35)
+ MOV_TO_REG(36)
+ MOV_TO_REG(37)
+ MOV_TO_REG(38)
+ MOV_TO_REG(39)
+ MOV_TO_REG(40)
+ MOV_TO_REG(41)
+ MOV_TO_REG(42)
+ MOV_TO_REG(43)
+ MOV_TO_REG(44)
+ MOV_TO_REG(45)
+ MOV_TO_REG(46)
+ MOV_TO_REG(47)
+ MOV_TO_REG(48)
+ MOV_TO_REG(49)
+ MOV_TO_REG(50)
+ MOV_TO_REG(51)
+ MOV_TO_REG(52)
+ MOV_TO_REG(53)
+ MOV_TO_REG(54)
+ MOV_TO_REG(55)
+ MOV_TO_REG(56)
+ MOV_TO_REG(57)
+ MOV_TO_REG(58)
+ MOV_TO_REG(59)
+ MOV_TO_REG(60)
+ MOV_TO_REG(61)
+ MOV_TO_REG(62)
+ MOV_TO_REG(63)
+ MOV_TO_REG(64)
+ MOV_TO_REG(65)
+ MOV_TO_REG(66)
+ MOV_TO_REG(67)
+ MOV_TO_REG(68)
+ MOV_TO_REG(69)
+ MOV_TO_REG(70)
+ MOV_TO_REG(71)
+ MOV_TO_REG(72)
+ MOV_TO_REG(73)
+ MOV_TO_REG(74)
+ MOV_TO_REG(75)
+ MOV_TO_REG(76)
+ MOV_TO_REG(77)
+ MOV_TO_REG(78)
+ MOV_TO_REG(79)
+ MOV_TO_REG(80)
+ MOV_TO_REG(81)
+ MOV_TO_REG(82)
+ MOV_TO_REG(83)
+ MOV_TO_REG(84)
+ MOV_TO_REG(85)
+ MOV_TO_REG(86)
+ MOV_TO_REG(87)
+ MOV_TO_REG(88)
+ MOV_TO_REG(89)
+ MOV_TO_REG(90)
+ MOV_TO_REG(91)
+ MOV_TO_REG(92)
+ MOV_TO_REG(93)
+ MOV_TO_REG(94)
+ MOV_TO_REG(95)
+ MOV_TO_REG(96)
+ MOV_TO_REG(97)
+ MOV_TO_REG(98)
+ MOV_TO_REG(99)
+ MOV_TO_REG(100)
+ MOV_TO_REG(101)
+ MOV_TO_REG(102)
+ MOV_TO_REG(103)
+ MOV_TO_REG(104)
+ MOV_TO_REG(105)
+ MOV_TO_REG(106)
+ MOV_TO_REG(107)
+ MOV_TO_REG(108)
+ MOV_TO_REG(109)
+ MOV_TO_REG(110)
+ MOV_TO_REG(111)
+ MOV_TO_REG(112)
+ MOV_TO_REG(113)
+ MOV_TO_REG(114)
+ MOV_TO_REG(115)
+ MOV_TO_REG(116)
+ MOV_TO_REG(117)
+ MOV_TO_REG(118)
+ MOV_TO_REG(119)
+ MOV_TO_REG(120)
+ MOV_TO_REG(121)
+ MOV_TO_REG(122)
+ MOV_TO_REG(123)
+ MOV_TO_REG(124)
+ MOV_TO_REG(125)
+ MOV_TO_REG(126)
+ MOV_TO_REG(127)
+END(asm_mov_to_reg)
diff --git a/arch/ia64/kvm/process.c b/arch/ia64/kvm/process.c
new file mode 100644
index 000000000000..5a33f7ed29a0
--- /dev/null
+++ b/arch/ia64/kvm/process.c
@@ -0,0 +1,970 @@
+/*
+ * process.c: handle interruption inject for guests.
+ * Copyright (c) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Shaofan Li (Susue Li) <susie.li@intel.com>
+ * Xiaoyan Feng (Fleming Feng) <fleming.feng@intel.com>
+ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ */
+#include "vcpu.h"
+
+#include <asm/pal.h>
+#include <asm/sal.h>
+#include <asm/fpswa.h>
+#include <asm/kregs.h>
+#include <asm/tlb.h>
+
+fpswa_interface_t *vmm_fpswa_interface;
+
+#define IA64_VHPT_TRANS_VECTOR 0x0000
+#define IA64_INST_TLB_VECTOR 0x0400
+#define IA64_DATA_TLB_VECTOR 0x0800
+#define IA64_ALT_INST_TLB_VECTOR 0x0c00
+#define IA64_ALT_DATA_TLB_VECTOR 0x1000
+#define IA64_DATA_NESTED_TLB_VECTOR 0x1400
+#define IA64_INST_KEY_MISS_VECTOR 0x1800
+#define IA64_DATA_KEY_MISS_VECTOR 0x1c00
+#define IA64_DIRTY_BIT_VECTOR 0x2000
+#define IA64_INST_ACCESS_BIT_VECTOR 0x2400
+#define IA64_DATA_ACCESS_BIT_VECTOR 0x2800
+#define IA64_BREAK_VECTOR 0x2c00
+#define IA64_EXTINT_VECTOR 0x3000
+#define IA64_PAGE_NOT_PRESENT_VECTOR 0x5000
+#define IA64_KEY_PERMISSION_VECTOR 0x5100
+#define IA64_INST_ACCESS_RIGHTS_VECTOR 0x5200
+#define IA64_DATA_ACCESS_RIGHTS_VECTOR 0x5300
+#define IA64_GENEX_VECTOR 0x5400
+#define IA64_DISABLED_FPREG_VECTOR 0x5500
+#define IA64_NAT_CONSUMPTION_VECTOR 0x5600
+#define IA64_SPECULATION_VECTOR 0x5700 /* UNUSED */
+#define IA64_DEBUG_VECTOR 0x5900
+#define IA64_UNALIGNED_REF_VECTOR 0x5a00
+#define IA64_UNSUPPORTED_DATA_REF_VECTOR 0x5b00
+#define IA64_FP_FAULT_VECTOR 0x5c00
+#define IA64_FP_TRAP_VECTOR 0x5d00
+#define IA64_LOWERPRIV_TRANSFER_TRAP_VECTOR 0x5e00
+#define IA64_TAKEN_BRANCH_TRAP_VECTOR 0x5f00
+#define IA64_SINGLE_STEP_TRAP_VECTOR 0x6000
+
+/* SDM vol2 5.5 - IVA based interruption handling */
+#define INITIAL_PSR_VALUE_AT_INTERRUPTION (IA64_PSR_UP | IA64_PSR_MFL |\
+ IA64_PSR_MFH | IA64_PSR_PK | IA64_PSR_DT | \
+ IA64_PSR_RT | IA64_PSR_MC|IA64_PSR_IT)
+
+#define DOMN_PAL_REQUEST 0x110000
+#define DOMN_SAL_REQUEST 0x110001
+
+static u64 vec2off[68] = {0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800,
+ 0x1c00, 0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00,
+ 0x4000, 0x4400, 0x4800, 0x4c00, 0x5000, 0x5100, 0x5200, 0x5300, 0x5400,
+ 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5a00, 0x5b00, 0x5c00, 0x5d00,
+ 0x5e00, 0x5f00, 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600,
+ 0x6700, 0x6800, 0x6900, 0x6a00, 0x6b00, 0x6c00, 0x6d00, 0x6e00, 0x6f00,
+ 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, 0x7800,
+ 0x7900, 0x7a00, 0x7b00, 0x7c00, 0x7d00, 0x7e00, 0x7f00
+};
+
+static void collect_interruption(struct kvm_vcpu *vcpu)
+{
+ u64 ipsr;
+ u64 vdcr;
+ u64 vifs;
+ unsigned long vpsr;
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ vpsr = vcpu_get_psr(vcpu);
+ vcpu_bsw0(vcpu);
+ if (vpsr & IA64_PSR_IC) {
+
+ /* Sync mpsr id/da/dd/ss/ed bits to vipsr
+ * since after guest do rfi, we still want these bits on in
+ * mpsr
+ */
+
+ ipsr = regs->cr_ipsr;
+ vpsr = vpsr | (ipsr & (IA64_PSR_ID | IA64_PSR_DA
+ | IA64_PSR_DD | IA64_PSR_SS
+ | IA64_PSR_ED));
+ vcpu_set_ipsr(vcpu, vpsr);
+
+ /* Currently, for trap, we do not advance IIP to next
+ * instruction. That's because we assume caller already
+ * set up IIP correctly
+ */
+
+ vcpu_set_iip(vcpu , regs->cr_iip);
+
+ /* set vifs.v to zero */
+ vifs = VCPU(vcpu, ifs);
+ vifs &= ~IA64_IFS_V;
+ vcpu_set_ifs(vcpu, vifs);
+
+ vcpu_set_iipa(vcpu, VMX(vcpu, cr_iipa));
+ }
+
+ vdcr = VCPU(vcpu, dcr);
+
+ /* Set guest psr
+ * up/mfl/mfh/pk/dt/rt/mc/it keeps unchanged
+ * be: set to the value of dcr.be
+ * pp: set to the value of dcr.pp
+ */
+ vpsr &= INITIAL_PSR_VALUE_AT_INTERRUPTION;
+ vpsr |= (vdcr & IA64_DCR_BE);
+
+ /* VDCR pp bit position is different from VPSR pp bit */
+ if (vdcr & IA64_DCR_PP) {
+ vpsr |= IA64_PSR_PP;
+ } else {
+ vpsr &= ~IA64_PSR_PP;;
+ }
+
+ vcpu_set_psr(vcpu, vpsr);
+
+}
+
+void inject_guest_interruption(struct kvm_vcpu *vcpu, u64 vec)
+{
+ u64 viva;
+ struct kvm_pt_regs *regs;
+ union ia64_isr pt_isr;
+
+ regs = vcpu_regs(vcpu);
+
+ /* clear cr.isr.ir (incomplete register frame)*/
+ pt_isr.val = VMX(vcpu, cr_isr);
+ pt_isr.ir = 0;
+ VMX(vcpu, cr_isr) = pt_isr.val;
+
+ collect_interruption(vcpu);
+
+ viva = vcpu_get_iva(vcpu);
+ regs->cr_iip = viva + vec;
+}
+
+static u64 vcpu_get_itir_on_fault(struct kvm_vcpu *vcpu, u64 ifa)
+{
+ union ia64_rr rr, rr1;
+
+ rr.val = vcpu_get_rr(vcpu, ifa);
+ rr1.val = 0;
+ rr1.ps = rr.ps;
+ rr1.rid = rr.rid;
+ return (rr1.val);
+}
+
+
+/*
+ * Set vIFA & vITIR & vIHA, when vPSR.ic =1
+ * Parameter:
+ * set_ifa: if true, set vIFA
+ * set_itir: if true, set vITIR
+ * set_iha: if true, set vIHA
+ */
+void set_ifa_itir_iha(struct kvm_vcpu *vcpu, u64 vadr,
+ int set_ifa, int set_itir, int set_iha)
+{
+ long vpsr;
+ u64 value;
+
+ vpsr = VCPU(vcpu, vpsr);
+ /* Vol2, Table 8-1 */
+ if (vpsr & IA64_PSR_IC) {
+ if (set_ifa)
+ vcpu_set_ifa(vcpu, vadr);
+ if (set_itir) {
+ value = vcpu_get_itir_on_fault(vcpu, vadr);
+ vcpu_set_itir(vcpu, value);
+ }
+
+ if (set_iha) {
+ value = vcpu_thash(vcpu, vadr);
+ vcpu_set_iha(vcpu, value);
+ }
+ }
+}
+
+/*
+ * Data TLB Fault
+ * @ Data TLB vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void dtlb_fault(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ /* If vPSR.ic, IFA, ITIR, IHA */
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 1);
+ inject_guest_interruption(vcpu, IA64_DATA_TLB_VECTOR);
+}
+
+/*
+ * Instruction TLB Fault
+ * @ Instruction TLB vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void itlb_fault(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ /* If vPSR.ic, IFA, ITIR, IHA */
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 1);
+ inject_guest_interruption(vcpu, IA64_INST_TLB_VECTOR);
+}
+
+
+
+/*
+ * Data Nested TLB Fault
+ * @ Data Nested TLB Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void nested_dtlb(struct kvm_vcpu *vcpu)
+{
+ inject_guest_interruption(vcpu, IA64_DATA_NESTED_TLB_VECTOR);
+}
+
+/*
+ * Alternate Data TLB Fault
+ * @ Alternate Data TLB vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void alt_dtlb(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 0);
+ inject_guest_interruption(vcpu, IA64_ALT_DATA_TLB_VECTOR);
+}
+
+
+/*
+ * Data TLB Fault
+ * @ Data TLB vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void alt_itlb(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 0);
+ inject_guest_interruption(vcpu, IA64_ALT_INST_TLB_VECTOR);
+}
+
+/* Deal with:
+ * VHPT Translation Vector
+ */
+static void _vhpt_fault(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ /* If vPSR.ic, IFA, ITIR, IHA*/
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 1);
+ inject_guest_interruption(vcpu, IA64_VHPT_TRANS_VECTOR);
+
+
+}
+
+/*
+ * VHPT Instruction Fault
+ * @ VHPT Translation vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void ivhpt_fault(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ _vhpt_fault(vcpu, vadr);
+}
+
+
+/*
+ * VHPT Data Fault
+ * @ VHPT Translation vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void dvhpt_fault(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ _vhpt_fault(vcpu, vadr);
+}
+
+
+
+/*
+ * Deal with:
+ * General Exception vector
+ */
+void _general_exception(struct kvm_vcpu *vcpu)
+{
+ inject_guest_interruption(vcpu, IA64_GENEX_VECTOR);
+}
+
+
+/*
+ * Illegal Operation Fault
+ * @ General Exception Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void illegal_op(struct kvm_vcpu *vcpu)
+{
+ _general_exception(vcpu);
+}
+
+/*
+ * Illegal Dependency Fault
+ * @ General Exception Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void illegal_dep(struct kvm_vcpu *vcpu)
+{
+ _general_exception(vcpu);
+}
+
+/*
+ * Reserved Register/Field Fault
+ * @ General Exception Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void rsv_reg_field(struct kvm_vcpu *vcpu)
+{
+ _general_exception(vcpu);
+}
+/*
+ * Privileged Operation Fault
+ * @ General Exception Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+
+void privilege_op(struct kvm_vcpu *vcpu)
+{
+ _general_exception(vcpu);
+}
+
+/*
+ * Unimplement Data Address Fault
+ * @ General Exception Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void unimpl_daddr(struct kvm_vcpu *vcpu)
+{
+ _general_exception(vcpu);
+}
+
+/*
+ * Privileged Register Fault
+ * @ General Exception Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void privilege_reg(struct kvm_vcpu *vcpu)
+{
+ _general_exception(vcpu);
+}
+
+/* Deal with
+ * Nat consumption vector
+ * Parameter:
+ * vaddr: Optional, if t == REGISTER
+ */
+static void _nat_consumption_fault(struct kvm_vcpu *vcpu, u64 vadr,
+ enum tlb_miss_type t)
+{
+ /* If vPSR.ic && t == DATA/INST, IFA */
+ if (t == DATA || t == INSTRUCTION) {
+ /* IFA */
+ set_ifa_itir_iha(vcpu, vadr, 1, 0, 0);
+ }
+
+ inject_guest_interruption(vcpu, IA64_NAT_CONSUMPTION_VECTOR);
+}
+
+/*
+ * Instruction Nat Page Consumption Fault
+ * @ Nat Consumption Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void inat_page_consumption(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ _nat_consumption_fault(vcpu, vadr, INSTRUCTION);
+}
+
+/*
+ * Register Nat Consumption Fault
+ * @ Nat Consumption Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void rnat_consumption(struct kvm_vcpu *vcpu)
+{
+ _nat_consumption_fault(vcpu, 0, REGISTER);
+}
+
+/*
+ * Data Nat Page Consumption Fault
+ * @ Nat Consumption Vector
+ * Refer to SDM Vol2 Table 5-6 & 8-1
+ */
+void dnat_page_consumption(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ _nat_consumption_fault(vcpu, vadr, DATA);
+}
+
+/* Deal with
+ * Page not present vector
+ */
+static void __page_not_present(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ /* If vPSR.ic, IFA, ITIR */
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 0);
+ inject_guest_interruption(vcpu, IA64_PAGE_NOT_PRESENT_VECTOR);
+}
+
+
+void data_page_not_present(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ __page_not_present(vcpu, vadr);
+}
+
+
+void inst_page_not_present(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ __page_not_present(vcpu, vadr);
+}
+
+
+/* Deal with
+ * Data access rights vector
+ */
+void data_access_rights(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ /* If vPSR.ic, IFA, ITIR */
+ set_ifa_itir_iha(vcpu, vadr, 1, 1, 0);
+ inject_guest_interruption(vcpu, IA64_DATA_ACCESS_RIGHTS_VECTOR);
+}
+
+fpswa_ret_t vmm_fp_emulate(int fp_fault, void *bundle, unsigned long *ipsr,
+ unsigned long *fpsr, unsigned long *isr, unsigned long *pr,
+ unsigned long *ifs, struct kvm_pt_regs *regs)
+{
+ fp_state_t fp_state;
+ fpswa_ret_t ret;
+ struct kvm_vcpu *vcpu = current_vcpu;
+
+ uint64_t old_rr7 = ia64_get_rr(7UL<<61);
+
+ if (!vmm_fpswa_interface)
+ return (fpswa_ret_t) {-1, 0, 0, 0};
+
+ /*
+ * Just let fpswa driver to use hardware fp registers.
+ * No fp register is valid in memory.
+ */
+ memset(&fp_state, 0, sizeof(fp_state_t));
+
+ /*
+ * unsigned long (*EFI_FPSWA) (
+ * unsigned long trap_type,
+ * void *Bundle,
+ * unsigned long *pipsr,
+ * unsigned long *pfsr,
+ * unsigned long *pisr,
+ * unsigned long *ppreds,
+ * unsigned long *pifs,
+ * void *fp_state);
+ */
+ /*Call host fpswa interface directly to virtualize
+ *guest fpswa request!
+ */
+ ia64_set_rr(7UL << 61, vcpu->arch.host.rr[7]);
+ ia64_srlz_d();
+
+ ret = (*vmm_fpswa_interface->fpswa) (fp_fault, bundle,
+ ipsr, fpsr, isr, pr, ifs, &fp_state);
+ ia64_set_rr(7UL << 61, old_rr7);
+ ia64_srlz_d();
+ return ret;
+}
+
+/*
+ * Handle floating-point assist faults and traps for domain.
+ */
+unsigned long vmm_handle_fpu_swa(int fp_fault, struct kvm_pt_regs *regs,
+ unsigned long isr)
+{
+ struct kvm_vcpu *v = current_vcpu;
+ IA64_BUNDLE bundle;
+ unsigned long fault_ip;
+ fpswa_ret_t ret;
+
+ fault_ip = regs->cr_iip;
+ /*
+ * When the FP trap occurs, the trapping instruction is completed.
+ * If ipsr.ri == 0, there is the trapping instruction in previous
+ * bundle.
+ */
+ if (!fp_fault && (ia64_psr(regs)->ri == 0))
+ fault_ip -= 16;
+
+ if (fetch_code(v, fault_ip, &bundle))
+ return -EAGAIN;
+
+ if (!bundle.i64[0] && !bundle.i64[1])
+ return -EACCES;
+
+ ret = vmm_fp_emulate(fp_fault, &bundle, &regs->cr_ipsr, &regs->ar_fpsr,
+ &isr, &regs->pr, &regs->cr_ifs, regs);
+ return ret.status;
+}
+
+void reflect_interruption(u64 ifa, u64 isr, u64 iim,
+ u64 vec, struct kvm_pt_regs *regs)
+{
+ u64 vector;
+ int status ;
+ struct kvm_vcpu *vcpu = current_vcpu;
+ u64 vpsr = VCPU(vcpu, vpsr);
+
+ vector = vec2off[vec];
+
+ if (!(vpsr & IA64_PSR_IC) && (vector != IA64_DATA_NESTED_TLB_VECTOR)) {
+ panic_vm(vcpu);
+ return;
+ }
+
+ switch (vec) {
+ case 32: /*IA64_FP_FAULT_VECTOR*/
+ status = vmm_handle_fpu_swa(1, regs, isr);
+ if (!status) {
+ vcpu_increment_iip(vcpu);
+ return;
+ } else if (-EAGAIN == status)
+ return;
+ break;
+ case 33: /*IA64_FP_TRAP_VECTOR*/
+ status = vmm_handle_fpu_swa(0, regs, isr);
+ if (!status)
+ return ;
+ else if (-EAGAIN == status) {
+ vcpu_decrement_iip(vcpu);
+ return ;
+ }
+ break;
+ }
+
+ VCPU(vcpu, isr) = isr;
+ VCPU(vcpu, iipa) = regs->cr_iip;
+ if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR)
+ VCPU(vcpu, iim) = iim;
+ else
+ set_ifa_itir_iha(vcpu, ifa, 1, 1, 1);
+
+ inject_guest_interruption(vcpu, vector);
+}
+
+static void set_pal_call_data(struct kvm_vcpu *vcpu)
+{
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+
+ /*FIXME:For static and stacked convention, firmware
+ * has put the parameters in gr28-gr31 before
+ * break to vmm !!*/
+
+ p->u.pal_data.gr28 = vcpu_get_gr(vcpu, 28);
+ p->u.pal_data.gr29 = vcpu_get_gr(vcpu, 29);
+ p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30);
+ p->u.pal_data.gr31 = vcpu_get_gr(vcpu, 31);
+ p->exit_reason = EXIT_REASON_PAL_CALL;
+}
+
+static void set_pal_call_result(struct kvm_vcpu *vcpu)
+{
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+
+ if (p->exit_reason == EXIT_REASON_PAL_CALL) {
+ vcpu_set_gr(vcpu, 8, p->u.pal_data.ret.status, 0);
+ vcpu_set_gr(vcpu, 9, p->u.pal_data.ret.v0, 0);
+ vcpu_set_gr(vcpu, 10, p->u.pal_data.ret.v1, 0);
+ vcpu_set_gr(vcpu, 11, p->u.pal_data.ret.v2, 0);
+ } else
+ panic_vm(vcpu);
+}
+
+static void set_sal_call_data(struct kvm_vcpu *vcpu)
+{
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+
+ p->u.sal_data.in0 = vcpu_get_gr(vcpu, 32);
+ p->u.sal_data.in1 = vcpu_get_gr(vcpu, 33);
+ p->u.sal_data.in2 = vcpu_get_gr(vcpu, 34);
+ p->u.sal_data.in3 = vcpu_get_gr(vcpu, 35);
+ p->u.sal_data.in4 = vcpu_get_gr(vcpu, 36);
+ p->u.sal_data.in5 = vcpu_get_gr(vcpu, 37);
+ p->u.sal_data.in6 = vcpu_get_gr(vcpu, 38);
+ p->u.sal_data.in7 = vcpu_get_gr(vcpu, 39);
+ p->exit_reason = EXIT_REASON_SAL_CALL;
+}
+
+static void set_sal_call_result(struct kvm_vcpu *vcpu)
+{
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+
+ if (p->exit_reason == EXIT_REASON_SAL_CALL) {
+ vcpu_set_gr(vcpu, 8, p->u.sal_data.ret.r8, 0);
+ vcpu_set_gr(vcpu, 9, p->u.sal_data.ret.r9, 0);
+ vcpu_set_gr(vcpu, 10, p->u.sal_data.ret.r10, 0);
+ vcpu_set_gr(vcpu, 11, p->u.sal_data.ret.r11, 0);
+ } else
+ panic_vm(vcpu);
+}
+
+void kvm_ia64_handle_break(unsigned long ifa, struct kvm_pt_regs *regs,
+ unsigned long isr, unsigned long iim)
+{
+ struct kvm_vcpu *v = current_vcpu;
+
+ if (ia64_psr(regs)->cpl == 0) {
+ /* Allow hypercalls only when cpl = 0. */
+ if (iim == DOMN_PAL_REQUEST) {
+ set_pal_call_data(v);
+ vmm_transition(v);
+ set_pal_call_result(v);
+ vcpu_increment_iip(v);
+ return;
+ } else if (iim == DOMN_SAL_REQUEST) {
+ set_sal_call_data(v);
+ vmm_transition(v);
+ set_sal_call_result(v);
+ vcpu_increment_iip(v);
+ return;
+ }
+ }
+ reflect_interruption(ifa, isr, iim, 11, regs);
+}
+
+void check_pending_irq(struct kvm_vcpu *vcpu)
+{
+ int mask, h_pending, h_inservice;
+ u64 isr;
+ unsigned long vpsr;
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ h_pending = highest_pending_irq(vcpu);
+ if (h_pending == NULL_VECTOR) {
+ update_vhpi(vcpu, NULL_VECTOR);
+ return;
+ }
+ h_inservice = highest_inservice_irq(vcpu);
+
+ vpsr = VCPU(vcpu, vpsr);
+ mask = irq_masked(vcpu, h_pending, h_inservice);
+ if ((vpsr & IA64_PSR_I) && IRQ_NO_MASKED == mask) {
+ isr = vpsr & IA64_PSR_RI;
+ update_vhpi(vcpu, h_pending);
+ reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */
+ } else if (mask == IRQ_MASKED_BY_INSVC) {
+ if (VCPU(vcpu, vhpi))
+ update_vhpi(vcpu, NULL_VECTOR);
+ } else {
+ /* masked by vpsr.i or vtpr.*/
+ update_vhpi(vcpu, h_pending);
+ }
+}
+
+static void generate_exirq(struct kvm_vcpu *vcpu)
+{
+ unsigned vpsr;
+ uint64_t isr;
+
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ vpsr = VCPU(vcpu, vpsr);
+ isr = vpsr & IA64_PSR_RI;
+ if (!(vpsr & IA64_PSR_IC))
+ panic_vm(vcpu);
+ reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */
+}
+
+void vhpi_detection(struct kvm_vcpu *vcpu)
+{
+ uint64_t threshold, vhpi;
+ union ia64_tpr vtpr;
+ struct ia64_psr vpsr;
+
+ vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr);
+ vtpr.val = VCPU(vcpu, tpr);
+
+ threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic;
+ vhpi = VCPU(vcpu, vhpi);
+ if (vhpi > threshold) {
+ /* interrupt actived*/
+ generate_exirq(vcpu);
+ }
+}
+
+
+void leave_hypervisor_tail(void)
+{
+ struct kvm_vcpu *v = current_vcpu;
+
+ if (VMX(v, timer_check)) {
+ VMX(v, timer_check) = 0;
+ if (VMX(v, itc_check)) {
+ if (vcpu_get_itc(v) > VCPU(v, itm)) {
+ if (!(VCPU(v, itv) & (1 << 16))) {
+ vcpu_pend_interrupt(v, VCPU(v, itv)
+ & 0xff);
+ VMX(v, itc_check) = 0;
+ } else {
+ v->arch.timer_pending = 1;
+ }
+ VMX(v, last_itc) = VCPU(v, itm) + 1;
+ }
+ }
+ }
+
+ rmb();
+ if (v->arch.irq_new_pending) {
+ v->arch.irq_new_pending = 0;
+ VMX(v, irq_check) = 0;
+ check_pending_irq(v);
+ return;
+ }
+ if (VMX(v, irq_check)) {
+ VMX(v, irq_check) = 0;
+ vhpi_detection(v);
+ }
+}
+
+
+static inline void handle_lds(struct kvm_pt_regs *regs)
+{
+ regs->cr_ipsr |= IA64_PSR_ED;
+}
+
+void physical_tlb_miss(struct kvm_vcpu *vcpu, unsigned long vadr, int type)
+{
+ unsigned long pte;
+ union ia64_rr rr;
+
+ rr.val = ia64_get_rr(vadr);
+ pte = vadr & _PAGE_PPN_MASK;
+ pte = pte | PHY_PAGE_WB;
+ thash_vhpt_insert(vcpu, pte, (u64)(rr.ps << 2), vadr, type);
+ return;
+}
+
+void kvm_page_fault(u64 vadr , u64 vec, struct kvm_pt_regs *regs)
+{
+ unsigned long vpsr;
+ int type;
+
+ u64 vhpt_adr, gppa, pteval, rr, itir;
+ union ia64_isr misr;
+ union ia64_pta vpta;
+ struct thash_data *data;
+ struct kvm_vcpu *v = current_vcpu;
+
+ vpsr = VCPU(v, vpsr);
+ misr.val = VMX(v, cr_isr);
+
+ type = vec;
+
+ if (is_physical_mode(v) && (!(vadr << 1 >> 62))) {
+ if (vec == 2) {
+ if (__gpfn_is_io((vadr << 1) >> (PAGE_SHIFT + 1))) {
+ emulate_io_inst(v, ((vadr << 1) >> 1), 4);
+ return;
+ }
+ }
+ physical_tlb_miss(v, vadr, type);
+ return;
+ }
+ data = vtlb_lookup(v, vadr, type);
+ if (data != 0) {
+ if (type == D_TLB) {
+ gppa = (vadr & ((1UL << data->ps) - 1))
+ + (data->ppn >> (data->ps - 12) << data->ps);
+ if (__gpfn_is_io(gppa >> PAGE_SHIFT)) {
+ if (data->pl >= ((regs->cr_ipsr >>
+ IA64_PSR_CPL0_BIT) & 3))
+ emulate_io_inst(v, gppa, data->ma);
+ else {
+ vcpu_set_isr(v, misr.val);
+ data_access_rights(v, vadr);
+ }
+ return ;
+ }
+ }
+ thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type);
+
+ } else if (type == D_TLB) {
+ if (misr.sp) {
+ handle_lds(regs);
+ return;
+ }
+
+ rr = vcpu_get_rr(v, vadr);
+ itir = rr & (RR_RID_MASK | RR_PS_MASK);
+
+ if (!vhpt_enabled(v, vadr, misr.rs ? RSE_REF : DATA_REF)) {
+ if (vpsr & IA64_PSR_IC) {
+ vcpu_set_isr(v, misr.val);
+ alt_dtlb(v, vadr);
+ } else {
+ nested_dtlb(v);
+ }
+ return ;
+ }
+
+ vpta.val = vcpu_get_pta(v);
+ /* avoid recursively walking (short format) VHPT */
+
+ vhpt_adr = vcpu_thash(v, vadr);
+ if (!guest_vhpt_lookup(vhpt_adr, &pteval)) {
+ /* VHPT successfully read. */
+ if (!(pteval & _PAGE_P)) {
+ if (vpsr & IA64_PSR_IC) {
+ vcpu_set_isr(v, misr.val);
+ dtlb_fault(v, vadr);
+ } else {
+ nested_dtlb(v);
+ }
+ } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) {
+ thash_purge_and_insert(v, pteval, itir,
+ vadr, D_TLB);
+ } else if (vpsr & IA64_PSR_IC) {
+ vcpu_set_isr(v, misr.val);
+ dtlb_fault(v, vadr);
+ } else {
+ nested_dtlb(v);
+ }
+ } else {
+ /* Can't read VHPT. */
+ if (vpsr & IA64_PSR_IC) {
+ vcpu_set_isr(v, misr.val);
+ dvhpt_fault(v, vadr);
+ } else {
+ nested_dtlb(v);
+ }
+ }
+ } else if (type == I_TLB) {
+ if (!(vpsr & IA64_PSR_IC))
+ misr.ni = 1;
+ if (!vhpt_enabled(v, vadr, INST_REF)) {
+ vcpu_set_isr(v, misr.val);
+ alt_itlb(v, vadr);
+ return;
+ }
+
+ vpta.val = vcpu_get_pta(v);
+
+ vhpt_adr = vcpu_thash(v, vadr);
+ if (!guest_vhpt_lookup(vhpt_adr, &pteval)) {
+ /* VHPT successfully read. */
+ if (pteval & _PAGE_P) {
+ if ((pteval & _PAGE_MA_MASK) == _PAGE_MA_ST) {
+ vcpu_set_isr(v, misr.val);
+ itlb_fault(v, vadr);
+ return ;
+ }
+ rr = vcpu_get_rr(v, vadr);
+ itir = rr & (RR_RID_MASK | RR_PS_MASK);
+ thash_purge_and_insert(v, pteval, itir,
+ vadr, I_TLB);
+ } else {
+ vcpu_set_isr(v, misr.val);
+ inst_page_not_present(v, vadr);
+ }
+ } else {
+ vcpu_set_isr(v, misr.val);
+ ivhpt_fault(v, vadr);
+ }
+ }
+}
+
+void kvm_vexirq(struct kvm_vcpu *vcpu)
+{
+ u64 vpsr, isr;
+ struct kvm_pt_regs *regs;
+
+ regs = vcpu_regs(vcpu);
+ vpsr = VCPU(vcpu, vpsr);
+ isr = vpsr & IA64_PSR_RI;
+ reflect_interruption(0, isr, 0, 12, regs); /*EXT IRQ*/
+}
+
+void kvm_ia64_handle_irq(struct kvm_vcpu *v)
+{
+ struct exit_ctl_data *p = &v->arch.exit_data;
+ long psr;
+
+ local_irq_save(psr);
+ p->exit_reason = EXIT_REASON_EXTERNAL_INTERRUPT;
+ vmm_transition(v);
+ local_irq_restore(psr);
+
+ VMX(v, timer_check) = 1;
+
+}
+
+static void ptc_ga_remote_func(struct kvm_vcpu *v, int pos)
+{
+ u64 oldrid, moldrid, oldpsbits, vaddr;
+ struct kvm_ptc_g *p = &v->arch.ptc_g_data[pos];
+ vaddr = p->vaddr;
+
+ oldrid = VMX(v, vrr[0]);
+ VMX(v, vrr[0]) = p->rr;
+ oldpsbits = VMX(v, psbits[0]);
+ VMX(v, psbits[0]) = VMX(v, psbits[REGION_NUMBER(vaddr)]);
+ moldrid = ia64_get_rr(0x0);
+ ia64_set_rr(0x0, vrrtomrr(p->rr));
+ ia64_srlz_d();
+
+ vaddr = PAGEALIGN(vaddr, p->ps);
+ thash_purge_entries_remote(v, vaddr, p->ps);
+
+ VMX(v, vrr[0]) = oldrid;
+ VMX(v, psbits[0]) = oldpsbits;
+ ia64_set_rr(0x0, moldrid);
+ ia64_dv_serialize_data();
+}
+
+static void vcpu_do_resume(struct kvm_vcpu *vcpu)
+{
+ /*Re-init VHPT and VTLB once from resume*/
+ vcpu->arch.vhpt.num = VHPT_NUM_ENTRIES;
+ thash_init(&vcpu->arch.vhpt, VHPT_SHIFT);
+ vcpu->arch.vtlb.num = VTLB_NUM_ENTRIES;
+ thash_init(&vcpu->arch.vtlb, VTLB_SHIFT);
+
+ ia64_set_pta(vcpu->arch.vhpt.pta.val);
+}
+
+static void kvm_do_resume_op(struct kvm_vcpu *vcpu)
+{
+ if (test_and_clear_bit(KVM_REQ_RESUME, &vcpu->requests)) {
+ vcpu_do_resume(vcpu);
+ return;
+ }
+
+ if (unlikely(test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))) {
+ thash_purge_all(vcpu);
+ return;
+ }
+
+ if (test_and_clear_bit(KVM_REQ_PTC_G, &vcpu->requests)) {
+ while (vcpu->arch.ptc_g_count > 0)
+ ptc_ga_remote_func(vcpu, --vcpu->arch.ptc_g_count);
+ }
+}
+
+void vmm_transition(struct kvm_vcpu *vcpu)
+{
+ ia64_call_vsa(PAL_VPS_SAVE, (unsigned long)vcpu->arch.vpd,
+ 0, 0, 0, 0, 0, 0);
+ vmm_trampoline(&vcpu->arch.guest, &vcpu->arch.host);
+ ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)vcpu->arch.vpd,
+ 0, 0, 0, 0, 0, 0);
+ kvm_do_resume_op(vcpu);
+}
diff --git a/arch/ia64/kvm/trampoline.S b/arch/ia64/kvm/trampoline.S
new file mode 100644
index 000000000000..30897d44d61e
--- /dev/null
+++ b/arch/ia64/kvm/trampoline.S
@@ -0,0 +1,1038 @@
+/* Save all processor states
+ *
+ * Copyright (c) 2007 Fleming Feng <fleming.feng@intel.com>
+ * Copyright (c) 2007 Anthony Xu <anthony.xu@intel.com>
+ */
+
+#include <asm/asmmacro.h>
+#include "asm-offsets.h"
+
+
+#define CTX(name) VMM_CTX_##name##_OFFSET
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_BRANCH_REGS \
+ add r2 = CTX(B0),r32; \
+ add r3 = CTX(B1),r32; \
+ mov r16 = b0; \
+ mov r17 = b1; \
+ ;; \
+ st8 [r2]=r16,16; \
+ st8 [r3]=r17,16; \
+ ;; \
+ mov r16 = b2; \
+ mov r17 = b3; \
+ ;; \
+ st8 [r2]=r16,16; \
+ st8 [r3]=r17,16; \
+ ;; \
+ mov r16 = b4; \
+ mov r17 = b5; \
+ ;; \
+ st8 [r2]=r16; \
+ st8 [r3]=r17; \
+ ;;
+
+ /*
+ * r33: context_t base address
+ */
+#define RESTORE_BRANCH_REGS \
+ add r2 = CTX(B0),r33; \
+ add r3 = CTX(B1),r33; \
+ ;; \
+ ld8 r16=[r2],16; \
+ ld8 r17=[r3],16; \
+ ;; \
+ mov b0 = r16; \
+ mov b1 = r17; \
+ ;; \
+ ld8 r16=[r2],16; \
+ ld8 r17=[r3],16; \
+ ;; \
+ mov b2 = r16; \
+ mov b3 = r17; \
+ ;; \
+ ld8 r16=[r2]; \
+ ld8 r17=[r3]; \
+ ;; \
+ mov b4=r16; \
+ mov b5=r17; \
+ ;;
+
+
+ /*
+ * r32: context_t base address
+ * bsw == 1
+ * Save all bank1 general registers, r4 ~ r7
+ */
+#define SAVE_GENERAL_REGS \
+ add r2=CTX(R4),r32; \
+ add r3=CTX(R5),r32; \
+ ;; \
+.mem.offset 0,0; \
+ st8.spill [r2]=r4,16; \
+.mem.offset 8,0; \
+ st8.spill [r3]=r5,16; \
+ ;; \
+.mem.offset 0,0; \
+ st8.spill [r2]=r6,48; \
+.mem.offset 8,0; \
+ st8.spill [r3]=r7,48; \
+ ;; \
+.mem.offset 0,0; \
+ st8.spill [r2]=r12; \
+.mem.offset 8,0; \
+ st8.spill [r3]=r13; \
+ ;;
+
+ /*
+ * r33: context_t base address
+ * bsw == 1
+ */
+#define RESTORE_GENERAL_REGS \
+ add r2=CTX(R4),r33; \
+ add r3=CTX(R5),r33; \
+ ;; \
+ ld8.fill r4=[r2],16; \
+ ld8.fill r5=[r3],16; \
+ ;; \
+ ld8.fill r6=[r2],48; \
+ ld8.fill r7=[r3],48; \
+ ;; \
+ ld8.fill r12=[r2]; \
+ ld8.fill r13 =[r3]; \
+ ;;
+
+
+
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_KERNEL_REGS \
+ add r2 = CTX(KR0),r32; \
+ add r3 = CTX(KR1),r32; \
+ mov r16 = ar.k0; \
+ mov r17 = ar.k1; \
+ ;; \
+ st8 [r2] = r16,16; \
+ st8 [r3] = r17,16; \
+ ;; \
+ mov r16 = ar.k2; \
+ mov r17 = ar.k3; \
+ ;; \
+ st8 [r2] = r16,16; \
+ st8 [r3] = r17,16; \
+ ;; \
+ mov r16 = ar.k4; \
+ mov r17 = ar.k5; \
+ ;; \
+ st8 [r2] = r16,16; \
+ st8 [r3] = r17,16; \
+ ;; \
+ mov r16 = ar.k6; \
+ mov r17 = ar.k7; \
+ ;; \
+ st8 [r2] = r16; \
+ st8 [r3] = r17; \
+ ;;
+
+
+
+ /*
+ * r33: context_t base address
+ */
+#define RESTORE_KERNEL_REGS \
+ add r2 = CTX(KR0),r33; \
+ add r3 = CTX(KR1),r33; \
+ ;; \
+ ld8 r16=[r2],16; \
+ ld8 r17=[r3],16; \
+ ;; \
+ mov ar.k0=r16; \
+ mov ar.k1=r17; \
+ ;; \
+ ld8 r16=[r2],16; \
+ ld8 r17=[r3],16; \
+ ;; \
+ mov ar.k2=r16; \
+ mov ar.k3=r17; \
+ ;; \
+ ld8 r16=[r2],16; \
+ ld8 r17=[r3],16; \
+ ;; \
+ mov ar.k4=r16; \
+ mov ar.k5=r17; \
+ ;; \
+ ld8 r16=[r2],16; \
+ ld8 r17=[r3],16; \
+ ;; \
+ mov ar.k6=r16; \
+ mov ar.k7=r17; \
+ ;;
+
+
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_APP_REGS \
+ add r2 = CTX(BSPSTORE),r32; \
+ mov r16 = ar.bspstore; \
+ ;; \
+ st8 [r2] = r16,CTX(RNAT)-CTX(BSPSTORE);\
+ mov r16 = ar.rnat; \
+ ;; \
+ st8 [r2] = r16,CTX(FCR)-CTX(RNAT); \
+ mov r16 = ar.fcr; \
+ ;; \
+ st8 [r2] = r16,CTX(EFLAG)-CTX(FCR); \
+ mov r16 = ar.eflag; \
+ ;; \
+ st8 [r2] = r16,CTX(CFLG)-CTX(EFLAG); \
+ mov r16 = ar.cflg; \
+ ;; \
+ st8 [r2] = r16,CTX(FSR)-CTX(CFLG); \
+ mov r16 = ar.fsr; \
+ ;; \
+ st8 [r2] = r16,CTX(FIR)-CTX(FSR); \
+ mov r16 = ar.fir; \
+ ;; \
+ st8 [r2] = r16,CTX(FDR)-CTX(FIR); \
+ mov r16 = ar.fdr; \
+ ;; \
+ st8 [r2] = r16,CTX(UNAT)-CTX(FDR); \
+ mov r16 = ar.unat; \
+ ;; \
+ st8 [r2] = r16,CTX(FPSR)-CTX(UNAT); \
+ mov r16 = ar.fpsr; \
+ ;; \
+ st8 [r2] = r16,CTX(PFS)-CTX(FPSR); \
+ mov r16 = ar.pfs; \
+ ;; \
+ st8 [r2] = r16,CTX(LC)-CTX(PFS); \
+ mov r16 = ar.lc; \
+ ;; \
+ st8 [r2] = r16; \
+ ;;
+
+ /*
+ * r33: context_t base address
+ */
+#define RESTORE_APP_REGS \
+ add r2=CTX(BSPSTORE),r33; \
+ ;; \
+ ld8 r16=[r2],CTX(RNAT)-CTX(BSPSTORE); \
+ ;; \
+ mov ar.bspstore=r16; \
+ ld8 r16=[r2],CTX(FCR)-CTX(RNAT); \
+ ;; \
+ mov ar.rnat=r16; \
+ ld8 r16=[r2],CTX(EFLAG)-CTX(FCR); \
+ ;; \
+ mov ar.fcr=r16; \
+ ld8 r16=[r2],CTX(CFLG)-CTX(EFLAG); \
+ ;; \
+ mov ar.eflag=r16; \
+ ld8 r16=[r2],CTX(FSR)-CTX(CFLG); \
+ ;; \
+ mov ar.cflg=r16; \
+ ld8 r16=[r2],CTX(FIR)-CTX(FSR); \
+ ;; \
+ mov ar.fsr=r16; \
+ ld8 r16=[r2],CTX(FDR)-CTX(FIR); \
+ ;; \
+ mov ar.fir=r16; \
+ ld8 r16=[r2],CTX(UNAT)-CTX(FDR); \
+ ;; \
+ mov ar.fdr=r16; \
+ ld8 r16=[r2],CTX(FPSR)-CTX(UNAT); \
+ ;; \
+ mov ar.unat=r16; \
+ ld8 r16=[r2],CTX(PFS)-CTX(FPSR); \
+ ;; \
+ mov ar.fpsr=r16; \
+ ld8 r16=[r2],CTX(LC)-CTX(PFS); \
+ ;; \
+ mov ar.pfs=r16; \
+ ld8 r16=[r2]; \
+ ;; \
+ mov ar.lc=r16; \
+ ;;
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_CTL_REGS \
+ add r2 = CTX(DCR),r32; \
+ mov r16 = cr.dcr; \
+ ;; \
+ st8 [r2] = r16,CTX(IVA)-CTX(DCR); \
+ ;; \
+ mov r16 = cr.iva; \
+ ;; \
+ st8 [r2] = r16,CTX(PTA)-CTX(IVA); \
+ ;; \
+ mov r16 = cr.pta; \
+ ;; \
+ st8 [r2] = r16 ; \
+ ;;
+
+ /*
+ * r33: context_t base address
+ */
+#define RESTORE_CTL_REGS \
+ add r2 = CTX(DCR),r33; \
+ ;; \
+ ld8 r16 = [r2],CTX(IVA)-CTX(DCR); \
+ ;; \
+ mov cr.dcr = r16; \
+ dv_serialize_data; \
+ ;; \
+ ld8 r16 = [r2],CTX(PTA)-CTX(IVA); \
+ ;; \
+ mov cr.iva = r16; \
+ dv_serialize_data; \
+ ;; \
+ ld8 r16 = [r2]; \
+ ;; \
+ mov cr.pta = r16; \
+ dv_serialize_data; \
+ ;;
+
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_REGION_REGS \
+ add r2=CTX(RR0),r32; \
+ mov r16=rr[r0]; \
+ dep.z r18=1,61,3; \
+ ;; \
+ st8 [r2]=r16,8; \
+ mov r17=rr[r18]; \
+ dep.z r18=2,61,3; \
+ ;; \
+ st8 [r2]=r17,8; \
+ mov r16=rr[r18]; \
+ dep.z r18=3,61,3; \
+ ;; \
+ st8 [r2]=r16,8; \
+ mov r17=rr[r18]; \
+ dep.z r18=4,61,3; \
+ ;; \
+ st8 [r2]=r17,8; \
+ mov r16=rr[r18]; \
+ dep.z r18=5,61,3; \
+ ;; \
+ st8 [r2]=r16,8; \
+ mov r17=rr[r18]; \
+ dep.z r18=7,61,3; \
+ ;; \
+ st8 [r2]=r17,16; \
+ mov r16=rr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ ;;
+
+ /*
+ * r33:context_t base address
+ */
+#define RESTORE_REGION_REGS \
+ add r2=CTX(RR0),r33;\
+ mov r18=r0; \
+ ;; \
+ ld8 r20=[r2],8; \
+ ;; /* rr0 */ \
+ ld8 r21=[r2],8; \
+ ;; /* rr1 */ \
+ ld8 r22=[r2],8; \
+ ;; /* rr2 */ \
+ ld8 r23=[r2],8; \
+ ;; /* rr3 */ \
+ ld8 r24=[r2],8; \
+ ;; /* rr4 */ \
+ ld8 r25=[r2],16; \
+ ;; /* rr5 */ \
+ ld8 r27=[r2]; \
+ ;; /* rr7 */ \
+ mov rr[r18]=r20; \
+ dep.z r18=1,61,3; \
+ ;; /* rr1 */ \
+ mov rr[r18]=r21; \
+ dep.z r18=2,61,3; \
+ ;; /* rr2 */ \
+ mov rr[r18]=r22; \
+ dep.z r18=3,61,3; \
+ ;; /* rr3 */ \
+ mov rr[r18]=r23; \
+ dep.z r18=4,61,3; \
+ ;; /* rr4 */ \
+ mov rr[r18]=r24; \
+ dep.z r18=5,61,3; \
+ ;; /* rr5 */ \
+ mov rr[r18]=r25; \
+ dep.z r18=7,61,3; \
+ ;; /* rr7 */ \
+ mov rr[r18]=r27; \
+ ;; \
+ srlz.i; \
+ ;;
+
+
+
+ /*
+ * r32: context_t base address
+ * r36~r39:scratch registers
+ */
+#define SAVE_DEBUG_REGS \
+ add r2=CTX(IBR0),r32; \
+ add r3=CTX(DBR0),r32; \
+ mov r16=ibr[r0]; \
+ mov r17=dbr[r0]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=1,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=2,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=2,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=3,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=4,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=5,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=6,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ add r18=7,r0; \
+ ;; \
+ mov r16=ibr[r18]; \
+ mov r17=dbr[r18]; \
+ ;; \
+ st8 [r2]=r16,8; \
+ st8 [r3]=r17,8; \
+ ;;
+
+
+/*
+ * r33: point to context_t structure
+ * ar.lc are corrupted.
+ */
+#define RESTORE_DEBUG_REGS \
+ add r2=CTX(IBR0),r33; \
+ add r3=CTX(DBR0),r33; \
+ mov r16=7; \
+ mov r17=r0; \
+ ;; \
+ mov ar.lc = r16; \
+ ;; \
+1: \
+ ld8 r18=[r2],8; \
+ ld8 r19=[r3],8; \
+ ;; \
+ mov ibr[r17]=r18; \
+ mov dbr[r17]=r19; \
+ ;; \
+ srlz.i; \
+ ;; \
+ add r17=1,r17; \
+ br.cloop.sptk 1b; \
+ ;;
+
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_FPU_LOW \
+ add r2=CTX(F2),r32; \
+ add r3=CTX(F3),r32; \
+ ;; \
+ stf.spill.nta [r2]=f2,32; \
+ stf.spill.nta [r3]=f3,32; \
+ ;; \
+ stf.spill.nta [r2]=f4,32; \
+ stf.spill.nta [r3]=f5,32; \
+ ;; \
+ stf.spill.nta [r2]=f6,32; \
+ stf.spill.nta [r3]=f7,32; \
+ ;; \
+ stf.spill.nta [r2]=f8,32; \
+ stf.spill.nta [r3]=f9,32; \
+ ;; \
+ stf.spill.nta [r2]=f10,32; \
+ stf.spill.nta [r3]=f11,32; \
+ ;; \
+ stf.spill.nta [r2]=f12,32; \
+ stf.spill.nta [r3]=f13,32; \
+ ;; \
+ stf.spill.nta [r2]=f14,32; \
+ stf.spill.nta [r3]=f15,32; \
+ ;; \
+ stf.spill.nta [r2]=f16,32; \
+ stf.spill.nta [r3]=f17,32; \
+ ;; \
+ stf.spill.nta [r2]=f18,32; \
+ stf.spill.nta [r3]=f19,32; \
+ ;; \
+ stf.spill.nta [r2]=f20,32; \
+ stf.spill.nta [r3]=f21,32; \
+ ;; \
+ stf.spill.nta [r2]=f22,32; \
+ stf.spill.nta [r3]=f23,32; \
+ ;; \
+ stf.spill.nta [r2]=f24,32; \
+ stf.spill.nta [r3]=f25,32; \
+ ;; \
+ stf.spill.nta [r2]=f26,32; \
+ stf.spill.nta [r3]=f27,32; \
+ ;; \
+ stf.spill.nta [r2]=f28,32; \
+ stf.spill.nta [r3]=f29,32; \
+ ;; \
+ stf.spill.nta [r2]=f30; \
+ stf.spill.nta [r3]=f31; \
+ ;;
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_FPU_HIGH \
+ add r2=CTX(F32),r32; \
+ add r3=CTX(F33),r32; \
+ ;; \
+ stf.spill.nta [r2]=f32,32; \
+ stf.spill.nta [r3]=f33,32; \
+ ;; \
+ stf.spill.nta [r2]=f34,32; \
+ stf.spill.nta [r3]=f35,32; \
+ ;; \
+ stf.spill.nta [r2]=f36,32; \
+ stf.spill.nta [r3]=f37,32; \
+ ;; \
+ stf.spill.nta [r2]=f38,32; \
+ stf.spill.nta [r3]=f39,32; \
+ ;; \
+ stf.spill.nta [r2]=f40,32; \
+ stf.spill.nta [r3]=f41,32; \
+ ;; \
+ stf.spill.nta [r2]=f42,32; \
+ stf.spill.nta [r3]=f43,32; \
+ ;; \
+ stf.spill.nta [r2]=f44,32; \
+ stf.spill.nta [r3]=f45,32; \
+ ;; \
+ stf.spill.nta [r2]=f46,32; \
+ stf.spill.nta [r3]=f47,32; \
+ ;; \
+ stf.spill.nta [r2]=f48,32; \
+ stf.spill.nta [r3]=f49,32; \
+ ;; \
+ stf.spill.nta [r2]=f50,32; \
+ stf.spill.nta [r3]=f51,32; \
+ ;; \
+ stf.spill.nta [r2]=f52,32; \
+ stf.spill.nta [r3]=f53,32; \
+ ;; \
+ stf.spill.nta [r2]=f54,32; \
+ stf.spill.nta [r3]=f55,32; \
+ ;; \
+ stf.spill.nta [r2]=f56,32; \
+ stf.spill.nta [r3]=f57,32; \
+ ;; \
+ stf.spill.nta [r2]=f58,32; \
+ stf.spill.nta [r3]=f59,32; \
+ ;; \
+ stf.spill.nta [r2]=f60,32; \
+ stf.spill.nta [r3]=f61,32; \
+ ;; \
+ stf.spill.nta [r2]=f62,32; \
+ stf.spill.nta [r3]=f63,32; \
+ ;; \
+ stf.spill.nta [r2]=f64,32; \
+ stf.spill.nta [r3]=f65,32; \
+ ;; \
+ stf.spill.nta [r2]=f66,32; \
+ stf.spill.nta [r3]=f67,32; \
+ ;; \
+ stf.spill.nta [r2]=f68,32; \
+ stf.spill.nta [r3]=f69,32; \
+ ;; \
+ stf.spill.nta [r2]=f70,32; \
+ stf.spill.nta [r3]=f71,32; \
+ ;; \
+ stf.spill.nta [r2]=f72,32; \
+ stf.spill.nta [r3]=f73,32; \
+ ;; \
+ stf.spill.nta [r2]=f74,32; \
+ stf.spill.nta [r3]=f75,32; \
+ ;; \
+ stf.spill.nta [r2]=f76,32; \
+ stf.spill.nta [r3]=f77,32; \
+ ;; \
+ stf.spill.nta [r2]=f78,32; \
+ stf.spill.nta [r3]=f79,32; \
+ ;; \
+ stf.spill.nta [r2]=f80,32; \
+ stf.spill.nta [r3]=f81,32; \
+ ;; \
+ stf.spill.nta [r2]=f82,32; \
+ stf.spill.nta [r3]=f83,32; \
+ ;; \
+ stf.spill.nta [r2]=f84,32; \
+ stf.spill.nta [r3]=f85,32; \
+ ;; \
+ stf.spill.nta [r2]=f86,32; \
+ stf.spill.nta [r3]=f87,32; \
+ ;; \
+ stf.spill.nta [r2]=f88,32; \
+ stf.spill.nta [r3]=f89,32; \
+ ;; \
+ stf.spill.nta [r2]=f90,32; \
+ stf.spill.nta [r3]=f91,32; \
+ ;; \
+ stf.spill.nta [r2]=f92,32; \
+ stf.spill.nta [r3]=f93,32; \
+ ;; \
+ stf.spill.nta [r2]=f94,32; \
+ stf.spill.nta [r3]=f95,32; \
+ ;; \
+ stf.spill.nta [r2]=f96,32; \
+ stf.spill.nta [r3]=f97,32; \
+ ;; \
+ stf.spill.nta [r2]=f98,32; \
+ stf.spill.nta [r3]=f99,32; \
+ ;; \
+ stf.spill.nta [r2]=f100,32; \
+ stf.spill.nta [r3]=f101,32; \
+ ;; \
+ stf.spill.nta [r2]=f102,32; \
+ stf.spill.nta [r3]=f103,32; \
+ ;; \
+ stf.spill.nta [r2]=f104,32; \
+ stf.spill.nta [r3]=f105,32; \
+ ;; \
+ stf.spill.nta [r2]=f106,32; \
+ stf.spill.nta [r3]=f107,32; \
+ ;; \
+ stf.spill.nta [r2]=f108,32; \
+ stf.spill.nta [r3]=f109,32; \
+ ;; \
+ stf.spill.nta [r2]=f110,32; \
+ stf.spill.nta [r3]=f111,32; \
+ ;; \
+ stf.spill.nta [r2]=f112,32; \
+ stf.spill.nta [r3]=f113,32; \
+ ;; \
+ stf.spill.nta [r2]=f114,32; \
+ stf.spill.nta [r3]=f115,32; \
+ ;; \
+ stf.spill.nta [r2]=f116,32; \
+ stf.spill.nta [r3]=f117,32; \
+ ;; \
+ stf.spill.nta [r2]=f118,32; \
+ stf.spill.nta [r3]=f119,32; \
+ ;; \
+ stf.spill.nta [r2]=f120,32; \
+ stf.spill.nta [r3]=f121,32; \
+ ;; \
+ stf.spill.nta [r2]=f122,32; \
+ stf.spill.nta [r3]=f123,32; \
+ ;; \
+ stf.spill.nta [r2]=f124,32; \
+ stf.spill.nta [r3]=f125,32; \
+ ;; \
+ stf.spill.nta [r2]=f126; \
+ stf.spill.nta [r3]=f127; \
+ ;;
+
+ /*
+ * r33: point to context_t structure
+ */
+#define RESTORE_FPU_LOW \
+ add r2 = CTX(F2), r33; \
+ add r3 = CTX(F3), r33; \
+ ;; \
+ ldf.fill.nta f2 = [r2], 32; \
+ ldf.fill.nta f3 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f4 = [r2], 32; \
+ ldf.fill.nta f5 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f6 = [r2], 32; \
+ ldf.fill.nta f7 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f8 = [r2], 32; \
+ ldf.fill.nta f9 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f10 = [r2], 32; \
+ ldf.fill.nta f11 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f12 = [r2], 32; \
+ ldf.fill.nta f13 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f14 = [r2], 32; \
+ ldf.fill.nta f15 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f16 = [r2], 32; \
+ ldf.fill.nta f17 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f18 = [r2], 32; \
+ ldf.fill.nta f19 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f20 = [r2], 32; \
+ ldf.fill.nta f21 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f22 = [r2], 32; \
+ ldf.fill.nta f23 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f24 = [r2], 32; \
+ ldf.fill.nta f25 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f26 = [r2], 32; \
+ ldf.fill.nta f27 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f28 = [r2], 32; \
+ ldf.fill.nta f29 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f30 = [r2], 32; \
+ ldf.fill.nta f31 = [r3], 32; \
+ ;;
+
+
+
+ /*
+ * r33: point to context_t structure
+ */
+#define RESTORE_FPU_HIGH \
+ add r2 = CTX(F32), r33; \
+ add r3 = CTX(F33), r33; \
+ ;; \
+ ldf.fill.nta f32 = [r2], 32; \
+ ldf.fill.nta f33 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f34 = [r2], 32; \
+ ldf.fill.nta f35 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f36 = [r2], 32; \
+ ldf.fill.nta f37 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f38 = [r2], 32; \
+ ldf.fill.nta f39 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f40 = [r2], 32; \
+ ldf.fill.nta f41 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f42 = [r2], 32; \
+ ldf.fill.nta f43 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f44 = [r2], 32; \
+ ldf.fill.nta f45 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f46 = [r2], 32; \
+ ldf.fill.nta f47 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f48 = [r2], 32; \
+ ldf.fill.nta f49 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f50 = [r2], 32; \
+ ldf.fill.nta f51 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f52 = [r2], 32; \
+ ldf.fill.nta f53 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f54 = [r2], 32; \
+ ldf.fill.nta f55 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f56 = [r2], 32; \
+ ldf.fill.nta f57 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f58 = [r2], 32; \
+ ldf.fill.nta f59 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f60 = [r2], 32; \
+ ldf.fill.nta f61 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f62 = [r2], 32; \
+ ldf.fill.nta f63 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f64 = [r2], 32; \
+ ldf.fill.nta f65 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f66 = [r2], 32; \
+ ldf.fill.nta f67 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f68 = [r2], 32; \
+ ldf.fill.nta f69 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f70 = [r2], 32; \
+ ldf.fill.nta f71 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f72 = [r2], 32; \
+ ldf.fill.nta f73 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f74 = [r2], 32; \
+ ldf.fill.nta f75 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f76 = [r2], 32; \
+ ldf.fill.nta f77 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f78 = [r2], 32; \
+ ldf.fill.nta f79 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f80 = [r2], 32; \
+ ldf.fill.nta f81 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f82 = [r2], 32; \
+ ldf.fill.nta f83 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f84 = [r2], 32; \
+ ldf.fill.nta f85 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f86 = [r2], 32; \
+ ldf.fill.nta f87 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f88 = [r2], 32; \
+ ldf.fill.nta f89 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f90 = [r2], 32; \
+ ldf.fill.nta f91 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f92 = [r2], 32; \
+ ldf.fill.nta f93 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f94 = [r2], 32; \
+ ldf.fill.nta f95 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f96 = [r2], 32; \
+ ldf.fill.nta f97 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f98 = [r2], 32; \
+ ldf.fill.nta f99 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f100 = [r2], 32; \
+ ldf.fill.nta f101 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f102 = [r2], 32; \
+ ldf.fill.nta f103 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f104 = [r2], 32; \
+ ldf.fill.nta f105 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f106 = [r2], 32; \
+ ldf.fill.nta f107 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f108 = [r2], 32; \
+ ldf.fill.nta f109 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f110 = [r2], 32; \
+ ldf.fill.nta f111 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f112 = [r2], 32; \
+ ldf.fill.nta f113 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f114 = [r2], 32; \
+ ldf.fill.nta f115 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f116 = [r2], 32; \
+ ldf.fill.nta f117 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f118 = [r2], 32; \
+ ldf.fill.nta f119 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f120 = [r2], 32; \
+ ldf.fill.nta f121 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f122 = [r2], 32; \
+ ldf.fill.nta f123 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f124 = [r2], 32; \
+ ldf.fill.nta f125 = [r3], 32; \
+ ;; \
+ ldf.fill.nta f126 = [r2], 32; \
+ ldf.fill.nta f127 = [r3], 32; \
+ ;;
+
+ /*
+ * r32: context_t base address
+ */
+#define SAVE_PTK_REGS \
+ add r2=CTX(PKR0), r32; \
+ mov r16=7; \
+ ;; \
+ mov ar.lc=r16; \
+ mov r17=r0; \
+ ;; \
+1: \
+ mov r18=pkr[r17]; \
+ ;; \
+ srlz.i; \
+ ;; \
+ st8 [r2]=r18, 8; \
+ ;; \
+ add r17 =1,r17; \
+ ;; \
+ br.cloop.sptk 1b; \
+ ;;
+
+/*
+ * r33: point to context_t structure
+ * ar.lc are corrupted.
+ */
+#define RESTORE_PTK_REGS \
+ add r2=CTX(PKR0), r33; \
+ mov r16=7; \
+ ;; \
+ mov ar.lc=r16; \
+ mov r17=r0; \
+ ;; \
+1: \
+ ld8 r18=[r2], 8; \
+ ;; \
+ mov pkr[r17]=r18; \
+ ;; \
+ srlz.i; \
+ ;; \
+ add r17 =1,r17; \
+ ;; \
+ br.cloop.sptk 1b; \
+ ;;
+
+
+/*
+ * void vmm_trampoline( context_t * from,
+ * context_t * to)
+ *
+ * from: r32
+ * to: r33
+ * note: interrupt disabled before call this function.
+ */
+GLOBAL_ENTRY(vmm_trampoline)
+ mov r16 = psr
+ adds r2 = CTX(PSR), r32
+ ;;
+ st8 [r2] = r16, 8 // psr
+ mov r17 = pr
+ ;;
+ st8 [r2] = r17, 8 // pr
+ mov r18 = ar.unat
+ ;;
+ st8 [r2] = r18
+ mov r17 = ar.rsc
+ ;;
+ adds r2 = CTX(RSC),r32
+ ;;
+ st8 [r2]= r17
+ mov ar.rsc =0
+ flushrs
+ ;;
+ SAVE_GENERAL_REGS
+ ;;
+ SAVE_KERNEL_REGS
+ ;;
+ SAVE_APP_REGS
+ ;;
+ SAVE_BRANCH_REGS
+ ;;
+ SAVE_CTL_REGS
+ ;;
+ SAVE_REGION_REGS
+ ;;
+ //SAVE_DEBUG_REGS
+ ;;
+ rsm psr.dfl
+ ;;
+ srlz.d
+ ;;
+ SAVE_FPU_LOW
+ ;;
+ rsm psr.dfh
+ ;;
+ srlz.d
+ ;;
+ SAVE_FPU_HIGH
+ ;;
+ SAVE_PTK_REGS
+ ;;
+ RESTORE_PTK_REGS
+ ;;
+ RESTORE_FPU_HIGH
+ ;;
+ RESTORE_FPU_LOW
+ ;;
+ //RESTORE_DEBUG_REGS
+ ;;
+ RESTORE_REGION_REGS
+ ;;
+ RESTORE_CTL_REGS
+ ;;
+ RESTORE_BRANCH_REGS
+ ;;
+ RESTORE_APP_REGS
+ ;;
+ RESTORE_KERNEL_REGS
+ ;;
+ RESTORE_GENERAL_REGS
+ ;;
+ adds r2=CTX(PSR), r33
+ ;;
+ ld8 r16=[r2], 8 // psr
+ ;;
+ mov psr.l=r16
+ ;;
+ srlz.d
+ ;;
+ ld8 r16=[r2], 8 // pr
+ ;;
+ mov pr =r16,-1
+ ld8 r16=[r2] // unat
+ ;;
+ mov ar.unat=r16
+ ;;
+ adds r2=CTX(RSC),r33
+ ;;
+ ld8 r16 =[r2]
+ ;;
+ mov ar.rsc = r16
+ ;;
+ br.ret.sptk.few b0
+END(vmm_trampoline)
diff --git a/arch/ia64/kvm/vcpu.c b/arch/ia64/kvm/vcpu.c
new file mode 100644
index 000000000000..e44027ce5667
--- /dev/null
+++ b/arch/ia64/kvm/vcpu.c
@@ -0,0 +1,2163 @@
+/*
+ * kvm_vcpu.c: handling all virtual cpu related thing.
+ * Copyright (c) 2005, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Shaofan Li (Susue Li) <susie.li@intel.com>
+ * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
+ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
+ * Xiantao Zhang <xiantao.zhang@intel.com>
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+#include <asm/ia64regs.h>
+#include <asm/gcc_intrin.h>
+#include <asm/kregs.h>
+#include <asm/pgtable.h>
+#include <asm/tlb.h>
+
+#include "asm-offsets.h"
+#include "vcpu.h"
+
+/*
+ * Special notes:
+ * - Index by it/dt/rt sequence
+ * - Only existing mode transitions are allowed in this table
+ * - RSE is placed at lazy mode when emulating guest partial mode
+ * - If gva happens to be rr0 and rr4, only allowed case is identity
+ * mapping (gva=gpa), or panic! (How?)
+ */
+int mm_switch_table[8][8] = {
+ /* 2004/09/12(Kevin): Allow switch to self */
+ /*
+ * (it,dt,rt): (0,0,0) -> (1,1,1)
+ * This kind of transition usually occurs in the very early
+ * stage of Linux boot up procedure. Another case is in efi
+ * and pal calls. (see "arch/ia64/kernel/head.S")
+ *
+ * (it,dt,rt): (0,0,0) -> (0,1,1)
+ * This kind of transition is found when OSYa exits efi boot
+ * service. Due to gva = gpa in this case (Same region),
+ * data access can be satisfied though itlb entry for physical
+ * emulation is hit.
+ */
+ {SW_SELF, 0, 0, SW_NOP, 0, 0, 0, SW_P2V},
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ /*
+ * (it,dt,rt): (0,1,1) -> (1,1,1)
+ * This kind of transition is found in OSYa.
+ *
+ * (it,dt,rt): (0,1,1) -> (0,0,0)
+ * This kind of transition is found in OSYa
+ */
+ {SW_NOP, 0, 0, SW_SELF, 0, 0, 0, SW_P2V},
+ /* (1,0,0)->(1,1,1) */
+ {0, 0, 0, 0, 0, 0, 0, SW_P2V},
+ /*
+ * (it,dt,rt): (1,0,1) -> (1,1,1)
+ * This kind of transition usually occurs when Linux returns
+ * from the low level TLB miss handlers.
+ * (see "arch/ia64/kernel/ivt.S")
+ */
+ {0, 0, 0, 0, 0, SW_SELF, 0, SW_P2V},
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ /*
+ * (it,dt,rt): (1,1,1) -> (1,0,1)
+ * This kind of transition usually occurs in Linux low level
+ * TLB miss handler. (see "arch/ia64/kernel/ivt.S")
+ *
+ * (it,dt,rt): (1,1,1) -> (0,0,0)
+ * This kind of transition usually occurs in pal and efi calls,
+ * which requires running in physical mode.
+ * (see "arch/ia64/kernel/head.S")
+ * (1,1,1)->(1,0,0)
+ */
+
+ {SW_V2P, 0, 0, 0, SW_V2P, SW_V2P, 0, SW_SELF},
+};
+
+void physical_mode_init(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.mode_flags = GUEST_IN_PHY;
+}
+
+void switch_to_physical_rid(struct kvm_vcpu *vcpu)
+{
+ unsigned long psr;
+
+ /* Save original virtual mode rr[0] and rr[4] */
+ psr = ia64_clear_ic();
+ ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_rr0);
+ ia64_srlz_d();
+ ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_rr4);
+ ia64_srlz_d();
+
+ ia64_set_psr(psr);
+ return;
+}
+
+
+void switch_to_virtual_rid(struct kvm_vcpu *vcpu)
+{
+ unsigned long psr;
+
+ psr = ia64_clear_ic();
+ ia64_set_rr(VRN0 << VRN_SHIFT, vcpu->arch.metaphysical_saved_rr0);
+ ia64_srlz_d();
+ ia64_set_rr(VRN4 << VRN_SHIFT, vcpu->arch.metaphysical_saved_rr4);
+ ia64_srlz_d();
+ ia64_set_psr(psr);
+ return;
+}
+
+static int mm_switch_action(struct ia64_psr opsr, struct ia64_psr npsr)
+{
+ return mm_switch_table[MODE_IND(opsr)][MODE_IND(npsr)];
+}
+
+void switch_mm_mode(struct kvm_vcpu *vcpu, struct ia64_psr old_psr,
+ struct ia64_psr new_psr)
+{
+ int act;
+ act = mm_switch_action(old_psr, new_psr);
+ switch (act) {
+ case SW_V2P:
+ /*printk("V -> P mode transition: (0x%lx -> 0x%lx)\n",
+ old_psr.val, new_psr.val);*/
+ switch_to_physical_rid(vcpu);
+ /*
+ * Set rse to enforced lazy, to prevent active rse
+ *save/restor when guest physical mode.
+ */
+ vcpu->arch.mode_flags |= GUEST_IN_PHY;
+ break;
+ case SW_P2V:
+ switch_to_virtual_rid(vcpu);
+ /*
+ * recover old mode which is saved when entering
+ * guest physical mode
+ */
+ vcpu->arch.mode_flags &= ~GUEST_IN_PHY;
+ break;
+ case SW_SELF:
+ break;
+ case SW_NOP:
+ break;
+ default:
+ /* Sanity check */
+ break;
+ }
+ return;
+}
+
+
+
+/*
+ * In physical mode, insert tc/tr for region 0 and 4 uses
+ * RID[0] and RID[4] which is for physical mode emulation.
+ * However what those inserted tc/tr wants is rid for
+ * virtual mode. So original virtual rid needs to be restored
+ * before insert.
+ *
+ * Operations which required such switch include:
+ * - insertions (itc.*, itr.*)
+ * - purges (ptc.* and ptr.*)
+ * - tpa
+ * - tak
+ * - thash?, ttag?
+ * All above needs actual virtual rid for destination entry.
+ */
+
+void check_mm_mode_switch(struct kvm_vcpu *vcpu, struct ia64_psr old_psr,
+ struct ia64_psr new_psr)
+{
+
+ if ((old_psr.dt != new_psr.dt)
+ || (old_psr.it != new_psr.it)
+ || (old_psr.rt != new_psr.rt))
+ switch_mm_mode(vcpu, old_psr, new_psr);
+
+ return;
+}
+
+
+/*
+ * In physical mode, insert tc/tr for region 0 and 4 uses
+ * RID[0] and RID[4] which is for physical mode emulation.
+ * However what those inserted tc/tr wants is rid for
+ * virtual mode. So original virtual rid needs to be restored
+ * before insert.
+ *
+ * Operations which required such switch include:
+ * - insertions (itc.*, itr.*)
+ * - purges (ptc.* and ptr.*)
+ * - tpa
+ * - tak
+ * - thash?, ttag?
+ * All above needs actual virtual rid for destination entry.
+ */
+
+void prepare_if_physical_mode(struct kvm_vcpu *vcpu)
+{
+ if (is_physical_mode(vcpu)) {
+ vcpu->arch.mode_flags |= GUEST_PHY_EMUL;
+ switch_to_virtual_rid(vcpu);
+ }
+ return;
+}
+
+/* Recover always follows prepare */
+void recover_if_physical_mode(struct kvm_vcpu *vcpu)
+{
+ if (is_physical_mode(vcpu))
+ switch_to_physical_rid(vcpu);
+ vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL;
+ return;
+}
+
+#define RPT(x) ((u16) &((struct kvm_pt_regs *)0)->x)
+
+static u16 gr_info[32] = {
+ 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */
+ RPT(r1), RPT(r2), RPT(r3),
+ RPT(r4), RPT(r5), RPT(r6), RPT(r7),
+ RPT(r8), RPT(r9), RPT(r10), RPT(r11),
+ RPT(r12), RPT(r13), RPT(r14), RPT(r15),
+ RPT(r16), RPT(r17), RPT(r18), RPT(r19),
+ RPT(r20), RPT(r21), RPT(r22), RPT(r23),
+ RPT(r24), RPT(r25), RPT(r26), RPT(r27),
+ RPT(r28), RPT(r29), RPT(r30), RPT(r31)
+};
+
+#define IA64_FIRST_STACKED_GR 32
+#define IA64_FIRST_ROTATING_FR 32
+
+static inline unsigned long
+rotate_reg(unsigned long sor, unsigned long rrb, unsigned long reg)
+{
+ reg += rrb;
+ if (reg >= sor)
+ reg -= sor;
+ return reg;
+}
+
+/*
+ * Return the (rotated) index for floating point register
+ * be in the REGNUM (REGNUM must range from 32-127,
+ * result is in the range from 0-95.
+ */
+static inline unsigned long fph_index(struct kvm_pt_regs *regs,
+ long regnum)
+{
+ unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f;
+ return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR));
+}
+
+
+/*
+ * The inverse of the above: given bspstore and the number of
+ * registers, calculate ar.bsp.
+ */
+static inline unsigned long *kvm_rse_skip_regs(unsigned long *addr,
+ long num_regs)
+{
+ long delta = ia64_rse_slot_num(addr) + num_regs;
+ int i = 0;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ if (delta < 0) {
+ while (delta <= -0x3f) {
+ i--;
+ delta += 0x3f;
+ }
+ } else {
+ while (delta >= 0x3f) {
+ i++;
+ delta -= 0x3f;
+ }
+ }
+
+ return addr + num_regs + i;
+}
+
+static void get_rse_reg(struct kvm_pt_regs *regs, unsigned long r1,
+ unsigned long *val, int *nat)
+{
+ unsigned long *bsp, *addr, *rnat_addr, *bspstore;
+ unsigned long *kbs = (void *) current_vcpu + VMM_RBS_OFFSET;
+ unsigned long nat_mask;
+ unsigned long old_rsc, new_rsc;
+ long sof = (regs->cr_ifs) & 0x7f;
+ long sor = (((regs->cr_ifs >> 14) & 0xf) << 3);
+ long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
+ long ridx = r1 - 32;
+
+ if (ridx < sor)
+ ridx = rotate_reg(sor, rrb_gr, ridx);
+
+ old_rsc = ia64_getreg(_IA64_REG_AR_RSC);
+ new_rsc = old_rsc&(~(0x3));
+ ia64_setreg(_IA64_REG_AR_RSC, new_rsc);
+
+ bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE);
+ bsp = kbs + (regs->loadrs >> 19);
+
+ addr = kvm_rse_skip_regs(bsp, -sof + ridx);
+ nat_mask = 1UL << ia64_rse_slot_num(addr);
+ rnat_addr = ia64_rse_rnat_addr(addr);
+
+ if (addr >= bspstore) {
+ ia64_flushrs();
+ ia64_mf();
+ bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE);
+ }
+ *val = *addr;
+ if (nat) {
+ if (bspstore < rnat_addr)
+ *nat = (int)!!(ia64_getreg(_IA64_REG_AR_RNAT)
+ & nat_mask);
+ else
+ *nat = (int)!!((*rnat_addr) & nat_mask);
+ ia64_setreg(_IA64_REG_AR_RSC, old_rsc);
+ }
+}
+
+void set_rse_reg(struct kvm_pt_regs *regs, unsigned long r1,
+ unsigned long val, unsigned long nat)
+{
+ unsigned long *bsp, *bspstore, *addr, *rnat_addr;
+ unsigned long *kbs = (void *) current_vcpu + VMM_RBS_OFFSET;
+ unsigned long nat_mask;
+ unsigned long old_rsc, new_rsc, psr;
+ unsigned long rnat;
+ long sof = (regs->cr_ifs) & 0x7f;
+ long sor = (((regs->cr_ifs >> 14) & 0xf) << 3);
+ long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
+ long ridx = r1 - 32;
+
+ if (ridx < sor)
+ ridx = rotate_reg(sor, rrb_gr, ridx);
+
+ old_rsc = ia64_getreg(_IA64_REG_AR_RSC);
+ /* put RSC to lazy mode, and set loadrs 0 */
+ new_rsc = old_rsc & (~0x3fff0003);
+ ia64_setreg(_IA64_REG_AR_RSC, new_rsc);
+ bsp = kbs + (regs->loadrs >> 19); /* 16 + 3 */
+
+ addr = kvm_rse_skip_regs(bsp, -sof + ridx);
+ nat_mask = 1UL << ia64_rse_slot_num(addr);
+ rnat_addr = ia64_rse_rnat_addr(addr);
+
+ local_irq_save(psr);
+ bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE);
+ if (addr >= bspstore) {
+
+ ia64_flushrs();
+ ia64_mf();
+ *addr = val;
+ bspstore = (unsigned long *)ia64_getreg(_IA64_REG_AR_BSPSTORE);
+ rnat = ia64_getreg(_IA64_REG_AR_RNAT);
+ if (bspstore < rnat_addr)
+ rnat = rnat & (~nat_mask);
+ else
+ *rnat_addr = (*rnat_addr)&(~nat_mask);
+
+ ia64_mf();
+ ia64_loadrs();
+ ia64_setreg(_IA64_REG_AR_RNAT, rnat);
+ } else {
+ rnat = ia64_getreg(_IA64_REG_AR_RNAT);
+ *addr = val;
+ if (bspstore < rnat_addr)
+ rnat = rnat&(~nat_mask);
+ else
+ *rnat_addr = (*rnat_addr) & (~nat_mask);
+
+ ia64_setreg(_IA64_REG_AR_BSPSTORE, bspstore);
+ ia64_setreg(_IA64_REG_AR_RNAT, rnat);
+ }
+ local_irq_restore(psr);
+ ia64_setreg(_IA64_REG_AR_RSC, old_rsc);
+}
+
+void getreg(unsigned long regnum, unsigned long *val,
+ int *nat, struct kvm_pt_regs *regs)
+{
+ unsigned long addr, *unat;
+ if (regnum >= IA64_FIRST_STACKED_GR) {
+ get_rse_reg(regs, regnum, val, nat);
+ return;
+ }
+
+ /*
+ * Now look at registers in [0-31] range and init correct UNAT
+ */
+ addr = (unsigned long)regs;
+ unat = &regs->eml_unat;;
+
+ addr += gr_info[regnum];
+
+ *val = *(unsigned long *)addr;
+ /*
+ * do it only when requested
+ */
+ if (nat)
+ *nat = (*unat >> ((addr >> 3) & 0x3f)) & 0x1UL;
+}
+
+void setreg(unsigned long regnum, unsigned long val,
+ int nat, struct kvm_pt_regs *regs)
+{
+ unsigned long addr;
+ unsigned long bitmask;
+ unsigned long *unat;
+
+ /*
+ * First takes care of stacked registers
+ */
+ if (regnum >= IA64_FIRST_STACKED_GR) {
+ set_rse_reg(regs, regnum, val, nat);
+ return;
+ }
+
+ /*
+ * Now look at registers in [0-31] range and init correct UNAT
+ */
+ addr = (unsigned long)regs;
+ unat = &regs->eml_unat;
+ /*
+ * add offset from base of struct
+ * and do it !
+ */
+ addr += gr_info[regnum];
+
+ *(unsigned long *)addr = val;
+
+ /*
+ * We need to clear the corresponding UNAT bit to fully emulate the load
+ * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4
+ */
+ bitmask = 1UL << ((addr >> 3) & 0x3f);
+ if (nat)
+ *unat |= bitmask;
+ else
+ *unat &= ~bitmask;
+
+}
+
+u64 vcpu_get_gr(struct kvm_vcpu *vcpu, unsigned long reg)
+{
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ u64 val;
+
+ if (!reg)
+ return 0;
+ getreg(reg, &val, 0, regs);
+ return val;
+}
+
+void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 value, int nat)
+{
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ long sof = (regs->cr_ifs) & 0x7f;
+
+ if (!reg)
+ return;
+ if (reg >= sof + 32)
+ return;
+ setreg(reg, value, nat, regs); /* FIXME: handle NATs later*/
+}
+
+void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval,
+ struct kvm_pt_regs *regs)
+{
+ /* Take floating register rotation into consideration*/
+ if (regnum >= IA64_FIRST_ROTATING_FR)
+ regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, regnum);
+#define CASE_FIXED_FP(reg) \
+ case (reg) : \
+ ia64_stf_spill(fpval, reg); \
+ break
+
+ switch (regnum) {
+ CASE_FIXED_FP(0);
+ CASE_FIXED_FP(1);
+ CASE_FIXED_FP(2);
+ CASE_FIXED_FP(3);
+ CASE_FIXED_FP(4);
+ CASE_FIXED_FP(5);
+
+ CASE_FIXED_FP(6);
+ CASE_FIXED_FP(7);
+ CASE_FIXED_FP(8);
+ CASE_FIXED_FP(9);
+ CASE_FIXED_FP(10);
+ CASE_FIXED_FP(11);
+
+ CASE_FIXED_FP(12);
+ CASE_FIXED_FP(13);
+ CASE_FIXED_FP(14);
+ CASE_FIXED_FP(15);
+ CASE_FIXED_FP(16);
+ CASE_FIXED_FP(17);
+ CASE_FIXED_FP(18);
+ CASE_FIXED_FP(19);
+ CASE_FIXED_FP(20);
+ CASE_FIXED_FP(21);
+ CASE_FIXED_FP(22);
+ CASE_FIXED_FP(23);
+ CASE_FIXED_FP(24);
+ CASE_FIXED_FP(25);
+ CASE_FIXED_FP(26);
+ CASE_FIXED_FP(27);
+ CASE_FIXED_FP(28);
+ CASE_FIXED_FP(29);
+ CASE_FIXED_FP(30);
+ CASE_FIXED_FP(31);
+ CASE_FIXED_FP(32);
+ CASE_FIXED_FP(33);
+ CASE_FIXED_FP(34);
+ CASE_FIXED_FP(35);
+ CASE_FIXED_FP(36);
+ CASE_FIXED_FP(37);
+ CASE_FIXED_FP(38);
+ CASE_FIXED_FP(39);
+ CASE_FIXED_FP(40);
+ CASE_FIXED_FP(41);
+ CASE_FIXED_FP(42);
+ CASE_FIXED_FP(43);
+ CASE_FIXED_FP(44);
+ CASE_FIXED_FP(45);
+ CASE_FIXED_FP(46);
+ CASE_FIXED_FP(47);
+ CASE_FIXED_FP(48);
+ CASE_FIXED_FP(49);
+ CASE_FIXED_FP(50);
+ CASE_FIXED_FP(51);
+ CASE_FIXED_FP(52);
+ CASE_FIXED_FP(53);
+ CASE_FIXED_FP(54);
+ CASE_FIXED_FP(55);
+ CASE_FIXED_FP(56);
+ CASE_FIXED_FP(57);
+ CASE_FIXED_FP(58);
+ CASE_FIXED_FP(59);
+ CASE_FIXED_FP(60);
+ CASE_FIXED_FP(61);
+ CASE_FIXED_FP(62);
+ CASE_FIXED_FP(63);
+ CASE_FIXED_FP(64);
+ CASE_FIXED_FP(65);
+ CASE_FIXED_FP(66);
+ CASE_FIXED_FP(67);
+ CASE_FIXED_FP(68);
+ CASE_FIXED_FP(69);
+ CASE_FIXED_FP(70);
+ CASE_FIXED_FP(71);
+ CASE_FIXED_FP(72);
+ CASE_FIXED_FP(73);
+ CASE_FIXED_FP(74);
+ CASE_FIXED_FP(75);
+ CASE_FIXED_FP(76);
+ CASE_FIXED_FP(77);
+ CASE_FIXED_FP(78);
+ CASE_FIXED_FP(79);
+ CASE_FIXED_FP(80);
+ CASE_FIXED_FP(81);
+ CASE_FIXED_FP(82);
+ CASE_FIXED_FP(83);
+ CASE_FIXED_FP(84);
+ CASE_FIXED_FP(85);
+ CASE_FIXED_FP(86);
+ CASE_FIXED_FP(87);
+ CASE_FIXED_FP(88);
+ CASE_FIXED_FP(89);
+ CASE_FIXED_FP(90);
+ CASE_FIXED_FP(91);
+ CASE_FIXED_FP(92);
+ CASE_FIXED_FP(93);
+ CASE_FIXED_FP(94);
+ CASE_FIXED_FP(95);
+ CASE_FIXED_FP(96);
+ CASE_FIXED_FP(97);
+ CASE_FIXED_FP(98);
+ CASE_FIXED_FP(99);
+ CASE_FIXED_FP(100);
+ CASE_FIXED_FP(101);
+ CASE_FIXED_FP(102);
+ CASE_FIXED_FP(103);
+ CASE_FIXED_FP(104);
+ CASE_FIXED_FP(105);
+ CASE_FIXED_FP(106);
+ CASE_FIXED_FP(107);
+ CASE_FIXED_FP(108);
+ CASE_FIXED_FP(109);
+ CASE_FIXED_FP(110);
+ CASE_FIXED_FP(111);
+ CASE_FIXED_FP(112);
+ CASE_FIXED_FP(113);
+ CASE_FIXED_FP(114);
+ CASE_FIXED_FP(115);
+ CASE_FIXED_FP(116);
+ CASE_FIXED_FP(117);
+ CASE_FIXED_FP(118);
+ CASE_FIXED_FP(119);
+ CASE_FIXED_FP(120);
+ CASE_FIXED_FP(121);
+ CASE_FIXED_FP(122);
+ CASE_FIXED_FP(123);
+ CASE_FIXED_FP(124);
+ CASE_FIXED_FP(125);
+ CASE_FIXED_FP(126);
+ CASE_FIXED_FP(127);
+ }
+#undef CASE_FIXED_FP
+}
+
+void setfpreg(unsigned long regnum, struct ia64_fpreg *fpval,
+ struct kvm_pt_regs *regs)
+{
+ /* Take floating register rotation into consideration*/
+ if (regnum >= IA64_FIRST_ROTATING_FR)
+ regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, regnum);
+
+#define CASE_FIXED_FP(reg) \
+ case (reg) : \
+ ia64_ldf_fill(reg, fpval); \
+ break
+
+ switch (regnum) {
+ CASE_FIXED_FP(2);
+ CASE_FIXED_FP(3);
+ CASE_FIXED_FP(4);
+ CASE_FIXED_FP(5);
+
+ CASE_FIXED_FP(6);
+ CASE_FIXED_FP(7);
+ CASE_FIXED_FP(8);
+ CASE_FIXED_FP(9);
+ CASE_FIXED_FP(10);
+ CASE_FIXED_FP(11);
+
+ CASE_FIXED_FP(12);
+ CASE_FIXED_FP(13);
+ CASE_FIXED_FP(14);
+ CASE_FIXED_FP(15);
+ CASE_FIXED_FP(16);
+ CASE_FIXED_FP(17);
+ CASE_FIXED_FP(18);
+ CASE_FIXED_FP(19);
+ CASE_FIXED_FP(20);
+ CASE_FIXED_FP(21);
+ CASE_FIXED_FP(22);
+ CASE_FIXED_FP(23);
+ CASE_FIXED_FP(24);
+ CASE_FIXED_FP(25);
+ CASE_FIXED_FP(26);
+ CASE_FIXED_FP(27);
+ CASE_FIXED_FP(28);
+ CASE_FIXED_FP(29);
+ CASE_FIXED_FP(30);
+ CASE_FIXED_FP(31);
+ CASE_FIXED_FP(32);
+ CASE_FIXED_FP(33);
+ CASE_FIXED_FP(34);
+ CASE_FIXED_FP(35);
+ CASE_FIXED_FP(36);
+ CASE_FIXED_FP(37);
+ CASE_FIXED_FP(38);
+ CASE_FIXED_FP(39);
+ CASE_FIXED_FP(40);
+ CASE_FIXED_FP(41);
+ CASE_FIXED_FP(42);
+ CASE_FIXED_FP(43);
+ CASE_FIXED_FP(44);
+ CASE_FIXED_FP(45);
+ CASE_FIXED_FP(46);
+ CASE_FIXED_FP(47);
+ CASE_FIXED_FP(48);
+ CASE_FIXED_FP(49);
+ CASE_FIXED_FP(50);
+ CASE_FIXED_FP(51);
+ CASE_FIXED_FP(52);
+ CASE_FIXED_FP(53);
+ CASE_FIXED_FP(54);
+ CASE_FIXED_FP(55);
+ CASE_FIXED_FP(56);
+ CASE_FIXED_FP(57);
+ CASE_FIXED_FP(58);
+ CASE_FIXED_FP(59);
+ CASE_FIXED_FP(60);
+ CASE_FIXED_FP(61);
+ CASE_FIXED_FP(62);
+ CASE_FIXED_FP(63);
+ CASE_FIXED_FP(64);
+ CASE_FIXED_FP(65);
+ CASE_FIXED_FP(66);
+ CASE_FIXED_FP(67);
+ CASE_FIXED_FP(68);
+ CASE_FIXED_FP(69);
+ CASE_FIXED_FP(70);
+ CASE_FIXED_FP(71);
+ CASE_FIXED_FP(72);
+ CASE_FIXED_FP(73);
+ CASE_FIXED_FP(74);
+ CASE_FIXED_FP(75);
+ CASE_FIXED_FP(76);
+ CASE_FIXED_FP(77);
+ CASE_FIXED_FP(78);
+ CASE_FIXED_FP(79);
+ CASE_FIXED_FP(80);
+ CASE_FIXED_FP(81);
+ CASE_FIXED_FP(82);
+ CASE_FIXED_FP(83);
+ CASE_FIXED_FP(84);
+ CASE_FIXED_FP(85);
+ CASE_FIXED_FP(86);
+ CASE_FIXED_FP(87);
+ CASE_FIXED_FP(88);
+ CASE_FIXED_FP(89);
+ CASE_FIXED_FP(90);
+ CASE_FIXED_FP(91);
+ CASE_FIXED_FP(92);
+ CASE_FIXED_FP(93);
+ CASE_FIXED_FP(94);
+ CASE_FIXED_FP(95);
+ CASE_FIXED_FP(96);
+ CASE_FIXED_FP(97);
+ CASE_FIXED_FP(98);
+ CASE_FIXED_FP(99);
+ CASE_FIXED_FP(100);
+ CASE_FIXED_FP(101);
+ CASE_FIXED_FP(102);
+ CASE_FIXED_FP(103);
+ CASE_FIXED_FP(104);
+ CASE_FIXED_FP(105);
+ CASE_FIXED_FP(106);
+ CASE_FIXED_FP(107);
+ CASE_FIXED_FP(108);
+ CASE_FIXED_FP(109);
+ CASE_FIXED_FP(110);
+ CASE_FIXED_FP(111);
+ CASE_FIXED_FP(112);
+ CASE_FIXED_FP(113);
+ CASE_FIXED_FP(114);
+ CASE_FIXED_FP(115);
+ CASE_FIXED_FP(116);
+ CASE_FIXED_FP(117);
+ CASE_FIXED_FP(118);
+ CASE_FIXED_FP(119);
+ CASE_FIXED_FP(120);
+ CASE_FIXED_FP(121);
+ CASE_FIXED_FP(122);
+ CASE_FIXED_FP(123);
+ CASE_FIXED_FP(124);
+ CASE_FIXED_FP(125);
+ CASE_FIXED_FP(126);
+ CASE_FIXED_FP(127);
+ }
+}
+
+void vcpu_get_fpreg(struct kvm_vcpu *vcpu, unsigned long reg,
+ struct ia64_fpreg *val)
+{
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ getfpreg(reg, val, regs); /* FIXME: handle NATs later*/
+}
+
+void vcpu_set_fpreg(struct kvm_vcpu *vcpu, unsigned long reg,
+ struct ia64_fpreg *val)
+{
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ if (reg > 1)
+ setfpreg(reg, val, regs); /* FIXME: handle NATs later*/
+}
+
+/************************************************************************
+ * lsapic timer
+ ***********************************************************************/
+u64 vcpu_get_itc(struct kvm_vcpu *vcpu)
+{
+ unsigned long guest_itc;
+ guest_itc = VMX(vcpu, itc_offset) + ia64_getreg(_IA64_REG_AR_ITC);
+
+ if (guest_itc >= VMX(vcpu, last_itc)) {
+ VMX(vcpu, last_itc) = guest_itc;
+ return guest_itc;
+ } else
+ return VMX(vcpu, last_itc);
+}
+
+static inline void vcpu_set_itm(struct kvm_vcpu *vcpu, u64 val);
+static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val)
+{
+ struct kvm_vcpu *v;
+ int i;
+ long itc_offset = val - ia64_getreg(_IA64_REG_AR_ITC);
+ unsigned long vitv = VCPU(vcpu, itv);
+
+ if (vcpu->vcpu_id == 0) {
+ for (i = 0; i < MAX_VCPU_NUM; i++) {
+ v = (struct kvm_vcpu *)((char *)vcpu + VCPU_SIZE * i);
+ VMX(v, itc_offset) = itc_offset;
+ VMX(v, last_itc) = 0;
+ }
+ }
+ VMX(vcpu, last_itc) = 0;
+ if (VCPU(vcpu, itm) <= val) {
+ VMX(vcpu, itc_check) = 0;
+ vcpu_unpend_interrupt(vcpu, vitv);
+ } else {
+ VMX(vcpu, itc_check) = 1;
+ vcpu_set_itm(vcpu, VCPU(vcpu, itm));
+ }
+
+}
+
+static inline u64 vcpu_get_itm(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, itm));
+}
+
+static inline void vcpu_set_itm(struct kvm_vcpu *vcpu, u64 val)
+{
+ unsigned long vitv = VCPU(vcpu, itv);
+ VCPU(vcpu, itm) = val;
+
+ if (val > vcpu_get_itc(vcpu)) {
+ VMX(vcpu, itc_check) = 1;
+ vcpu_unpend_interrupt(vcpu, vitv);
+ VMX(vcpu, timer_pending) = 0;
+ } else
+ VMX(vcpu, itc_check) = 0;
+}
+
+#define ITV_VECTOR(itv) (itv&0xff)
+#define ITV_IRQ_MASK(itv) (itv&(1<<16))
+
+static inline void vcpu_set_itv(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, itv) = val;
+ if (!ITV_IRQ_MASK(val) && vcpu->arch.timer_pending) {
+ vcpu_pend_interrupt(vcpu, ITV_VECTOR(val));
+ vcpu->arch.timer_pending = 0;
+ }
+}
+
+static inline void vcpu_set_eoi(struct kvm_vcpu *vcpu, u64 val)
+{
+ int vec;
+
+ vec = highest_inservice_irq(vcpu);
+ if (vec == NULL_VECTOR)
+ return;
+ VMX(vcpu, insvc[vec >> 6]) &= ~(1UL << (vec & 63));
+ VCPU(vcpu, eoi) = 0;
+ vcpu->arch.irq_new_pending = 1;
+
+}
+
+/* See Table 5-8 in SDM vol2 for the definition */
+int irq_masked(struct kvm_vcpu *vcpu, int h_pending, int h_inservice)
+{
+ union ia64_tpr vtpr;
+
+ vtpr.val = VCPU(vcpu, tpr);
+
+ if (h_inservice == NMI_VECTOR)
+ return IRQ_MASKED_BY_INSVC;
+
+ if (h_pending == NMI_VECTOR) {
+ /* Non Maskable Interrupt */
+ return IRQ_NO_MASKED;
+ }
+
+ if (h_inservice == ExtINT_VECTOR)
+ return IRQ_MASKED_BY_INSVC;
+
+ if (h_pending == ExtINT_VECTOR) {
+ if (vtpr.mmi) {
+ /* mask all external IRQ */
+ return IRQ_MASKED_BY_VTPR;
+ } else
+ return IRQ_NO_MASKED;
+ }
+
+ if (is_higher_irq(h_pending, h_inservice)) {
+ if (is_higher_class(h_pending, vtpr.mic + (vtpr.mmi << 4)))
+ return IRQ_NO_MASKED;
+ else
+ return IRQ_MASKED_BY_VTPR;
+ } else {
+ return IRQ_MASKED_BY_INSVC;
+ }
+}
+
+void vcpu_pend_interrupt(struct kvm_vcpu *vcpu, u8 vec)
+{
+ long spsr;
+ int ret;
+
+ local_irq_save(spsr);
+ ret = test_and_set_bit(vec, &VCPU(vcpu, irr[0]));
+ local_irq_restore(spsr);
+
+ vcpu->arch.irq_new_pending = 1;
+}
+
+void vcpu_unpend_interrupt(struct kvm_vcpu *vcpu, u8 vec)
+{
+ long spsr;
+ int ret;
+
+ local_irq_save(spsr);
+ ret = test_and_clear_bit(vec, &VCPU(vcpu, irr[0]));
+ local_irq_restore(spsr);
+ if (ret) {
+ vcpu->arch.irq_new_pending = 1;
+ wmb();
+ }
+}
+
+void update_vhpi(struct kvm_vcpu *vcpu, int vec)
+{
+ u64 vhpi;
+
+ if (vec == NULL_VECTOR)
+ vhpi = 0;
+ else if (vec == NMI_VECTOR)
+ vhpi = 32;
+ else if (vec == ExtINT_VECTOR)
+ vhpi = 16;
+ else
+ vhpi = vec >> 4;
+
+ VCPU(vcpu, vhpi) = vhpi;
+ if (VCPU(vcpu, vac).a_int)
+ ia64_call_vsa(PAL_VPS_SET_PENDING_INTERRUPT,
+ (u64)vcpu->arch.vpd, 0, 0, 0, 0, 0, 0);
+}
+
+u64 vcpu_get_ivr(struct kvm_vcpu *vcpu)
+{
+ int vec, h_inservice, mask;
+
+ vec = highest_pending_irq(vcpu);
+ h_inservice = highest_inservice_irq(vcpu);
+ mask = irq_masked(vcpu, vec, h_inservice);
+ if (vec == NULL_VECTOR || mask == IRQ_MASKED_BY_INSVC) {
+ if (VCPU(vcpu, vhpi))
+ update_vhpi(vcpu, NULL_VECTOR);
+ return IA64_SPURIOUS_INT_VECTOR;
+ }
+ if (mask == IRQ_MASKED_BY_VTPR) {
+ update_vhpi(vcpu, vec);
+ return IA64_SPURIOUS_INT_VECTOR;
+ }
+ VMX(vcpu, insvc[vec >> 6]) |= (1UL << (vec & 63));
+ vcpu_unpend_interrupt(vcpu, vec);
+ return (u64)vec;
+}
+
+/**************************************************************************
+ Privileged operation emulation routines
+ **************************************************************************/
+u64 vcpu_thash(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ union ia64_pta vpta;
+ union ia64_rr vrr;
+ u64 pval;
+ u64 vhpt_offset;
+
+ vpta.val = vcpu_get_pta(vcpu);
+ vrr.val = vcpu_get_rr(vcpu, vadr);
+ vhpt_offset = ((vadr >> vrr.ps) << 3) & ((1UL << (vpta.size)) - 1);
+ if (vpta.vf) {
+ pval = ia64_call_vsa(PAL_VPS_THASH, vadr, vrr.val,
+ vpta.val, 0, 0, 0, 0);
+ } else {
+ pval = (vadr & VRN_MASK) | vhpt_offset |
+ (vpta.val << 3 >> (vpta.size + 3) << (vpta.size));
+ }
+ return pval;
+}
+
+u64 vcpu_ttag(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ union ia64_rr vrr;
+ union ia64_pta vpta;
+ u64 pval;
+
+ vpta.val = vcpu_get_pta(vcpu);
+ vrr.val = vcpu_get_rr(vcpu, vadr);
+ if (vpta.vf) {
+ pval = ia64_call_vsa(PAL_VPS_TTAG, vadr, vrr.val,
+ 0, 0, 0, 0, 0);
+ } else
+ pval = 1;
+
+ return pval;
+}
+
+u64 vcpu_tak(struct kvm_vcpu *vcpu, u64 vadr)
+{
+ struct thash_data *data;
+ union ia64_pta vpta;
+ u64 key;
+
+ vpta.val = vcpu_get_pta(vcpu);
+ if (vpta.vf == 0) {
+ key = 1;
+ return key;
+ }
+ data = vtlb_lookup(vcpu, vadr, D_TLB);
+ if (!data || !data->p)
+ key = 1;
+ else
+ key = data->key;
+
+ return key;
+}
+
+
+
+void kvm_thash(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long thash, vadr;
+
+ vadr = vcpu_get_gr(vcpu, inst.M46.r3);
+ thash = vcpu_thash(vcpu, vadr);
+ vcpu_set_gr(vcpu, inst.M46.r1, thash, 0);
+}
+
+
+void kvm_ttag(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long tag, vadr;
+
+ vadr = vcpu_get_gr(vcpu, inst.M46.r3);
+ tag = vcpu_ttag(vcpu, vadr);
+ vcpu_set_gr(vcpu, inst.M46.r1, tag, 0);
+}
+
+int vcpu_tpa(struct kvm_vcpu *vcpu, u64 vadr, u64 *padr)
+{
+ struct thash_data *data;
+ union ia64_isr visr, pt_isr;
+ struct kvm_pt_regs *regs;
+ struct ia64_psr vpsr;
+
+ regs = vcpu_regs(vcpu);
+ pt_isr.val = VMX(vcpu, cr_isr);
+ visr.val = 0;
+ visr.ei = pt_isr.ei;
+ visr.ir = pt_isr.ir;
+ vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr);
+ visr.na = 1;
+
+ data = vhpt_lookup(vadr);
+ if (data) {
+ if (data->p == 0) {
+ vcpu_set_isr(vcpu, visr.val);
+ data_page_not_present(vcpu, vadr);
+ return IA64_FAULT;
+ } else if (data->ma == VA_MATTR_NATPAGE) {
+ vcpu_set_isr(vcpu, visr.val);
+ dnat_page_consumption(vcpu, vadr);
+ return IA64_FAULT;
+ } else {
+ *padr = (data->gpaddr >> data->ps << data->ps) |
+ (vadr & (PSIZE(data->ps) - 1));
+ return IA64_NO_FAULT;
+ }
+ }
+
+ data = vtlb_lookup(vcpu, vadr, D_TLB);
+ if (data) {
+ if (data->p == 0) {
+ vcpu_set_isr(vcpu, visr.val);
+ data_page_not_present(vcpu, vadr);
+ return IA64_FAULT;
+ } else if (data->ma == VA_MATTR_NATPAGE) {
+ vcpu_set_isr(vcpu, visr.val);
+ dnat_page_consumption(vcpu, vadr);
+ return IA64_FAULT;
+ } else{
+ *padr = ((data->ppn >> (data->ps - 12)) << data->ps)
+ | (vadr & (PSIZE(data->ps) - 1));
+ return IA64_NO_FAULT;
+ }
+ }
+ if (!vhpt_enabled(vcpu, vadr, NA_REF)) {
+ if (vpsr.ic) {
+ vcpu_set_isr(vcpu, visr.val);
+ alt_dtlb(vcpu, vadr);
+ return IA64_FAULT;
+ } else {
+ nested_dtlb(vcpu);
+ return IA64_FAULT;
+ }
+ } else {
+ if (vpsr.ic) {
+ vcpu_set_isr(vcpu, visr.val);
+ dvhpt_fault(vcpu, vadr);
+ return IA64_FAULT;
+ } else{
+ nested_dtlb(vcpu);
+ return IA64_FAULT;
+ }
+ }
+
+ return IA64_NO_FAULT;
+}
+
+
+int kvm_tpa(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r1, r3;
+
+ r3 = vcpu_get_gr(vcpu, inst.M46.r3);
+
+ if (vcpu_tpa(vcpu, r3, &r1))
+ return IA64_FAULT;
+
+ vcpu_set_gr(vcpu, inst.M46.r1, r1, 0);
+ return(IA64_NO_FAULT);
+}
+
+void kvm_tak(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r1, r3;
+
+ r3 = vcpu_get_gr(vcpu, inst.M46.r3);
+ r1 = vcpu_tak(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M46.r1, r1, 0);
+}
+
+
+/************************************
+ * Insert/Purge translation register/cache
+ ************************************/
+void vcpu_itc_i(struct kvm_vcpu *vcpu, u64 pte, u64 itir, u64 ifa)
+{
+ thash_purge_and_insert(vcpu, pte, itir, ifa, I_TLB);
+}
+
+void vcpu_itc_d(struct kvm_vcpu *vcpu, u64 pte, u64 itir, u64 ifa)
+{
+ thash_purge_and_insert(vcpu, pte, itir, ifa, D_TLB);
+}
+
+void vcpu_itr_i(struct kvm_vcpu *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa)
+{
+ u64 ps, va, rid;
+ struct thash_data *p_itr;
+
+ ps = itir_ps(itir);
+ va = PAGEALIGN(ifa, ps);
+ pte &= ~PAGE_FLAGS_RV_MASK;
+ rid = vcpu_get_rr(vcpu, ifa);
+ rid = rid & RR_RID_MASK;
+ p_itr = (struct thash_data *)&vcpu->arch.itrs[slot];
+ vcpu_set_tr(p_itr, pte, itir, va, rid);
+ vcpu_quick_region_set(VMX(vcpu, itr_regions), va);
+}
+
+
+void vcpu_itr_d(struct kvm_vcpu *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa)
+{
+ u64 gpfn;
+ u64 ps, va, rid;
+ struct thash_data *p_dtr;
+
+ ps = itir_ps(itir);
+ va = PAGEALIGN(ifa, ps);
+ pte &= ~PAGE_FLAGS_RV_MASK;
+
+ if (ps != _PAGE_SIZE_16M)
+ thash_purge_entries(vcpu, va, ps);
+ gpfn = (pte & _PAGE_PPN_MASK) >> PAGE_SHIFT;
+ if (__gpfn_is_io(gpfn))
+ pte |= VTLB_PTE_IO;
+ rid = vcpu_get_rr(vcpu, va);
+ rid = rid & RR_RID_MASK;
+ p_dtr = (struct thash_data *)&vcpu->arch.dtrs[slot];
+ vcpu_set_tr((struct thash_data *)&vcpu->arch.dtrs[slot],
+ pte, itir, va, rid);
+ vcpu_quick_region_set(VMX(vcpu, dtr_regions), va);
+}
+
+void vcpu_ptr_d(struct kvm_vcpu *vcpu, u64 ifa, u64 ps)
+{
+ int index;
+ u64 va;
+
+ va = PAGEALIGN(ifa, ps);
+ while ((index = vtr_find_overlap(vcpu, va, ps, D_TLB)) >= 0)
+ vcpu->arch.dtrs[index].page_flags = 0;
+
+ thash_purge_entries(vcpu, va, ps);
+}
+
+void vcpu_ptr_i(struct kvm_vcpu *vcpu, u64 ifa, u64 ps)
+{
+ int index;
+ u64 va;
+
+ va = PAGEALIGN(ifa, ps);
+ while ((index = vtr_find_overlap(vcpu, va, ps, I_TLB)) >= 0)
+ vcpu->arch.itrs[index].page_flags = 0;
+
+ thash_purge_entries(vcpu, va, ps);
+}
+
+void vcpu_ptc_l(struct kvm_vcpu *vcpu, u64 va, u64 ps)
+{
+ va = PAGEALIGN(va, ps);
+ thash_purge_entries(vcpu, va, ps);
+}
+
+void vcpu_ptc_e(struct kvm_vcpu *vcpu, u64 va)
+{
+ thash_purge_all(vcpu);
+}
+
+void vcpu_ptc_ga(struct kvm_vcpu *vcpu, u64 va, u64 ps)
+{
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+ long psr;
+ local_irq_save(psr);
+ p->exit_reason = EXIT_REASON_PTC_G;
+
+ p->u.ptc_g_data.rr = vcpu_get_rr(vcpu, va);
+ p->u.ptc_g_data.vaddr = va;
+ p->u.ptc_g_data.ps = ps;
+ vmm_transition(vcpu);
+ /* Do Local Purge Here*/
+ vcpu_ptc_l(vcpu, va, ps);
+ local_irq_restore(psr);
+}
+
+
+void vcpu_ptc_g(struct kvm_vcpu *vcpu, u64 va, u64 ps)
+{
+ vcpu_ptc_ga(vcpu, va, ps);
+}
+
+void kvm_ptc_e(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long ifa;
+
+ ifa = vcpu_get_gr(vcpu, inst.M45.r3);
+ vcpu_ptc_e(vcpu, ifa);
+}
+
+void kvm_ptc_g(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long ifa, itir;
+
+ ifa = vcpu_get_gr(vcpu, inst.M45.r3);
+ itir = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_ptc_g(vcpu, ifa, itir_ps(itir));
+}
+
+void kvm_ptc_ga(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long ifa, itir;
+
+ ifa = vcpu_get_gr(vcpu, inst.M45.r3);
+ itir = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_ptc_ga(vcpu, ifa, itir_ps(itir));
+}
+
+void kvm_ptc_l(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long ifa, itir;
+
+ ifa = vcpu_get_gr(vcpu, inst.M45.r3);
+ itir = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_ptc_l(vcpu, ifa, itir_ps(itir));
+}
+
+void kvm_ptr_d(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long ifa, itir;
+
+ ifa = vcpu_get_gr(vcpu, inst.M45.r3);
+ itir = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_ptr_d(vcpu, ifa, itir_ps(itir));
+}
+
+void kvm_ptr_i(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long ifa, itir;
+
+ ifa = vcpu_get_gr(vcpu, inst.M45.r3);
+ itir = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_ptr_i(vcpu, ifa, itir_ps(itir));
+}
+
+void kvm_itr_d(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long itir, ifa, pte, slot;
+
+ slot = vcpu_get_gr(vcpu, inst.M45.r3);
+ pte = vcpu_get_gr(vcpu, inst.M45.r2);
+ itir = vcpu_get_itir(vcpu);
+ ifa = vcpu_get_ifa(vcpu);
+ vcpu_itr_d(vcpu, slot, pte, itir, ifa);
+}
+
+
+
+void kvm_itr_i(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long itir, ifa, pte, slot;
+
+ slot = vcpu_get_gr(vcpu, inst.M45.r3);
+ pte = vcpu_get_gr(vcpu, inst.M45.r2);
+ itir = vcpu_get_itir(vcpu);
+ ifa = vcpu_get_ifa(vcpu);
+ vcpu_itr_i(vcpu, slot, pte, itir, ifa);
+}
+
+void kvm_itc_d(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long itir, ifa, pte;
+
+ itir = vcpu_get_itir(vcpu);
+ ifa = vcpu_get_ifa(vcpu);
+ pte = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_itc_d(vcpu, pte, itir, ifa);
+}
+
+void kvm_itc_i(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long itir, ifa, pte;
+
+ itir = vcpu_get_itir(vcpu);
+ ifa = vcpu_get_ifa(vcpu);
+ pte = vcpu_get_gr(vcpu, inst.M45.r2);
+ vcpu_itc_i(vcpu, pte, itir, ifa);
+}
+
+/*************************************
+ * Moves to semi-privileged registers
+ *************************************/
+
+void kvm_mov_to_ar_imm(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long imm;
+
+ if (inst.M30.s)
+ imm = -inst.M30.imm;
+ else
+ imm = inst.M30.imm;
+
+ vcpu_set_itc(vcpu, imm);
+}
+
+void kvm_mov_to_ar_reg(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r2;
+
+ r2 = vcpu_get_gr(vcpu, inst.M29.r2);
+ vcpu_set_itc(vcpu, r2);
+}
+
+
+void kvm_mov_from_ar_reg(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r1;
+
+ r1 = vcpu_get_itc(vcpu);
+ vcpu_set_gr(vcpu, inst.M31.r1, r1, 0);
+}
+/**************************************************************************
+ struct kvm_vcpu*protection key register access routines
+ **************************************************************************/
+
+unsigned long vcpu_get_pkr(struct kvm_vcpu *vcpu, unsigned long reg)
+{
+ return ((unsigned long)ia64_get_pkr(reg));
+}
+
+void vcpu_set_pkr(struct kvm_vcpu *vcpu, unsigned long reg, unsigned long val)
+{
+ ia64_set_pkr(reg, val);
+}
+
+
+unsigned long vcpu_get_itir_on_fault(struct kvm_vcpu *vcpu, unsigned long ifa)
+{
+ union ia64_rr rr, rr1;
+
+ rr.val = vcpu_get_rr(vcpu, ifa);
+ rr1.val = 0;
+ rr1.ps = rr.ps;
+ rr1.rid = rr.rid;
+ return (rr1.val);
+}
+
+
+
+/********************************
+ * Moves to privileged registers
+ ********************************/
+unsigned long vcpu_set_rr(struct kvm_vcpu *vcpu, unsigned long reg,
+ unsigned long val)
+{
+ union ia64_rr oldrr, newrr;
+ unsigned long rrval;
+ struct exit_ctl_data *p = &vcpu->arch.exit_data;
+ unsigned long psr;
+
+ oldrr.val = vcpu_get_rr(vcpu, reg);
+ newrr.val = val;
+ vcpu->arch.vrr[reg >> VRN_SHIFT] = val;
+
+ switch ((unsigned long)(reg >> VRN_SHIFT)) {
+ case VRN6:
+ vcpu->arch.vmm_rr = vrrtomrr(val);
+ local_irq_save(psr);
+ p->exit_reason = EXIT_REASON_SWITCH_RR6;
+ vmm_transition(vcpu);
+ local_irq_restore(psr);
+ break;
+ case VRN4:
+ rrval = vrrtomrr(val);
+ vcpu->arch.metaphysical_saved_rr4 = rrval;
+ if (!is_physical_mode(vcpu))
+ ia64_set_rr(reg, rrval);
+ break;
+ case VRN0:
+ rrval = vrrtomrr(val);
+ vcpu->arch.metaphysical_saved_rr0 = rrval;
+ if (!is_physical_mode(vcpu))
+ ia64_set_rr(reg, rrval);
+ break;
+ default:
+ ia64_set_rr(reg, vrrtomrr(val));
+ break;
+ }
+
+ return (IA64_NO_FAULT);
+}
+
+
+
+void kvm_mov_to_rr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r2;
+
+ r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ vcpu_set_rr(vcpu, r3, r2);
+}
+
+void kvm_mov_to_dbr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+}
+
+void kvm_mov_to_ibr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+}
+
+void kvm_mov_to_pmc(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r2;
+
+ r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ vcpu_set_pmc(vcpu, r3, r2);
+}
+
+void kvm_mov_to_pmd(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r2;
+
+ r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ vcpu_set_pmd(vcpu, r3, r2);
+}
+
+void kvm_mov_to_pkr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ u64 r3, r2;
+
+ r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ vcpu_set_pkr(vcpu, r3, r2);
+}
+
+
+
+void kvm_mov_from_rr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r1;
+
+ r3 = vcpu_get_gr(vcpu, inst.M43.r3);
+ r1 = vcpu_get_rr(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M43.r1, r1, 0);
+}
+
+void kvm_mov_from_pkr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r1;
+
+ r3 = vcpu_get_gr(vcpu, inst.M43.r3);
+ r1 = vcpu_get_pkr(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M43.r1, r1, 0);
+}
+
+void kvm_mov_from_dbr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r1;
+
+ r3 = vcpu_get_gr(vcpu, inst.M43.r3);
+ r1 = vcpu_get_dbr(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M43.r1, r1, 0);
+}
+
+void kvm_mov_from_ibr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r1;
+
+ r3 = vcpu_get_gr(vcpu, inst.M43.r3);
+ r1 = vcpu_get_ibr(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M43.r1, r1, 0);
+}
+
+void kvm_mov_from_pmc(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r1;
+
+ r3 = vcpu_get_gr(vcpu, inst.M43.r3);
+ r1 = vcpu_get_pmc(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M43.r1, r1, 0);
+}
+
+
+unsigned long vcpu_get_cpuid(struct kvm_vcpu *vcpu, unsigned long reg)
+{
+ /* FIXME: This could get called as a result of a rsvd-reg fault */
+ if (reg > (ia64_get_cpuid(3) & 0xff))
+ return 0;
+ else
+ return ia64_get_cpuid(reg);
+}
+
+void kvm_mov_from_cpuid(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r3, r1;
+
+ r3 = vcpu_get_gr(vcpu, inst.M43.r3);
+ r1 = vcpu_get_cpuid(vcpu, r3);
+ vcpu_set_gr(vcpu, inst.M43.r1, r1, 0);
+}
+
+void vcpu_set_tpr(struct kvm_vcpu *vcpu, unsigned long val)
+{
+ VCPU(vcpu, tpr) = val;
+ vcpu->arch.irq_check = 1;
+}
+
+unsigned long kvm_mov_to_cr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long r2;
+
+ r2 = vcpu_get_gr(vcpu, inst.M32.r2);
+ VCPU(vcpu, vcr[inst.M32.cr3]) = r2;
+
+ switch (inst.M32.cr3) {
+ case 0:
+ vcpu_set_dcr(vcpu, r2);
+ break;
+ case 1:
+ vcpu_set_itm(vcpu, r2);
+ break;
+ case 66:
+ vcpu_set_tpr(vcpu, r2);
+ break;
+ case 67:
+ vcpu_set_eoi(vcpu, r2);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+unsigned long kvm_mov_from_cr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long tgt = inst.M33.r1;
+ unsigned long val;
+
+ switch (inst.M33.cr3) {
+ case 65:
+ val = vcpu_get_ivr(vcpu);
+ vcpu_set_gr(vcpu, tgt, val, 0);
+ break;
+
+ case 67:
+ vcpu_set_gr(vcpu, tgt, 0L, 0);
+ break;
+ default:
+ val = VCPU(vcpu, vcr[inst.M33.cr3]);
+ vcpu_set_gr(vcpu, tgt, val, 0);
+ break;
+ }
+
+ return 0;
+}
+
+
+
+void vcpu_set_psr(struct kvm_vcpu *vcpu, unsigned long val)
+{
+
+ unsigned long mask;
+ struct kvm_pt_regs *regs;
+ struct ia64_psr old_psr, new_psr;
+
+ old_psr = *(struct ia64_psr *)&VCPU(vcpu, vpsr);
+
+ regs = vcpu_regs(vcpu);
+ /* We only support guest as:
+ * vpsr.pk = 0
+ * vpsr.is = 0
+ * Otherwise panic
+ */
+ if (val & (IA64_PSR_PK | IA64_PSR_IS | IA64_PSR_VM))
+ panic_vm(vcpu);
+
+ /*
+ * For those IA64_PSR bits: id/da/dd/ss/ed/ia
+ * Since these bits will become 0, after success execution of each
+ * instruction, we will change set them to mIA64_PSR
+ */
+ VCPU(vcpu, vpsr) = val
+ & (~(IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD |
+ IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA));
+
+ if (!old_psr.i && (val & IA64_PSR_I)) {
+ /* vpsr.i 0->1 */
+ vcpu->arch.irq_check = 1;
+ }
+ new_psr = *(struct ia64_psr *)&VCPU(vcpu, vpsr);
+
+ /*
+ * All vIA64_PSR bits shall go to mPSR (v->tf->tf_special.psr)
+ * , except for the following bits:
+ * ic/i/dt/si/rt/mc/it/bn/vm
+ */
+ mask = IA64_PSR_IC + IA64_PSR_I + IA64_PSR_DT + IA64_PSR_SI +
+ IA64_PSR_RT + IA64_PSR_MC + IA64_PSR_IT + IA64_PSR_BN +
+ IA64_PSR_VM;
+
+ regs->cr_ipsr = (regs->cr_ipsr & mask) | (val & (~mask));
+
+ check_mm_mode_switch(vcpu, old_psr, new_psr);
+
+ return ;
+}
+
+unsigned long vcpu_cover(struct kvm_vcpu *vcpu)
+{
+ struct ia64_psr vpsr;
+
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr);
+
+ if (!vpsr.ic)
+ VCPU(vcpu, ifs) = regs->cr_ifs;
+ regs->cr_ifs = IA64_IFS_V;
+ return (IA64_NO_FAULT);
+}
+
+
+
+/**************************************************************************
+ VCPU banked general register access routines
+ **************************************************************************/
+#define vcpu_bsw0_unat(i, b0unat, b1unat, runat, VMM_PT_REGS_R16_SLOT) \
+ do { \
+ __asm__ __volatile__ ( \
+ ";;extr.u %0 = %3,%6,16;;\n" \
+ "dep %1 = %0, %1, 0, 16;;\n" \
+ "st8 [%4] = %1\n" \
+ "extr.u %0 = %2, 16, 16;;\n" \
+ "dep %3 = %0, %3, %6, 16;;\n" \
+ "st8 [%5] = %3\n" \
+ ::"r"(i), "r"(*b1unat), "r"(*b0unat), \
+ "r"(*runat), "r"(b1unat), "r"(runat), \
+ "i"(VMM_PT_REGS_R16_SLOT) : "memory"); \
+ } while (0)
+
+void vcpu_bsw0(struct kvm_vcpu *vcpu)
+{
+ unsigned long i;
+
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ unsigned long *r = &regs->r16;
+ unsigned long *b0 = &VCPU(vcpu, vbgr[0]);
+ unsigned long *b1 = &VCPU(vcpu, vgr[0]);
+ unsigned long *runat = &regs->eml_unat;
+ unsigned long *b0unat = &VCPU(vcpu, vbnat);
+ unsigned long *b1unat = &VCPU(vcpu, vnat);
+
+
+ if (VCPU(vcpu, vpsr) & IA64_PSR_BN) {
+ for (i = 0; i < 16; i++) {
+ *b1++ = *r;
+ *r++ = *b0++;
+ }
+ vcpu_bsw0_unat(i, b0unat, b1unat, runat,
+ VMM_PT_REGS_R16_SLOT);
+ VCPU(vcpu, vpsr) &= ~IA64_PSR_BN;
+ }
+}
+
+#define vcpu_bsw1_unat(i, b0unat, b1unat, runat, VMM_PT_REGS_R16_SLOT) \
+ do { \
+ __asm__ __volatile__ (";;extr.u %0 = %3, %6, 16;;\n" \
+ "dep %1 = %0, %1, 16, 16;;\n" \
+ "st8 [%4] = %1\n" \
+ "extr.u %0 = %2, 0, 16;;\n" \
+ "dep %3 = %0, %3, %6, 16;;\n" \
+ "st8 [%5] = %3\n" \
+ ::"r"(i), "r"(*b0unat), "r"(*b1unat), \
+ "r"(*runat), "r"(b0unat), "r"(runat), \
+ "i"(VMM_PT_REGS_R16_SLOT) : "memory"); \
+ } while (0)
+
+void vcpu_bsw1(struct kvm_vcpu *vcpu)
+{
+ unsigned long i;
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ unsigned long *r = &regs->r16;
+ unsigned long *b0 = &VCPU(vcpu, vbgr[0]);
+ unsigned long *b1 = &VCPU(vcpu, vgr[0]);
+ unsigned long *runat = &regs->eml_unat;
+ unsigned long *b0unat = &VCPU(vcpu, vbnat);
+ unsigned long *b1unat = &VCPU(vcpu, vnat);
+
+ if (!(VCPU(vcpu, vpsr) & IA64_PSR_BN)) {
+ for (i = 0; i < 16; i++) {
+ *b0++ = *r;
+ *r++ = *b1++;
+ }
+ vcpu_bsw1_unat(i, b0unat, b1unat, runat,
+ VMM_PT_REGS_R16_SLOT);
+ VCPU(vcpu, vpsr) |= IA64_PSR_BN;
+ }
+}
+
+
+
+
+void vcpu_rfi(struct kvm_vcpu *vcpu)
+{
+ unsigned long ifs, psr;
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ psr = VCPU(vcpu, ipsr);
+ if (psr & IA64_PSR_BN)
+ vcpu_bsw1(vcpu);
+ else
+ vcpu_bsw0(vcpu);
+ vcpu_set_psr(vcpu, psr);
+ ifs = VCPU(vcpu, ifs);
+ if (ifs >> 63)
+ regs->cr_ifs = ifs;
+ regs->cr_iip = VCPU(vcpu, iip);
+}
+
+
+/*
+ VPSR can't keep track of below bits of guest PSR
+ This function gets guest PSR
+ */
+
+unsigned long vcpu_get_psr(struct kvm_vcpu *vcpu)
+{
+ unsigned long mask;
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+
+ mask = IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL |
+ IA64_PSR_MFH | IA64_PSR_CPL | IA64_PSR_RI;
+ return (VCPU(vcpu, vpsr) & ~mask) | (regs->cr_ipsr & mask);
+}
+
+void kvm_rsm(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long vpsr;
+ unsigned long imm24 = (inst.M44.i<<23) | (inst.M44.i2<<21)
+ | inst.M44.imm;
+
+ vpsr = vcpu_get_psr(vcpu);
+ vpsr &= (~imm24);
+ vcpu_set_psr(vcpu, vpsr);
+}
+
+void kvm_ssm(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long vpsr;
+ unsigned long imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21)
+ | inst.M44.imm;
+
+ vpsr = vcpu_get_psr(vcpu);
+ vpsr |= imm24;
+ vcpu_set_psr(vcpu, vpsr);
+}
+
+/* Generate Mask
+ * Parameter:
+ * bit -- starting bit
+ * len -- how many bits
+ */
+#define MASK(bit,len) \
+({ \
+ __u64 ret; \
+ \
+ __asm __volatile("dep %0=-1, r0, %1, %2"\
+ : "=r" (ret): \
+ "M" (bit), \
+ "M" (len)); \
+ ret; \
+})
+
+void vcpu_set_psr_l(struct kvm_vcpu *vcpu, unsigned long val)
+{
+ val = (val & MASK(0, 32)) | (vcpu_get_psr(vcpu) & MASK(32, 32));
+ vcpu_set_psr(vcpu, val);
+}
+
+void kvm_mov_to_psr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long val;
+
+ val = vcpu_get_gr(vcpu, inst.M35.r2);
+ vcpu_set_psr_l(vcpu, val);
+}
+
+void kvm_mov_from_psr(struct kvm_vcpu *vcpu, INST64 inst)
+{
+ unsigned long val;
+
+ val = vcpu_get_psr(vcpu);
+ val = (val & MASK(0, 32)) | (val & MASK(35, 2));
+ vcpu_set_gr(vcpu, inst.M33.r1, val, 0);
+}
+
+void vcpu_increment_iip(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ struct ia64_psr *ipsr = (struct ia64_psr *)&regs->cr_ipsr;
+ if (ipsr->ri == 2) {
+ ipsr->ri = 0;
+ regs->cr_iip += 16;
+ } else
+ ipsr->ri++;
+}
+
+void vcpu_decrement_iip(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pt_regs *regs = vcpu_regs(vcpu);
+ struct ia64_psr *ipsr = (struct ia64_psr *)&regs->cr_ipsr;
+
+ if (ipsr->ri == 0) {
+ ipsr->ri = 2;
+ regs->cr_iip -= 16;
+ } else
+ ipsr->ri--;
+}
+
+/** Emulate a privileged operation.
+ *
+ *
+ * @param vcpu virtual cpu
+ * @cause the reason cause virtualization fault
+ * @opcode the instruction code which cause virtualization fault
+ */
+
+void kvm_emulate(struct kvm_vcpu *vcpu, struct kvm_pt_regs *regs)
+{
+ unsigned long status, cause, opcode ;
+ INST64 inst;
+
+ status = IA64_NO_FAULT;
+ cause = VMX(vcpu, cause);
+ opcode = VMX(vcpu, opcode);
+ inst.inst = opcode;
+ /*
+ * Switch to actual virtual rid in rr0 and rr4,
+ * which is required by some tlb related instructions.
+ */
+ prepare_if_physical_mode(vcpu);
+
+ switch (cause) {
+ case EVENT_RSM:
+ kvm_rsm(vcpu, inst);
+ break;
+ case EVENT_SSM:
+ kvm_ssm(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_PSR:
+ kvm_mov_to_psr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_PSR:
+ kvm_mov_from_psr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_CR:
+ kvm_mov_from_cr(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_CR:
+ kvm_mov_to_cr(vcpu, inst);
+ break;
+ case EVENT_BSW_0:
+ vcpu_bsw0(vcpu);
+ break;
+ case EVENT_BSW_1:
+ vcpu_bsw1(vcpu);
+ break;
+ case EVENT_COVER:
+ vcpu_cover(vcpu);
+ break;
+ case EVENT_RFI:
+ vcpu_rfi(vcpu);
+ break;
+ case EVENT_ITR_D:
+ kvm_itr_d(vcpu, inst);
+ break;
+ case EVENT_ITR_I:
+ kvm_itr_i(vcpu, inst);
+ break;
+ case EVENT_PTR_D:
+ kvm_ptr_d(vcpu, inst);
+ break;
+ case EVENT_PTR_I:
+ kvm_ptr_i(vcpu, inst);
+ break;
+ case EVENT_ITC_D:
+ kvm_itc_d(vcpu, inst);
+ break;
+ case EVENT_ITC_I:
+ kvm_itc_i(vcpu, inst);
+ break;
+ case EVENT_PTC_L:
+ kvm_ptc_l(vcpu, inst);
+ break;
+ case EVENT_PTC_G:
+ kvm_ptc_g(vcpu, inst);
+ break;
+ case EVENT_PTC_GA:
+ kvm_ptc_ga(vcpu, inst);
+ break;
+ case EVENT_PTC_E:
+ kvm_ptc_e(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_RR:
+ kvm_mov_to_rr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_RR:
+ kvm_mov_from_rr(vcpu, inst);
+ break;
+ case EVENT_THASH:
+ kvm_thash(vcpu, inst);
+ break;
+ case EVENT_TTAG:
+ kvm_ttag(vcpu, inst);
+ break;
+ case EVENT_TPA:
+ status = kvm_tpa(vcpu, inst);
+ break;
+ case EVENT_TAK:
+ kvm_tak(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_AR_IMM:
+ kvm_mov_to_ar_imm(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_AR:
+ kvm_mov_to_ar_reg(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_AR:
+ kvm_mov_from_ar_reg(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_DBR:
+ kvm_mov_to_dbr(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_IBR:
+ kvm_mov_to_ibr(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_PMC:
+ kvm_mov_to_pmc(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_PMD:
+ kvm_mov_to_pmd(vcpu, inst);
+ break;
+ case EVENT_MOV_TO_PKR:
+ kvm_mov_to_pkr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_DBR:
+ kvm_mov_from_dbr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_IBR:
+ kvm_mov_from_ibr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_PMC:
+ kvm_mov_from_pmc(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_PKR:
+ kvm_mov_from_pkr(vcpu, inst);
+ break;
+ case EVENT_MOV_FROM_CPUID:
+ kvm_mov_from_cpuid(vcpu, inst);
+ break;
+ case EVENT_VMSW:
+ status = IA64_FAULT;
+ break;
+ default:
+ break;
+ };
+ /*Assume all status is NO_FAULT ?*/
+ if (status == IA64_NO_FAULT && cause != EVENT_RFI)
+ vcpu_increment_iip(vcpu);
+
+ recover_if_physical_mode(vcpu);
+}
+
+void init_vcpu(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ vcpu->arch.mode_flags = GUEST_IN_PHY;
+ VMX(vcpu, vrr[0]) = 0x38;
+ VMX(vcpu, vrr[1]) = 0x38;
+ VMX(vcpu, vrr[2]) = 0x38;
+ VMX(vcpu, vrr[3]) = 0x38;
+ VMX(vcpu, vrr[4]) = 0x38;
+ VMX(vcpu, vrr[5]) = 0x38;
+ VMX(vcpu, vrr[6]) = 0x38;
+ VMX(vcpu, vrr[7]) = 0x38;
+ VCPU(vcpu, vpsr) = IA64_PSR_BN;
+ VCPU(vcpu, dcr) = 0;
+ /* pta.size must not be 0. The minimum is 15 (32k) */
+ VCPU(vcpu, pta) = 15 << 2;
+ VCPU(vcpu, itv) = 0x10000;
+ VCPU(vcpu, itm) = 0;
+ VMX(vcpu, last_itc) = 0;
+
+ VCPU(vcpu, lid) = VCPU_LID(vcpu);
+ VCPU(vcpu, ivr) = 0;
+ VCPU(vcpu, tpr) = 0x10000;
+ VCPU(vcpu, eoi) = 0;
+ VCPU(vcpu, irr[0]) = 0;
+ VCPU(vcpu, irr[1]) = 0;
+ VCPU(vcpu, irr[2]) = 0;
+ VCPU(vcpu, irr[3]) = 0;
+ VCPU(vcpu, pmv) = 0x10000;
+ VCPU(vcpu, cmcv) = 0x10000;
+ VCPU(vcpu, lrr0) = 0x10000; /* default reset value? */
+ VCPU(vcpu, lrr1) = 0x10000; /* default reset value? */
+ update_vhpi(vcpu, NULL_VECTOR);
+ VLSAPIC_XTP(vcpu) = 0x80; /* disabled */
+
+ for (i = 0; i < 4; i++)
+ VLSAPIC_INSVC(vcpu, i) = 0;
+}
+
+void kvm_init_all_rr(struct kvm_vcpu *vcpu)
+{
+ unsigned long psr;
+
+ local_irq_save(psr);
+
+ /* WARNING: not allow co-exist of both virtual mode and physical
+ * mode in same region
+ */
+
+ vcpu->arch.metaphysical_saved_rr0 = vrrtomrr(VMX(vcpu, vrr[VRN0]));
+ vcpu->arch.metaphysical_saved_rr4 = vrrtomrr(VMX(vcpu, vrr[VRN4]));
+
+ if (is_physical_mode(vcpu)) {
+ if (vcpu->arch.mode_flags & GUEST_PHY_EMUL)
+ panic_vm(vcpu);
+
+ ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->arch.metaphysical_rr0);
+ ia64_dv_serialize_data();
+ ia64_set_rr((VRN4 << VRN_SHIFT), vcpu->arch.metaphysical_rr4);
+ ia64_dv_serialize_data();
+ } else {
+ ia64_set_rr((VRN0 << VRN_SHIFT),
+ vcpu->arch.metaphysical_saved_rr0);
+ ia64_dv_serialize_data();
+ ia64_set_rr((VRN4 << VRN_SHIFT),
+ vcpu->arch.metaphysical_saved_rr4);
+ ia64_dv_serialize_data();
+ }
+ ia64_set_rr((VRN1 << VRN_SHIFT),
+ vrrtomrr(VMX(vcpu, vrr[VRN1])));
+ ia64_dv_serialize_data();
+ ia64_set_rr((VRN2 << VRN_SHIFT),
+ vrrtomrr(VMX(vcpu, vrr[VRN2])));
+ ia64_dv_serialize_data();
+ ia64_set_rr((VRN3 << VRN_SHIFT),
+ vrrtomrr(VMX(vcpu, vrr[VRN3])));
+ ia64_dv_serialize_data();
+ ia64_set_rr((VRN5 << VRN_SHIFT),
+ vrrtomrr(VMX(vcpu, vrr[VRN5])));
+ ia64_dv_serialize_data();
+ ia64_set_rr((VRN7 << VRN_SHIFT),
+ vrrtomrr(VMX(vcpu, vrr[VRN7])));
+ ia64_dv_serialize_data();
+ ia64_srlz_d();
+ ia64_set_psr(psr);
+}
+
+int vmm_entry(void)
+{
+ struct kvm_vcpu *v;
+ v = current_vcpu;
+
+ ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)v->arch.vpd,
+ 0, 0, 0, 0, 0, 0);
+ kvm_init_vtlb(v);
+ kvm_init_vhpt(v);
+ init_vcpu(v);
+ kvm_init_all_rr(v);
+ vmm_reset_entry();
+
+ return 0;
+}
+
+void panic_vm(struct kvm_vcpu *v)
+{
+ struct exit_ctl_data *p = &v->arch.exit_data;
+
+ p->exit_reason = EXIT_REASON_VM_PANIC;
+ vmm_transition(v);
+ /*Never to return*/
+ while (1);
+}
diff --git a/arch/ia64/kvm/vcpu.h b/arch/ia64/kvm/vcpu.h
new file mode 100644
index 000000000000..b0fcfb62c49e
--- /dev/null
+++ b/arch/ia64/kvm/vcpu.h
@@ -0,0 +1,740 @@
+/*
+ * vcpu.h: vcpu routines
+ * Copyright (c) 2005, Intel Corporation.
+ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
+ * Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
+ *
+ * Copyright (c) 2007, Intel Corporation.
+ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 __KVM_VCPU_H__
+#define __KVM_VCPU_H__
+
+#include <asm/types.h>
+#include <asm/fpu.h>
+#include <asm/processor.h>
+
+#ifndef __ASSEMBLY__
+#include "vti.h"
+
+#include <linux/kvm_host.h>
+#include <linux/spinlock.h>
+
+typedef unsigned long IA64_INST;
+
+typedef union U_IA64_BUNDLE {
+ unsigned long i64[2];
+ struct { unsigned long template:5, slot0:41, slot1a:18,
+ slot1b:23, slot2:41; };
+ /* NOTE: following doesn't work because bitfields can't cross natural
+ size boundaries
+ struct { unsigned long template:5, slot0:41, slot1:41, slot2:41; }; */
+} IA64_BUNDLE;
+
+typedef union U_INST64_A5 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, imm7b:7, r3:2, imm5c:5,
+ imm9d:9, s:1, major:4; };
+} INST64_A5;
+
+typedef union U_INST64_B4 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, btype:3, un3:3, p:1, b2:3, un11:11, x6:6,
+ wh:2, d:1, un1:1, major:4; };
+} INST64_B4;
+
+typedef union U_INST64_B8 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, un21:21, x6:6, un4:4, major:4; };
+} INST64_B8;
+
+typedef union U_INST64_B9 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, imm20:20, :1, x6:6, :3, i:1, major:4; };
+} INST64_B9;
+
+typedef union U_INST64_I19 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, imm20:20, :1, x6:6, x3:3, i:1, major:4; };
+} INST64_I19;
+
+typedef union U_INST64_I26 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, ar3:7, x6:6, x3:3, :1, major:4; };
+} INST64_I26;
+
+typedef union U_INST64_I27 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, imm:7, ar3:7, x6:6, x3:3, s:1, major:4; };
+} INST64_I27;
+
+typedef union U_INST64_I28 { /* not privileged (mov from AR) */
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, :7, ar3:7, x6:6, x3:3, :1, major:4; };
+} INST64_I28;
+
+typedef union U_INST64_M28 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :14, r3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M28;
+
+typedef union U_INST64_M29 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, ar3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M29;
+
+typedef union U_INST64_M30 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, imm:7, ar3:7, x4:4, x2:2,
+ x3:3, s:1, major:4; };
+} INST64_M30;
+
+typedef union U_INST64_M31 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, :7, ar3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M31;
+
+typedef union U_INST64_M32 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, cr3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M32;
+
+typedef union U_INST64_M33 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, :7, cr3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M33;
+
+typedef union U_INST64_M35 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, :7, x6:6, x3:3, :1, major:4; };
+
+} INST64_M35;
+
+typedef union U_INST64_M36 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, :14, x6:6, x3:3, :1, major:4; };
+} INST64_M36;
+
+typedef union U_INST64_M37 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, imm20a:20, :1, x4:4, x2:2, x3:3,
+ i:1, major:4; };
+} INST64_M37;
+
+typedef union U_INST64_M41 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, :7, x6:6, x3:3, :1, major:4; };
+} INST64_M41;
+
+typedef union U_INST64_M42 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, r3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M42;
+
+typedef union U_INST64_M43 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, :7, r3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M43;
+
+typedef union U_INST64_M44 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, imm:21, x4:4, i2:2, x3:3, i:1, major:4; };
+} INST64_M44;
+
+typedef union U_INST64_M45 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, r2:7, r3:7, x6:6, x3:3, :1, major:4; };
+} INST64_M45;
+
+typedef union U_INST64_M46 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, un7:7, r3:7, x6:6,
+ x3:3, un1:1, major:4; };
+} INST64_M46;
+
+typedef union U_INST64_M47 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, un14:14, r3:7, x6:6, x3:3, un1:1, major:4; };
+} INST64_M47;
+
+typedef union U_INST64_M1{
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, un7:7, r3:7, x:1, hint:2,
+ x6:6, m:1, major:4; };
+} INST64_M1;
+
+typedef union U_INST64_M2{
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, r2:7, r3:7, x:1, hint:2,
+ x6:6, m:1, major:4; };
+} INST64_M2;
+
+typedef union U_INST64_M3{
+ IA64_INST inst;
+ struct { unsigned long qp:6, r1:7, imm7:7, r3:7, i:1, hint:2,
+ x6:6, s:1, major:4; };
+} INST64_M3;
+
+typedef union U_INST64_M4 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, un7:7, r2:7, r3:7, x:1, hint:2,
+ x6:6, m:1, major:4; };
+} INST64_M4;
+
+typedef union U_INST64_M5 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, imm7:7, r2:7, r3:7, i:1, hint:2,
+ x6:6, s:1, major:4; };
+} INST64_M5;
+
+typedef union U_INST64_M6 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, f1:7, un7:7, r3:7, x:1, hint:2,
+ x6:6, m:1, major:4; };
+} INST64_M6;
+
+typedef union U_INST64_M9 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, f2:7, r3:7, x:1, hint:2,
+ x6:6, m:1, major:4; };
+} INST64_M9;
+
+typedef union U_INST64_M10 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, imm7:7, f2:7, r3:7, i:1, hint:2,
+ x6:6, s:1, major:4; };
+} INST64_M10;
+
+typedef union U_INST64_M12 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, f1:7, f2:7, r3:7, x:1, hint:2,
+ x6:6, m:1, major:4; };
+} INST64_M12;
+
+typedef union U_INST64_M15 {
+ IA64_INST inst;
+ struct { unsigned long qp:6, :7, imm7:7, r3:7, i:1, hint:2,
+ x6:6, s:1, major:4; };
+} INST64_M15;
+
+typedef union U_INST64 {
+ IA64_INST inst;
+ struct { unsigned long :37, major:4; } generic;
+ INST64_A5 A5; /* used in build_hypercall_bundle only */
+ INST64_B4 B4; /* used in build_hypercall_bundle only */
+ INST64_B8 B8; /* rfi, bsw.[01] */
+ INST64_B9 B9; /* break.b */
+ INST64_I19 I19; /* used in build_hypercall_bundle only */
+ INST64_I26 I26; /* mov register to ar (I unit) */
+ INST64_I27 I27; /* mov immediate to ar (I unit) */
+ INST64_I28 I28; /* mov from ar (I unit) */
+ INST64_M1 M1; /* ld integer */
+ INST64_M2 M2;
+ INST64_M3 M3;
+ INST64_M4 M4; /* st integer */
+ INST64_M5 M5;
+ INST64_M6 M6; /* ldfd floating pointer */
+ INST64_M9 M9; /* stfd floating pointer */
+ INST64_M10 M10; /* stfd floating pointer */
+ INST64_M12 M12; /* ldfd pair floating pointer */
+ INST64_M15 M15; /* lfetch + imm update */
+ INST64_M28 M28; /* purge translation cache entry */
+ INST64_M29 M29; /* mov register to ar (M unit) */
+ INST64_M30 M30; /* mov immediate to ar (M unit) */
+ INST64_M31 M31; /* mov from ar (M unit) */
+ INST64_M32 M32; /* mov reg to cr */
+ INST64_M33 M33; /* mov from cr */
+ INST64_M35 M35; /* mov to psr */
+ INST64_M36 M36; /* mov from psr */
+ INST64_M37 M37; /* break.m */
+ INST64_M41 M41; /* translation cache insert */
+ INST64_M42 M42; /* mov to indirect reg/translation reg insert*/
+ INST64_M43 M43; /* mov from indirect reg */
+ INST64_M44 M44; /* set/reset system mask */
+ INST64_M45 M45; /* translation purge */
+ INST64_M46 M46; /* translation access (tpa,tak) */
+ INST64_M47 M47; /* purge translation entry */
+} INST64;
+
+#define MASK_41 ((unsigned long)0x1ffffffffff)
+
+/* Virtual address memory attributes encoding */
+#define VA_MATTR_WB 0x0
+#define VA_MATTR_UC 0x4
+#define VA_MATTR_UCE 0x5
+#define VA_MATTR_WC 0x6
+#define VA_MATTR_NATPAGE 0x7
+
+#define PMASK(size) (~((size) - 1))
+#define PSIZE(size) (1UL<<(size))
+#define CLEARLSB(ppn, nbits) (((ppn) >> (nbits)) << (nbits))
+#define PAGEALIGN(va, ps) CLEARLSB(va, ps)
+#define PAGE_FLAGS_RV_MASK (0x2|(0x3UL<<50)|(((1UL<<11)-1)<<53))
+#define _PAGE_MA_ST (0x1 << 2) /* is reserved for software use */
+
+#define ARCH_PAGE_SHIFT 12
+
+#define INVALID_TI_TAG (1UL << 63)
+
+#define VTLB_PTE_P_BIT 0
+#define VTLB_PTE_IO_BIT 60
+#define VTLB_PTE_IO (1UL<<VTLB_PTE_IO_BIT)
+#define VTLB_PTE_P (1UL<<VTLB_PTE_P_BIT)
+
+#define vcpu_quick_region_check(_tr_regions,_ifa) \
+ (_tr_regions & (1 << ((unsigned long)_ifa >> 61)))
+
+#define vcpu_quick_region_set(_tr_regions,_ifa) \
+ do {_tr_regions |= (1 << ((unsigned long)_ifa >> 61)); } while (0)
+
+static inline void vcpu_set_tr(struct thash_data *trp, u64 pte, u64 itir,
+ u64 va, u64 rid)
+{
+ trp->page_flags = pte;
+ trp->itir = itir;
+ trp->vadr = va;
+ trp->rid = rid;
+}
+
+extern u64 kvm_lookup_mpa(u64 gpfn);
+extern u64 kvm_gpa_to_mpa(u64 gpa);
+
+/* Return I/O type if trye */
+#define __gpfn_is_io(gpfn) \
+ ({ \
+ u64 pte, ret = 0; \
+ pte = kvm_lookup_mpa(gpfn); \
+ if (!(pte & GPFN_INV_MASK)) \
+ ret = pte & GPFN_IO_MASK; \
+ ret; \
+ })
+
+#endif
+
+#define IA64_NO_FAULT 0
+#define IA64_FAULT 1
+
+#define VMM_RBS_OFFSET ((VMM_TASK_SIZE + 15) & ~15)
+
+#define SW_BAD 0 /* Bad mode transitition */
+#define SW_V2P 1 /* Physical emulatino is activated */
+#define SW_P2V 2 /* Exit physical mode emulation */
+#define SW_SELF 3 /* No mode transition */
+#define SW_NOP 4 /* Mode transition, but without action required */
+
+#define GUEST_IN_PHY 0x1
+#define GUEST_PHY_EMUL 0x2
+
+#define current_vcpu ((struct kvm_vcpu *) ia64_getreg(_IA64_REG_TP))
+
+#define VRN_SHIFT 61
+#define VRN_MASK 0xe000000000000000
+#define VRN0 0x0UL
+#define VRN1 0x1UL
+#define VRN2 0x2UL
+#define VRN3 0x3UL
+#define VRN4 0x4UL
+#define VRN5 0x5UL
+#define VRN6 0x6UL
+#define VRN7 0x7UL
+
+#define IRQ_NO_MASKED 0
+#define IRQ_MASKED_BY_VTPR 1
+#define IRQ_MASKED_BY_INSVC 2 /* masked by inservice IRQ */
+
+#define PTA_BASE_SHIFT 15
+
+#define IA64_PSR_VM_BIT 46
+#define IA64_PSR_VM (__IA64_UL(1) << IA64_PSR_VM_BIT)
+
+/* Interruption Function State */
+#define IA64_IFS_V_BIT 63
+#define IA64_IFS_V (__IA64_UL(1) << IA64_IFS_V_BIT)
+
+#define PHY_PAGE_UC (_PAGE_A|_PAGE_D|_PAGE_P|_PAGE_MA_UC|_PAGE_AR_RWX)
+#define PHY_PAGE_WB (_PAGE_A|_PAGE_D|_PAGE_P|_PAGE_MA_WB|_PAGE_AR_RWX)
+
+#ifndef __ASSEMBLY__
+
+#include <asm/gcc_intrin.h>
+
+#define is_physical_mode(v) \
+ ((v->arch.mode_flags) & GUEST_IN_PHY)
+
+#define is_virtual_mode(v) \
+ (!is_physical_mode(v))
+
+#define MODE_IND(psr) \
+ (((psr).it << 2) + ((psr).dt << 1) + (psr).rt)
+
+#define _vmm_raw_spin_lock(x) \
+ do { \
+ __u32 *ia64_spinlock_ptr = (__u32 *) (x); \
+ __u64 ia64_spinlock_val; \
+ ia64_spinlock_val = ia64_cmpxchg4_acq(ia64_spinlock_ptr, 1, 0);\
+ if (unlikely(ia64_spinlock_val)) { \
+ do { \
+ while (*ia64_spinlock_ptr) \
+ ia64_barrier(); \
+ ia64_spinlock_val = \
+ ia64_cmpxchg4_acq(ia64_spinlock_ptr, 1, 0);\
+ } while (ia64_spinlock_val); \
+ } \
+ } while (0)
+
+#define _vmm_raw_spin_unlock(x) \
+ do { barrier(); \
+ ((spinlock_t *)x)->raw_lock.lock = 0; } \
+while (0)
+
+void vmm_spin_lock(spinlock_t *lock);
+void vmm_spin_unlock(spinlock_t *lock);
+enum {
+ I_TLB = 1,
+ D_TLB = 2
+};
+
+union kvm_va {
+ struct {
+ unsigned long off : 60; /* intra-region offset */
+ unsigned long reg : 4; /* region number */
+ } f;
+ unsigned long l;
+ void *p;
+};
+
+#define __kvm_pa(x) ({union kvm_va _v; _v.l = (long) (x); \
+ _v.f.reg = 0; _v.l; })
+#define __kvm_va(x) ({union kvm_va _v; _v.l = (long) (x); \
+ _v.f.reg = -1; _v.p; })
+
+#define _REGION_ID(x) ({union ia64_rr _v; _v.val = (long)(x); \
+ _v.rid; })
+#define _REGION_PAGE_SIZE(x) ({union ia64_rr _v; _v.val = (long)(x); \
+ _v.ps; })
+#define _REGION_HW_WALKER(x) ({union ia64_rr _v; _v.val = (long)(x); \
+ _v.ve; })
+
+enum vhpt_ref{ DATA_REF, NA_REF, INST_REF, RSE_REF };
+enum tlb_miss_type { INSTRUCTION, DATA, REGISTER };
+
+#define VCPU(_v, _x) ((_v)->arch.vpd->_x)
+#define VMX(_v, _x) ((_v)->arch._x)
+
+#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.insvc[i])
+#define VLSAPIC_XTP(_v) VMX(_v, xtp)
+
+static inline unsigned long itir_ps(unsigned long itir)
+{
+ return ((itir >> 2) & 0x3f);
+}
+
+
+/**************************************************************************
+ VCPU control register access routines
+ **************************************************************************/
+
+static inline u64 vcpu_get_itir(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, itir));
+}
+
+static inline void vcpu_set_itir(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, itir) = val;
+}
+
+static inline u64 vcpu_get_ifa(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, ifa));
+}
+
+static inline void vcpu_set_ifa(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, ifa) = val;
+}
+
+static inline u64 vcpu_get_iva(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, iva));
+}
+
+static inline u64 vcpu_get_pta(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, pta));
+}
+
+static inline u64 vcpu_get_lid(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, lid));
+}
+
+static inline u64 vcpu_get_tpr(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, tpr));
+}
+
+static inline u64 vcpu_get_eoi(struct kvm_vcpu *vcpu)
+{
+ return (0UL); /*reads of eoi always return 0 */
+}
+
+static inline u64 vcpu_get_irr0(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, irr[0]));
+}
+
+static inline u64 vcpu_get_irr1(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, irr[1]));
+}
+
+static inline u64 vcpu_get_irr2(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, irr[2]));
+}
+
+static inline u64 vcpu_get_irr3(struct kvm_vcpu *vcpu)
+{
+ return ((u64)VCPU(vcpu, irr[3]));
+}
+
+static inline void vcpu_set_dcr(struct kvm_vcpu *vcpu, u64 val)
+{
+ ia64_setreg(_IA64_REG_CR_DCR, val);
+}
+
+static inline void vcpu_set_isr(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, isr) = val;
+}
+
+static inline void vcpu_set_lid(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, lid) = val;
+}
+
+static inline void vcpu_set_ipsr(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, ipsr) = val;
+}
+
+static inline void vcpu_set_iip(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, iip) = val;
+}
+
+static inline void vcpu_set_ifs(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, ifs) = val;
+}
+
+static inline void vcpu_set_iipa(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, iipa) = val;
+}
+
+static inline void vcpu_set_iha(struct kvm_vcpu *vcpu, u64 val)
+{
+ VCPU(vcpu, iha) = val;
+}
+
+
+static inline u64 vcpu_get_rr(struct kvm_vcpu *vcpu, u64 reg)
+{
+ return vcpu->arch.vrr[reg>>61];
+}
+
+/**************************************************************************
+ VCPU debug breakpoint register access routines
+ **************************************************************************/
+
+static inline void vcpu_set_dbr(struct kvm_vcpu *vcpu, u64 reg, u64 val)
+{
+ __ia64_set_dbr(reg, val);
+}
+
+static inline void vcpu_set_ibr(struct kvm_vcpu *vcpu, u64 reg, u64 val)
+{
+ ia64_set_ibr(reg, val);
+}
+
+static inline u64 vcpu_get_dbr(struct kvm_vcpu *vcpu, u64 reg)
+{
+ return ((u64)__ia64_get_dbr(reg));
+}
+
+static inline u64 vcpu_get_ibr(struct kvm_vcpu *vcpu, u64 reg)
+{
+ return ((u64)ia64_get_ibr(reg));
+}
+
+/**************************************************************************
+ VCPU performance monitor register access routines
+ **************************************************************************/
+static inline void vcpu_set_pmc(struct kvm_vcpu *vcpu, u64 reg, u64 val)
+{
+ /* NOTE: Writes to unimplemented PMC registers are discarded */
+ ia64_set_pmc(reg, val);
+}
+
+static inline void vcpu_set_pmd(struct kvm_vcpu *vcpu, u64 reg, u64 val)
+{
+ /* NOTE: Writes to unimplemented PMD registers are discarded */
+ ia64_set_pmd(reg, val);
+}
+
+static inline u64 vcpu_get_pmc(struct kvm_vcpu *vcpu, u64 reg)
+{
+ /* NOTE: Reads from unimplemented PMC registers return zero */
+ return ((u64)ia64_get_pmc(reg));
+}
+
+static inline u64 vcpu_get_pmd(struct kvm_vcpu *vcpu, u64 reg)
+{
+ /* NOTE: Reads from unimplemented PMD registers return zero */
+ return ((u64)ia64_get_pmd(reg));
+}
+
+static inline unsigned long vrrtomrr(unsigned long val)
+{
+ union ia64_rr rr;
+ rr.val = val;
+ rr.rid = (rr.rid << 4) | 0xe;
+ if (rr.ps > PAGE_SHIFT)
+ rr.ps = PAGE_SHIFT;
+ rr.ve = 1;
+ return rr.val;
+}
+
+
+static inline int highest_bits(int *dat)
+{
+ u32 bits, bitnum;
+ int i;
+
+ /* loop for all 256 bits */
+ for (i = 7; i >= 0 ; i--) {
+ bits = dat[i];
+ if (bits) {
+ bitnum = fls(bits);
+ return i * 32 + bitnum - 1;
+ }
+ }
+ return NULL_VECTOR;
+}
+
+/*
+ * The pending irq is higher than the inservice one.
+ *
+ */
+static inline int is_higher_irq(int pending, int inservice)
+{
+ return ((pending > inservice)
+ || ((pending != NULL_VECTOR)
+ && (inservice == NULL_VECTOR)));
+}
+
+static inline int is_higher_class(int pending, int mic)
+{
+ return ((pending >> 4) > mic);
+}
+
+/*
+ * Return 0-255 for pending irq.
+ * NULL_VECTOR: when no pending.
+ */
+static inline int highest_pending_irq(struct kvm_vcpu *vcpu)
+{
+ if (VCPU(vcpu, irr[0]) & (1UL<<NMI_VECTOR))
+ return NMI_VECTOR;
+ if (VCPU(vcpu, irr[0]) & (1UL<<ExtINT_VECTOR))
+ return ExtINT_VECTOR;
+
+ return highest_bits((int *)&VCPU(vcpu, irr[0]));
+}
+
+static inline int highest_inservice_irq(struct kvm_vcpu *vcpu)
+{
+ if (VMX(vcpu, insvc[0]) & (1UL<<NMI_VECTOR))
+ return NMI_VECTOR;
+ if (VMX(vcpu, insvc[0]) & (1UL<<ExtINT_VECTOR))
+ return ExtINT_VECTOR;
+
+ return highest_bits((int *)&(VMX(vcpu, insvc[0])));
+}
+
+extern void vcpu_get_fpreg(struct kvm_vcpu *vcpu, u64 reg,
+ struct ia64_fpreg *val);
+extern void vcpu_set_fpreg(struct kvm_vcpu *vcpu, u64 reg,
+ struct ia64_fpreg *val);
+extern u64 vcpu_get_gr(struct kvm_vcpu *vcpu, u64 reg);
+extern void vcpu_set_gr(struct kvm_vcpu *vcpu, u64 reg, u64 val, int nat);
+extern u64 vcpu_get_psr(struct kvm_vcpu *vcpu);
+extern void vcpu_set_psr(struct kvm_vcpu *vcpu, u64 val);
+extern u64 vcpu_thash(struct kvm_vcpu *vcpu, u64 vadr);
+extern void vcpu_bsw0(struct kvm_vcpu *vcpu);
+extern void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte,
+ u64 itir, u64 va, int type);
+extern struct thash_data *vhpt_lookup(u64 va);
+extern u64 guest_vhpt_lookup(u64 iha, u64 *pte);
+extern void thash_purge_entries(struct kvm_vcpu *v, u64 va, u64 ps);
+extern void thash_purge_entries_remote(struct kvm_vcpu *v, u64 va, u64 ps);
+extern u64 translate_phy_pte(u64 *pte, u64 itir, u64 va);
+extern int thash_purge_and_insert(struct kvm_vcpu *v, u64 pte,
+ u64 itir, u64 ifa, int type);
+extern void thash_purge_all(struct kvm_vcpu *v);
+extern struct thash_data *vtlb_lookup(struct kvm_vcpu *v,
+ u64 va, int is_data);
+extern int vtr_find_overlap(struct kvm_vcpu *vcpu, u64 va,
+ u64 ps, int is_data);
+
+extern void vcpu_increment_iip(struct kvm_vcpu *v);
+extern void vcpu_decrement_iip(struct kvm_vcpu *vcpu);
+extern void vcpu_pend_interrupt(struct kvm_vcpu *vcpu, u8 vec);
+extern void vcpu_unpend_interrupt(struct kvm_vcpu *vcpu, u8 vec);
+extern void data_page_not_present(struct kvm_vcpu *vcpu, u64 vadr);
+extern void dnat_page_consumption(struct kvm_vcpu *vcpu, u64 vadr);
+extern void alt_dtlb(struct kvm_vcpu *vcpu, u64 vadr);
+extern void nested_dtlb(struct kvm_vcpu *vcpu);
+extern void dvhpt_fault(struct kvm_vcpu *vcpu, u64 vadr);
+extern int vhpt_enabled(struct kvm_vcpu *vcpu, u64 vadr, enum vhpt_ref ref);
+
+extern void update_vhpi(struct kvm_vcpu *vcpu, int vec);
+extern int irq_masked(struct kvm_vcpu *vcpu, int h_pending, int h_inservice);
+
+extern int fetch_code(struct kvm_vcpu *vcpu, u64 gip, IA64_BUNDLE *pbundle);
+extern void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma);
+extern void vmm_transition(struct kvm_vcpu *vcpu);
+extern void vmm_trampoline(union context *from, union context *to);
+extern int vmm_entry(void);
+extern u64 vcpu_get_itc(struct kvm_vcpu *vcpu);
+
+extern void vmm_reset_entry(void);
+void kvm_init_vtlb(struct kvm_vcpu *v);
+void kvm_init_vhpt(struct kvm_vcpu *v);
+void thash_init(struct thash_cb *hcb, u64 sz);
+
+void panic_vm(struct kvm_vcpu *v);
+
+extern u64 ia64_call_vsa(u64 proc, u64 arg1, u64 arg2, u64 arg3,
+ u64 arg4, u64 arg5, u64 arg6, u64 arg7);
+#endif
+#endif /* __VCPU_H__ */
diff --git a/arch/ia64/kvm/vmm.c b/arch/ia64/kvm/vmm.c
new file mode 100644
index 000000000000..2275bf4e681a
--- /dev/null
+++ b/arch/ia64/kvm/vmm.c
@@ -0,0 +1,66 @@
+/*
+ * vmm.c: vmm module interface with kvm module
+ *
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * Xiantao Zhang (xiantao.zhang@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+
+#include<linux/module.h>
+#include<asm/fpswa.h>
+
+#include "vcpu.h"
+
+MODULE_AUTHOR("Intel");
+MODULE_LICENSE("GPL");
+
+extern char kvm_ia64_ivt;
+extern fpswa_interface_t *vmm_fpswa_interface;
+
+struct kvm_vmm_info vmm_info = {
+ .module = THIS_MODULE,
+ .vmm_entry = vmm_entry,
+ .tramp_entry = vmm_trampoline,
+ .vmm_ivt = (unsigned long)&kvm_ia64_ivt,
+};
+
+static int __init kvm_vmm_init(void)
+{
+
+ vmm_fpswa_interface = fpswa_interface;
+
+ /*Register vmm data to kvm side*/
+ return kvm_init(&vmm_info, 1024, THIS_MODULE);
+}
+
+static void __exit kvm_vmm_exit(void)
+{
+ kvm_exit();
+ return ;
+}
+
+void vmm_spin_lock(spinlock_t *lock)
+{
+ _vmm_raw_spin_lock(lock);
+}
+
+void vmm_spin_unlock(spinlock_t *lock)
+{
+ _vmm_raw_spin_unlock(lock);
+}
+module_init(kvm_vmm_init)
+module_exit(kvm_vmm_exit)
diff --git a/arch/ia64/kvm/vmm_ivt.S b/arch/ia64/kvm/vmm_ivt.S
new file mode 100644
index 000000000000..3ee5f481c06d
--- /dev/null
+++ b/arch/ia64/kvm/vmm_ivt.S
@@ -0,0 +1,1424 @@
+/*
+ * /ia64/kvm_ivt.S
+ *
+ * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co
+ * Stephane Eranian <eranian@hpl.hp.com>
+ * David Mosberger <davidm@hpl.hp.com>
+ * Copyright (C) 2000, 2002-2003 Intel Co
+ * Asit Mallick <asit.k.mallick@intel.com>
+ * Suresh Siddha <suresh.b.siddha@intel.com>
+ * Kenneth Chen <kenneth.w.chen@intel.com>
+ * Fenghua Yu <fenghua.yu@intel.com>
+ *
+ *
+ * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling
+ * for SMP
+ * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB
+ * handler now uses virtual PT.
+ *
+ * 07/6/20 Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
+ * Supporting Intel virtualization architecture
+ *
+ */
+
+/*
+ * This file defines the interruption vector table used by the CPU.
+ * It does not include one entry per possible cause of interruption.
+ *
+ * The first 20 entries of the table contain 64 bundles each while the
+ * remaining 48 entries contain only 16 bundles each.
+ *
+ * The 64 bundles are used to allow inlining the whole handler for
+ * critical
+ * interruptions like TLB misses.
+ *
+ * For each entry, the comment is as follows:
+ *
+ * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss
+ * (12,51)
+ * entry offset ----/ / / /
+ * /
+ * entry number ---------/ / /
+ * /
+ * size of the entry -------------/ /
+ * /
+ * vector name -------------------------------------/
+ * /
+ * interruptions triggering this vector
+ * ----------------------/
+ *
+ * The table is 32KB in size and must be aligned on 32KB
+ * boundary.
+ * (The CPU ignores the 15 lower bits of the address)
+ *
+ * Table is based upon EAS2.6 (Oct 1999)
+ */
+
+
+#include <asm/asmmacro.h>
+#include <asm/cache.h>
+#include <asm/pgtable.h>
+
+#include "asm-offsets.h"
+#include "vcpu.h"
+#include "kvm_minstate.h"
+#include "vti.h"
+
+#if 1
+# define PSR_DEFAULT_BITS psr.ac
+#else
+# define PSR_DEFAULT_BITS 0
+#endif
+
+
+#define KVM_FAULT(n) \
+ kvm_fault_##n:; \
+ mov r19=n;; \
+ br.sptk.many kvm_fault_##n; \
+ ;; \
+
+
+#define KVM_REFLECT(n) \
+ mov r31=pr; \
+ mov r19=n; /* prepare to save predicates */ \
+ mov r29=cr.ipsr; \
+ ;; \
+ tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \
+(p7)br.sptk.many kvm_dispatch_reflection; \
+ br.sptk.many kvm_panic; \
+
+
+GLOBAL_ENTRY(kvm_panic)
+ br.sptk.many kvm_panic
+ ;;
+END(kvm_panic)
+
+
+
+
+
+ .section .text.ivt,"ax"
+
+ .align 32768 // align on 32KB boundary
+ .global kvm_ia64_ivt
+kvm_ia64_ivt:
+///////////////////////////////////////////////////////////////
+// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47)
+ENTRY(kvm_vhpt_miss)
+ KVM_FAULT(0)
+END(kvm_vhpt_miss)
+
+
+ .org kvm_ia64_ivt+0x400
+////////////////////////////////////////////////////////////////
+// 0x0400 Entry 1 (size 64 bundles) ITLB (21)
+ENTRY(kvm_itlb_miss)
+ mov r31 = pr
+ mov r29=cr.ipsr;
+ ;;
+ tbit.z p6,p7=r29,IA64_PSR_VM_BIT;
+ (p6) br.sptk kvm_alt_itlb_miss
+ mov r19 = 1
+ br.sptk kvm_itlb_miss_dispatch
+ KVM_FAULT(1);
+END(kvm_itlb_miss)
+
+ .org kvm_ia64_ivt+0x0800
+//////////////////////////////////////////////////////////////////
+// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48)
+ENTRY(kvm_dtlb_miss)
+ mov r31 = pr
+ mov r29=cr.ipsr;
+ ;;
+ tbit.z p6,p7=r29,IA64_PSR_VM_BIT;
+(p6)br.sptk kvm_alt_dtlb_miss
+ br.sptk kvm_dtlb_miss_dispatch
+END(kvm_dtlb_miss)
+
+ .org kvm_ia64_ivt+0x0c00
+////////////////////////////////////////////////////////////////////
+// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19)
+ENTRY(kvm_alt_itlb_miss)
+ mov r16=cr.ifa // get address that caused the TLB miss
+ ;;
+ movl r17=PAGE_KERNEL
+ mov r24=cr.ipsr
+ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
+ ;;
+ and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
+ ;;
+ or r19=r17,r19 // insert PTE control bits into r19
+ ;;
+ movl r20=IA64_GRANULE_SHIFT<<2
+ ;;
+ mov cr.itir=r20
+ ;;
+ itc.i r19 // insert the TLB entry
+ mov pr=r31,-1
+ rfi
+END(kvm_alt_itlb_miss)
+
+ .org kvm_ia64_ivt+0x1000
+/////////////////////////////////////////////////////////////////////
+// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46)
+ENTRY(kvm_alt_dtlb_miss)
+ mov r16=cr.ifa // get address that caused the TLB miss
+ ;;
+ movl r17=PAGE_KERNEL
+ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
+ mov r24=cr.ipsr
+ ;;
+ and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
+ ;;
+ or r19=r19,r17 // insert PTE control bits into r19
+ ;;
+ movl r20=IA64_GRANULE_SHIFT<<2
+ ;;
+ mov cr.itir=r20
+ ;;
+ itc.d r19 // insert the TLB entry
+ mov pr=r31,-1
+ rfi
+END(kvm_alt_dtlb_miss)
+
+ .org kvm_ia64_ivt+0x1400
+//////////////////////////////////////////////////////////////////////
+// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45)
+ENTRY(kvm_nested_dtlb_miss)
+ KVM_FAULT(5)
+END(kvm_nested_dtlb_miss)
+
+ .org kvm_ia64_ivt+0x1800
+/////////////////////////////////////////////////////////////////////
+// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24)
+ENTRY(kvm_ikey_miss)
+ KVM_REFLECT(6)
+END(kvm_ikey_miss)
+
+ .org kvm_ia64_ivt+0x1c00
+/////////////////////////////////////////////////////////////////////
+// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51)
+ENTRY(kvm_dkey_miss)
+ KVM_REFLECT(7)
+END(kvm_dkey_miss)
+
+ .org kvm_ia64_ivt+0x2000
+////////////////////////////////////////////////////////////////////
+// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54)
+ENTRY(kvm_dirty_bit)
+ KVM_REFLECT(8)
+END(kvm_dirty_bit)
+
+ .org kvm_ia64_ivt+0x2400
+////////////////////////////////////////////////////////////////////
+// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27)
+ENTRY(kvm_iaccess_bit)
+ KVM_REFLECT(9)
+END(kvm_iaccess_bit)
+
+ .org kvm_ia64_ivt+0x2800
+///////////////////////////////////////////////////////////////////
+// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55)
+ENTRY(kvm_daccess_bit)
+ KVM_REFLECT(10)
+END(kvm_daccess_bit)
+
+ .org kvm_ia64_ivt+0x2c00
+/////////////////////////////////////////////////////////////////
+// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33)
+ENTRY(kvm_break_fault)
+ mov r31=pr
+ mov r19=11
+ mov r29=cr.ipsr
+ ;;
+ KVM_SAVE_MIN_WITH_COVER_R19
+ ;;
+ alloc r14=ar.pfs,0,0,4,0 // now it's safe (must be first in insn group!)
+ mov out0=cr.ifa
+ mov out2=cr.isr // FIXME: pity to make this slow access twice
+ mov out3=cr.iim // FIXME: pity to make this slow access twice
+ adds r3=8,r2 // set up second base pointer
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i // guarantee that interruption collection is on
+ ;;
+ //(p15)ssm psr.i // restore psr.i
+ addl r14=@gprel(ia64_leave_hypervisor),gp
+ ;;
+ KVM_SAVE_REST
+ mov rp=r14
+ ;;
+ adds out1=16,sp
+ br.call.sptk.many b6=kvm_ia64_handle_break
+ ;;
+END(kvm_break_fault)
+
+ .org kvm_ia64_ivt+0x3000
+/////////////////////////////////////////////////////////////////
+// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4)
+ENTRY(kvm_interrupt)
+ mov r31=pr // prepare to save predicates
+ mov r19=12
+ mov r29=cr.ipsr
+ ;;
+ tbit.z p6,p7=r29,IA64_PSR_VM_BIT
+ tbit.z p0,p15=r29,IA64_PSR_I_BIT
+ ;;
+(p7) br.sptk kvm_dispatch_interrupt
+ ;;
+ mov r27=ar.rsc /* M */
+ mov r20=r1 /* A */
+ mov r25=ar.unat /* M */
+ mov r26=ar.pfs /* I */
+ mov r28=cr.iip /* M */
+ cover /* B (or nothing) */
+ ;;
+ mov r1=sp
+ ;;
+ invala /* M */
+ mov r30=cr.ifs
+ ;;
+ addl r1=-VMM_PT_REGS_SIZE,r1
+ ;;
+ adds r17=2*L1_CACHE_BYTES,r1 /* really: biggest cache-line size */
+ adds r16=PT(CR_IPSR),r1
+ ;;
+ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES
+ st8 [r16]=r29 /* save cr.ipsr */
+ ;;
+ lfetch.fault.excl.nt1 [r17]
+ mov r29=b0
+ ;;
+ adds r16=PT(R8),r1 /* initialize first base pointer */
+ adds r17=PT(R9),r1 /* initialize second base pointer */
+ mov r18=r0 /* make sure r18 isn't NaT */
+ ;;
+.mem.offset 0,0; st8.spill [r16]=r8,16
+.mem.offset 8,0; st8.spill [r17]=r9,16
+ ;;
+.mem.offset 0,0; st8.spill [r16]=r10,24
+.mem.offset 8,0; st8.spill [r17]=r11,24
+ ;;
+ st8 [r16]=r28,16 /* save cr.iip */
+ st8 [r17]=r30,16 /* save cr.ifs */
+ mov r8=ar.fpsr /* M */
+ mov r9=ar.csd
+ mov r10=ar.ssd
+ movl r11=FPSR_DEFAULT /* L-unit */
+ ;;
+ st8 [r16]=r25,16 /* save ar.unat */
+ st8 [r17]=r26,16 /* save ar.pfs */
+ shl r18=r18,16 /* compute ar.rsc to be used for "loadrs" */
+ ;;
+ st8 [r16]=r27,16 /* save ar.rsc */
+ adds r17=16,r17 /* skip over ar_rnat field */
+ ;;
+ st8 [r17]=r31,16 /* save predicates */
+ adds r16=16,r16 /* skip over ar_bspstore field */
+ ;;
+ st8 [r16]=r29,16 /* save b0 */
+ st8 [r17]=r18,16 /* save ar.rsc value for "loadrs" */
+ ;;
+.mem.offset 0,0; st8.spill [r16]=r20,16 /* save original r1 */
+.mem.offset 8,0; st8.spill [r17]=r12,16
+ adds r12=-16,r1
+ /* switch to kernel memory stack (with 16 bytes of scratch) */
+ ;;
+.mem.offset 0,0; st8.spill [r16]=r13,16
+.mem.offset 8,0; st8.spill [r17]=r8,16 /* save ar.fpsr */
+ ;;
+.mem.offset 0,0; st8.spill [r16]=r15,16
+.mem.offset 8,0; st8.spill [r17]=r14,16
+ dep r14=-1,r0,60,4
+ ;;
+.mem.offset 0,0; st8.spill [r16]=r2,16
+.mem.offset 8,0; st8.spill [r17]=r3,16
+ adds r2=VMM_PT_REGS_R16_OFFSET,r1
+ adds r14 = VMM_VCPU_GP_OFFSET,r13
+ ;;
+ mov r8=ar.ccv
+ ld8 r14 = [r14]
+ ;;
+ mov r1=r14 /* establish kernel global pointer */
+ ;; \
+ bsw.1
+ ;;
+ alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group
+ mov out0=r13
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i
+ ;;
+ //(p15) ssm psr.i
+ adds r3=8,r2 // set up second base pointer for SAVE_REST
+ srlz.i // ensure everybody knows psr.ic is back on
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r16,16
+.mem.offset 8,0; st8.spill [r3]=r17,16
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r18,16
+.mem.offset 8,0; st8.spill [r3]=r19,16
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r20,16
+.mem.offset 8,0; st8.spill [r3]=r21,16
+ mov r18=b6
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r22,16
+.mem.offset 8,0; st8.spill [r3]=r23,16
+ mov r19=b7
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r24,16
+.mem.offset 8,0; st8.spill [r3]=r25,16
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r26,16
+.mem.offset 8,0; st8.spill [r3]=r27,16
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r28,16
+.mem.offset 8,0; st8.spill [r3]=r29,16
+ ;;
+.mem.offset 0,0; st8.spill [r2]=r30,16
+.mem.offset 8,0; st8.spill [r3]=r31,32
+ ;;
+ mov ar.fpsr=r11 /* M-unit */
+ st8 [r2]=r8,8 /* ar.ccv */
+ adds r24=PT(B6)-PT(F7),r3
+ ;;
+ stf.spill [r2]=f6,32
+ stf.spill [r3]=f7,32
+ ;;
+ stf.spill [r2]=f8,32
+ stf.spill [r3]=f9,32
+ ;;
+ stf.spill [r2]=f10
+ stf.spill [r3]=f11
+ adds r25=PT(B7)-PT(F11),r3
+ ;;
+ st8 [r24]=r18,16 /* b6 */
+ st8 [r25]=r19,16 /* b7 */
+ ;;
+ st8 [r24]=r9 /* ar.csd */
+ st8 [r25]=r10 /* ar.ssd */
+ ;;
+ srlz.d // make sure we see the effect of cr.ivr
+ addl r14=@gprel(ia64_leave_nested),gp
+ ;;
+ mov rp=r14
+ br.call.sptk.many b6=kvm_ia64_handle_irq
+ ;;
+END(kvm_interrupt)
+
+ .global kvm_dispatch_vexirq
+ .org kvm_ia64_ivt+0x3400
+//////////////////////////////////////////////////////////////////////
+// 0x3400 Entry 13 (size 64 bundles) Reserved
+ENTRY(kvm_virtual_exirq)
+ mov r31=pr
+ mov r19=13
+ mov r30 =r0
+ ;;
+kvm_dispatch_vexirq:
+ cmp.eq p6,p0 = 1,r30
+ ;;
+(p6)add r29 = VMM_VCPU_SAVED_GP_OFFSET,r21
+ ;;
+(p6)ld8 r1 = [r29]
+ ;;
+ KVM_SAVE_MIN_WITH_COVER_R19
+ alloc r14=ar.pfs,0,0,1,0
+ mov out0=r13
+
+ ssm psr.ic
+ ;;
+ srlz.i // guarantee that interruption collection is on
+ ;;
+ //(p15) ssm psr.i // restore psr.i
+ adds r3=8,r2 // set up second base pointer
+ ;;
+ KVM_SAVE_REST
+ addl r14=@gprel(ia64_leave_hypervisor),gp
+ ;;
+ mov rp=r14
+ br.call.sptk.many b6=kvm_vexirq
+END(kvm_virtual_exirq)
+
+ .org kvm_ia64_ivt+0x3800
+/////////////////////////////////////////////////////////////////////
+// 0x3800 Entry 14 (size 64 bundles) Reserved
+ KVM_FAULT(14)
+ // this code segment is from 2.6.16.13
+
+
+ .org kvm_ia64_ivt+0x3c00
+///////////////////////////////////////////////////////////////////////
+// 0x3c00 Entry 15 (size 64 bundles) Reserved
+ KVM_FAULT(15)
+
+
+ .org kvm_ia64_ivt+0x4000
+///////////////////////////////////////////////////////////////////////
+// 0x4000 Entry 16 (size 64 bundles) Reserved
+ KVM_FAULT(16)
+
+ .org kvm_ia64_ivt+0x4400
+//////////////////////////////////////////////////////////////////////
+// 0x4400 Entry 17 (size 64 bundles) Reserved
+ KVM_FAULT(17)
+
+ .org kvm_ia64_ivt+0x4800
+//////////////////////////////////////////////////////////////////////
+// 0x4800 Entry 18 (size 64 bundles) Reserved
+ KVM_FAULT(18)
+
+ .org kvm_ia64_ivt+0x4c00
+//////////////////////////////////////////////////////////////////////
+// 0x4c00 Entry 19 (size 64 bundles) Reserved
+ KVM_FAULT(19)
+
+ .org kvm_ia64_ivt+0x5000
+//////////////////////////////////////////////////////////////////////
+// 0x5000 Entry 20 (size 16 bundles) Page Not Present
+ENTRY(kvm_page_not_present)
+ KVM_REFLECT(20)
+END(kvm_page_not_present)
+
+ .org kvm_ia64_ivt+0x5100
+///////////////////////////////////////////////////////////////////////
+// 0x5100 Entry 21 (size 16 bundles) Key Permission vector
+ENTRY(kvm_key_permission)
+ KVM_REFLECT(21)
+END(kvm_key_permission)
+
+ .org kvm_ia64_ivt+0x5200
+//////////////////////////////////////////////////////////////////////
+// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26)
+ENTRY(kvm_iaccess_rights)
+ KVM_REFLECT(22)
+END(kvm_iaccess_rights)
+
+ .org kvm_ia64_ivt+0x5300
+//////////////////////////////////////////////////////////////////////
+// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53)
+ENTRY(kvm_daccess_rights)
+ KVM_REFLECT(23)
+END(kvm_daccess_rights)
+
+ .org kvm_ia64_ivt+0x5400
+/////////////////////////////////////////////////////////////////////
+// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39)
+ENTRY(kvm_general_exception)
+ KVM_REFLECT(24)
+ KVM_FAULT(24)
+END(kvm_general_exception)
+
+ .org kvm_ia64_ivt+0x5500
+//////////////////////////////////////////////////////////////////////
+// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35)
+ENTRY(kvm_disabled_fp_reg)
+ KVM_REFLECT(25)
+END(kvm_disabled_fp_reg)
+
+ .org kvm_ia64_ivt+0x5600
+////////////////////////////////////////////////////////////////////
+// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50)
+ENTRY(kvm_nat_consumption)
+ KVM_REFLECT(26)
+END(kvm_nat_consumption)
+
+ .org kvm_ia64_ivt+0x5700
+/////////////////////////////////////////////////////////////////////
+// 0x5700 Entry 27 (size 16 bundles) Speculation (40)
+ENTRY(kvm_speculation_vector)
+ KVM_REFLECT(27)
+END(kvm_speculation_vector)
+
+ .org kvm_ia64_ivt+0x5800
+/////////////////////////////////////////////////////////////////////
+// 0x5800 Entry 28 (size 16 bundles) Reserved
+ KVM_FAULT(28)
+
+ .org kvm_ia64_ivt+0x5900
+///////////////////////////////////////////////////////////////////
+// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56)
+ENTRY(kvm_debug_vector)
+ KVM_FAULT(29)
+END(kvm_debug_vector)
+
+ .org kvm_ia64_ivt+0x5a00
+///////////////////////////////////////////////////////////////
+// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57)
+ENTRY(kvm_unaligned_access)
+ KVM_REFLECT(30)
+END(kvm_unaligned_access)
+
+ .org kvm_ia64_ivt+0x5b00
+//////////////////////////////////////////////////////////////////////
+// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57)
+ENTRY(kvm_unsupported_data_reference)
+ KVM_REFLECT(31)
+END(kvm_unsupported_data_reference)
+
+ .org kvm_ia64_ivt+0x5c00
+////////////////////////////////////////////////////////////////////
+// 0x5c00 Entry 32 (size 16 bundles) Floating Point FAULT (65)
+ENTRY(kvm_floating_point_fault)
+ KVM_REFLECT(32)
+END(kvm_floating_point_fault)
+
+ .org kvm_ia64_ivt+0x5d00
+/////////////////////////////////////////////////////////////////////
+// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66)
+ENTRY(kvm_floating_point_trap)
+ KVM_REFLECT(33)
+END(kvm_floating_point_trap)
+
+ .org kvm_ia64_ivt+0x5e00
+//////////////////////////////////////////////////////////////////////
+// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66)
+ENTRY(kvm_lower_privilege_trap)
+ KVM_REFLECT(34)
+END(kvm_lower_privilege_trap)
+
+ .org kvm_ia64_ivt+0x5f00
+//////////////////////////////////////////////////////////////////////
+// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68)
+ENTRY(kvm_taken_branch_trap)
+ KVM_REFLECT(35)
+END(kvm_taken_branch_trap)
+
+ .org kvm_ia64_ivt+0x6000
+////////////////////////////////////////////////////////////////////
+// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69)
+ENTRY(kvm_single_step_trap)
+ KVM_REFLECT(36)
+END(kvm_single_step_trap)
+ .global kvm_virtualization_fault_back
+ .org kvm_ia64_ivt+0x6100
+/////////////////////////////////////////////////////////////////////
+// 0x6100 Entry 37 (size 16 bundles) Virtualization Fault
+ENTRY(kvm_virtualization_fault)
+ mov r31=pr
+ adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21
+ ;;
+ st8 [r16] = r1
+ adds r17 = VMM_VCPU_GP_OFFSET, r21
+ ;;
+ ld8 r1 = [r17]
+ cmp.eq p6,p0=EVENT_MOV_FROM_AR,r24
+ cmp.eq p7,p0=EVENT_MOV_FROM_RR,r24
+ cmp.eq p8,p0=EVENT_MOV_TO_RR,r24
+ cmp.eq p9,p0=EVENT_RSM,r24
+ cmp.eq p10,p0=EVENT_SSM,r24
+ cmp.eq p11,p0=EVENT_MOV_TO_PSR,r24
+ cmp.eq p12,p0=EVENT_THASH,r24
+ (p6) br.dptk.many kvm_asm_mov_from_ar
+ (p7) br.dptk.many kvm_asm_mov_from_rr
+ (p8) br.dptk.many kvm_asm_mov_to_rr
+ (p9) br.dptk.many kvm_asm_rsm
+ (p10) br.dptk.many kvm_asm_ssm
+ (p11) br.dptk.many kvm_asm_mov_to_psr
+ (p12) br.dptk.many kvm_asm_thash
+ ;;
+kvm_virtualization_fault_back:
+ adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21
+ ;;
+ ld8 r1 = [r16]
+ ;;
+ mov r19=37
+ adds r16 = VMM_VCPU_CAUSE_OFFSET,r21
+ adds r17 = VMM_VCPU_OPCODE_OFFSET,r21
+ ;;
+ st8 [r16] = r24
+ st8 [r17] = r25
+ ;;
+ cmp.ne p6,p0=EVENT_RFI, r24
+ (p6) br.sptk kvm_dispatch_virtualization_fault
+ ;;
+ adds r18=VMM_VPD_BASE_OFFSET,r21
+ ;;
+ ld8 r18=[r18]
+ ;;
+ adds r18=VMM_VPD_VIFS_OFFSET,r18
+ ;;
+ ld8 r18=[r18]
+ ;;
+ tbit.z p6,p0=r18,63
+ (p6) br.sptk kvm_dispatch_virtualization_fault
+ ;;
+ //if vifs.v=1 desert current register frame
+ alloc r18=ar.pfs,0,0,0,0
+ br.sptk kvm_dispatch_virtualization_fault
+END(kvm_virtualization_fault)
+
+ .org kvm_ia64_ivt+0x6200
+//////////////////////////////////////////////////////////////
+// 0x6200 Entry 38 (size 16 bundles) Reserved
+ KVM_FAULT(38)
+
+ .org kvm_ia64_ivt+0x6300
+/////////////////////////////////////////////////////////////////
+// 0x6300 Entry 39 (size 16 bundles) Reserved
+ KVM_FAULT(39)
+
+ .org kvm_ia64_ivt+0x6400
+/////////////////////////////////////////////////////////////////
+// 0x6400 Entry 40 (size 16 bundles) Reserved
+ KVM_FAULT(40)
+
+ .org kvm_ia64_ivt+0x6500
+//////////////////////////////////////////////////////////////////
+// 0x6500 Entry 41 (size 16 bundles) Reserved
+ KVM_FAULT(41)
+
+ .org kvm_ia64_ivt+0x6600
+//////////////////////////////////////////////////////////////////
+// 0x6600 Entry 42 (size 16 bundles) Reserved
+ KVM_FAULT(42)
+
+ .org kvm_ia64_ivt+0x6700
+//////////////////////////////////////////////////////////////////
+// 0x6700 Entry 43 (size 16 bundles) Reserved
+ KVM_FAULT(43)
+
+ .org kvm_ia64_ivt+0x6800
+//////////////////////////////////////////////////////////////////
+// 0x6800 Entry 44 (size 16 bundles) Reserved
+ KVM_FAULT(44)
+
+ .org kvm_ia64_ivt+0x6900
+///////////////////////////////////////////////////////////////////
+// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception
+//(17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77)
+ENTRY(kvm_ia32_exception)
+ KVM_FAULT(45)
+END(kvm_ia32_exception)
+
+ .org kvm_ia64_ivt+0x6a00
+////////////////////////////////////////////////////////////////////
+// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71)
+ENTRY(kvm_ia32_intercept)
+ KVM_FAULT(47)
+END(kvm_ia32_intercept)
+
+ .org kvm_ia64_ivt+0x6c00
+/////////////////////////////////////////////////////////////////////
+// 0x6c00 Entry 48 (size 16 bundles) Reserved
+ KVM_FAULT(48)
+
+ .org kvm_ia64_ivt+0x6d00
+//////////////////////////////////////////////////////////////////////
+// 0x6d00 Entry 49 (size 16 bundles) Reserved
+ KVM_FAULT(49)
+
+ .org kvm_ia64_ivt+0x6e00
+//////////////////////////////////////////////////////////////////////
+// 0x6e00 Entry 50 (size 16 bundles) Reserved
+ KVM_FAULT(50)
+
+ .org kvm_ia64_ivt+0x6f00
+/////////////////////////////////////////////////////////////////////
+// 0x6f00 Entry 51 (size 16 bundles) Reserved
+ KVM_FAULT(52)
+
+ .org kvm_ia64_ivt+0x7100
+////////////////////////////////////////////////////////////////////
+// 0x7100 Entry 53 (size 16 bundles) Reserved
+ KVM_FAULT(53)
+
+ .org kvm_ia64_ivt+0x7200
+/////////////////////////////////////////////////////////////////////
+// 0x7200 Entry 54 (size 16 bundles) Reserved
+ KVM_FAULT(54)
+
+ .org kvm_ia64_ivt+0x7300
+////////////////////////////////////////////////////////////////////
+// 0x7300 Entry 55 (size 16 bundles) Reserved
+ KVM_FAULT(55)
+
+ .org kvm_ia64_ivt+0x7400
+////////////////////////////////////////////////////////////////////
+// 0x7400 Entry 56 (size 16 bundles) Reserved
+ KVM_FAULT(56)
+
+ .org kvm_ia64_ivt+0x7500
+/////////////////////////////////////////////////////////////////////
+// 0x7500 Entry 57 (size 16 bundles) Reserved
+ KVM_FAULT(57)
+
+ .org kvm_ia64_ivt+0x7600
+/////////////////////////////////////////////////////////////////////
+// 0x7600 Entry 58 (size 16 bundles) Reserved
+ KVM_FAULT(58)
+
+ .org kvm_ia64_ivt+0x7700
+////////////////////////////////////////////////////////////////////
+// 0x7700 Entry 59 (size 16 bundles) Reserved
+ KVM_FAULT(59)
+
+ .org kvm_ia64_ivt+0x7800
+////////////////////////////////////////////////////////////////////
+// 0x7800 Entry 60 (size 16 bundles) Reserved
+ KVM_FAULT(60)
+
+ .org kvm_ia64_ivt+0x7900
+/////////////////////////////////////////////////////////////////////
+// 0x7900 Entry 61 (size 16 bundles) Reserved
+ KVM_FAULT(61)
+
+ .org kvm_ia64_ivt+0x7a00
+/////////////////////////////////////////////////////////////////////
+// 0x7a00 Entry 62 (size 16 bundles) Reserved
+ KVM_FAULT(62)
+
+ .org kvm_ia64_ivt+0x7b00
+/////////////////////////////////////////////////////////////////////
+// 0x7b00 Entry 63 (size 16 bundles) Reserved
+ KVM_FAULT(63)
+
+ .org kvm_ia64_ivt+0x7c00
+////////////////////////////////////////////////////////////////////
+// 0x7c00 Entry 64 (size 16 bundles) Reserved
+ KVM_FAULT(64)
+
+ .org kvm_ia64_ivt+0x7d00
+/////////////////////////////////////////////////////////////////////
+// 0x7d00 Entry 65 (size 16 bundles) Reserved
+ KVM_FAULT(65)
+
+ .org kvm_ia64_ivt+0x7e00
+/////////////////////////////////////////////////////////////////////
+// 0x7e00 Entry 66 (size 16 bundles) Reserved
+ KVM_FAULT(66)
+
+ .org kvm_ia64_ivt+0x7f00
+////////////////////////////////////////////////////////////////////
+// 0x7f00 Entry 67 (size 16 bundles) Reserved
+ KVM_FAULT(67)
+
+ .org kvm_ia64_ivt+0x8000
+// There is no particular reason for this code to be here, other than that
+// there happens to be space here that would go unused otherwise. If this
+// fault ever gets "unreserved", simply moved the following code to a more
+// suitable spot...
+
+
+ENTRY(kvm_dtlb_miss_dispatch)
+ mov r19 = 2
+ KVM_SAVE_MIN_WITH_COVER_R19
+ alloc r14=ar.pfs,0,0,3,0
+ mov out0=cr.ifa
+ mov out1=r15
+ adds r3=8,r2 // set up second base pointer
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i // guarantee that interruption collection is on
+ ;;
+ //(p15) ssm psr.i // restore psr.i
+ addl r14=@gprel(ia64_leave_hypervisor_prepare),gp
+ ;;
+ KVM_SAVE_REST
+ KVM_SAVE_EXTRA
+ mov rp=r14
+ ;;
+ adds out2=16,r12
+ br.call.sptk.many b6=kvm_page_fault
+END(kvm_dtlb_miss_dispatch)
+
+ENTRY(kvm_itlb_miss_dispatch)
+
+ KVM_SAVE_MIN_WITH_COVER_R19
+ alloc r14=ar.pfs,0,0,3,0
+ mov out0=cr.ifa
+ mov out1=r15
+ adds r3=8,r2 // set up second base pointer
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i // guarantee that interruption collection is on
+ ;;
+ //(p15) ssm psr.i // restore psr.i
+ addl r14=@gprel(ia64_leave_hypervisor),gp
+ ;;
+ KVM_SAVE_REST
+ mov rp=r14
+ ;;
+ adds out2=16,r12
+ br.call.sptk.many b6=kvm_page_fault
+END(kvm_itlb_miss_dispatch)
+
+ENTRY(kvm_dispatch_reflection)
+ /*
+ * Input:
+ * psr.ic: off
+ * r19: intr type (offset into ivt, see ia64_int.h)
+ * r31: contains saved predicates (pr)
+ */
+ KVM_SAVE_MIN_WITH_COVER_R19
+ alloc r14=ar.pfs,0,0,5,0
+ mov out0=cr.ifa
+ mov out1=cr.isr
+ mov out2=cr.iim
+ mov out3=r15
+ adds r3=8,r2 // set up second base pointer
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i // guarantee that interruption collection is on
+ ;;
+ //(p15) ssm psr.i // restore psr.i
+ addl r14=@gprel(ia64_leave_hypervisor),gp
+ ;;
+ KVM_SAVE_REST
+ mov rp=r14
+ ;;
+ adds out4=16,r12
+ br.call.sptk.many b6=reflect_interruption
+END(kvm_dispatch_reflection)
+
+ENTRY(kvm_dispatch_virtualization_fault)
+ adds r16 = VMM_VCPU_CAUSE_OFFSET,r21
+ adds r17 = VMM_VCPU_OPCODE_OFFSET,r21
+ ;;
+ st8 [r16] = r24
+ st8 [r17] = r25
+ ;;
+ KVM_SAVE_MIN_WITH_COVER_R19
+ ;;
+ alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!)
+ mov out0=r13 //vcpu
+ adds r3=8,r2 // set up second base pointer
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i // guarantee that interruption collection is on
+ ;;
+ //(p15) ssm psr.i // restore psr.i
+ addl r14=@gprel(ia64_leave_hypervisor_prepare),gp
+ ;;
+ KVM_SAVE_REST
+ KVM_SAVE_EXTRA
+ mov rp=r14
+ ;;
+ adds out1=16,sp //regs
+ br.call.sptk.many b6=kvm_emulate
+END(kvm_dispatch_virtualization_fault)
+
+
+ENTRY(kvm_dispatch_interrupt)
+ KVM_SAVE_MIN_WITH_COVER_R19 // uses r31; defines r2 and r3
+ ;;
+ alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group
+ //mov out0=cr.ivr // pass cr.ivr as first arg
+ adds r3=8,r2 // set up second base pointer for SAVE_REST
+ ;;
+ ssm psr.ic
+ ;;
+ srlz.i
+ ;;
+ //(p15) ssm psr.i
+ addl r14=@gprel(ia64_leave_hypervisor),gp
+ ;;
+ KVM_SAVE_REST
+ mov rp=r14
+ ;;
+ mov out0=r13 // pass pointer to pt_regs as second arg
+ br.call.sptk.many b6=kvm_ia64_handle_irq
+END(kvm_dispatch_interrupt)
+
+
+
+
+GLOBAL_ENTRY(ia64_leave_nested)
+ rsm psr.i
+ ;;
+ adds r21=PT(PR)+16,r12
+ ;;
+ lfetch [r21],PT(CR_IPSR)-PT(PR)
+ adds r2=PT(B6)+16,r12
+ adds r3=PT(R16)+16,r12
+ ;;
+ lfetch [r21]
+ ld8 r28=[r2],8 // load b6
+ adds r29=PT(R24)+16,r12
+
+ ld8.fill r16=[r3]
+ adds r3=PT(AR_CSD)-PT(R16),r3
+ adds r30=PT(AR_CCV)+16,r12
+ ;;
+ ld8.fill r24=[r29]
+ ld8 r15=[r30] // load ar.ccv
+ ;;
+ ld8 r29=[r2],16 // load b7
+ ld8 r30=[r3],16 // load ar.csd
+ ;;
+ ld8 r31=[r2],16 // load ar.ssd
+ ld8.fill r8=[r3],16
+ ;;
+ ld8.fill r9=[r2],16
+ ld8.fill r10=[r3],PT(R17)-PT(R10)
+ ;;
+ ld8.fill r11=[r2],PT(R18)-PT(R11)
+ ld8.fill r17=[r3],16
+ ;;
+ ld8.fill r18=[r2],16
+ ld8.fill r19=[r3],16
+ ;;
+ ld8.fill r20=[r2],16
+ ld8.fill r21=[r3],16
+ mov ar.csd=r30
+ mov ar.ssd=r31
+ ;;
+ rsm psr.i | psr.ic
+ // initiate turning off of interrupt and interruption collection
+ invala // invalidate ALAT
+ ;;
+ srlz.i
+ ;;
+ ld8.fill r22=[r2],24
+ ld8.fill r23=[r3],24
+ mov b6=r28
+ ;;
+ ld8.fill r25=[r2],16
+ ld8.fill r26=[r3],16
+ mov b7=r29
+ ;;
+ ld8.fill r27=[r2],16
+ ld8.fill r28=[r3],16
+ ;;
+ ld8.fill r29=[r2],16
+ ld8.fill r30=[r3],24
+ ;;
+ ld8.fill r31=[r2],PT(F9)-PT(R31)
+ adds r3=PT(F10)-PT(F6),r3
+ ;;
+ ldf.fill f9=[r2],PT(F6)-PT(F9)
+ ldf.fill f10=[r3],PT(F8)-PT(F10)
+ ;;
+ ldf.fill f6=[r2],PT(F7)-PT(F6)
+ ;;
+ ldf.fill f7=[r2],PT(F11)-PT(F7)
+ ldf.fill f8=[r3],32
+ ;;
+ srlz.i // ensure interruption collection is off
+ mov ar.ccv=r15
+ ;;
+ bsw.0 // switch back to bank 0 (no stop bit required beforehand...)
+ ;;
+ ldf.fill f11=[r2]
+// mov r18=r13
+// mov r21=r13
+ adds r16=PT(CR_IPSR)+16,r12
+ adds r17=PT(CR_IIP)+16,r12
+ ;;
+ ld8 r29=[r16],16 // load cr.ipsr
+ ld8 r28=[r17],16 // load cr.iip
+ ;;
+ ld8 r30=[r16],16 // load cr.ifs
+ ld8 r25=[r17],16 // load ar.unat
+ ;;
+ ld8 r26=[r16],16 // load ar.pfs
+ ld8 r27=[r17],16 // load ar.rsc
+ cmp.eq p9,p0=r0,r0
+ // set p9 to indicate that we should restore cr.ifs
+ ;;
+ ld8 r24=[r16],16 // load ar.rnat (may be garbage)
+ ld8 r23=[r17],16// load ar.bspstore (may be garbage)
+ ;;
+ ld8 r31=[r16],16 // load predicates
+ ld8 r22=[r17],16 // load b0
+ ;;
+ ld8 r19=[r16],16 // load ar.rsc value for "loadrs"
+ ld8.fill r1=[r17],16 // load r1
+ ;;
+ ld8.fill r12=[r16],16
+ ld8.fill r13=[r17],16
+ ;;
+ ld8 r20=[r16],16 // ar.fpsr
+ ld8.fill r15=[r17],16
+ ;;
+ ld8.fill r14=[r16],16
+ ld8.fill r2=[r17]
+ ;;
+ ld8.fill r3=[r16]
+ ;;
+ mov r16=ar.bsp // get existing backing store pointer
+ ;;
+ mov b0=r22
+ mov ar.pfs=r26
+ mov cr.ifs=r30
+ mov cr.ipsr=r29
+ mov ar.fpsr=r20
+ mov cr.iip=r28
+ ;;
+ mov ar.rsc=r27
+ mov ar.unat=r25
+ mov pr=r31,-1
+ rfi
+END(ia64_leave_nested)
+
+
+
+GLOBAL_ENTRY(ia64_leave_hypervisor_prepare)
+ /*
+ * work.need_resched etc. mustn't get changed
+ *by this CPU before it returns to
+ ;;
+ * user- or fsys-mode, hence we disable interrupts early on:
+ */
+ adds r2 = PT(R4)+16,r12
+ adds r3 = PT(R5)+16,r12
+ adds r8 = PT(EML_UNAT)+16,r12
+ ;;
+ ld8 r8 = [r8]
+ ;;
+ mov ar.unat=r8
+ ;;
+ ld8.fill r4=[r2],16 //load r4
+ ld8.fill r5=[r3],16 //load r5
+ ;;
+ ld8.fill r6=[r2] //load r6
+ ld8.fill r7=[r3] //load r7
+ ;;
+END(ia64_leave_hypervisor_prepare)
+//fall through
+GLOBAL_ENTRY(ia64_leave_hypervisor)
+ rsm psr.i
+ ;;
+ br.call.sptk.many b0=leave_hypervisor_tail
+ ;;
+ adds r20=PT(PR)+16,r12
+ adds r8=PT(EML_UNAT)+16,r12
+ ;;
+ ld8 r8=[r8]
+ ;;
+ mov ar.unat=r8
+ ;;
+ lfetch [r20],PT(CR_IPSR)-PT(PR)
+ adds r2 = PT(B6)+16,r12
+ adds r3 = PT(B7)+16,r12
+ ;;
+ lfetch [r20]
+ ;;
+ ld8 r24=[r2],16 /* B6 */
+ ld8 r25=[r3],16 /* B7 */
+ ;;
+ ld8 r26=[r2],16 /* ar_csd */
+ ld8 r27=[r3],16 /* ar_ssd */
+ mov b6 = r24
+ ;;
+ ld8.fill r8=[r2],16
+ ld8.fill r9=[r3],16
+ mov b7 = r25
+ ;;
+ mov ar.csd = r26
+ mov ar.ssd = r27
+ ;;
+ ld8.fill r10=[r2],PT(R15)-PT(R10)
+ ld8.fill r11=[r3],PT(R14)-PT(R11)
+ ;;
+ ld8.fill r15=[r2],PT(R16)-PT(R15)
+ ld8.fill r14=[r3],PT(R17)-PT(R14)
+ ;;
+ ld8.fill r16=[r2],16
+ ld8.fill r17=[r3],16
+ ;;
+ ld8.fill r18=[r2],16
+ ld8.fill r19=[r3],16
+ ;;
+ ld8.fill r20=[r2],16
+ ld8.fill r21=[r3],16
+ ;;
+ ld8.fill r22=[r2],16
+ ld8.fill r23=[r3],16
+ ;;
+ ld8.fill r24=[r2],16
+ ld8.fill r25=[r3],16
+ ;;
+ ld8.fill r26=[r2],16
+ ld8.fill r27=[r3],16
+ ;;
+ ld8.fill r28=[r2],16
+ ld8.fill r29=[r3],16
+ ;;
+ ld8.fill r30=[r2],PT(F6)-PT(R30)
+ ld8.fill r31=[r3],PT(F7)-PT(R31)
+ ;;
+ rsm psr.i | psr.ic
+ // initiate turning off of interrupt and interruption collection
+ invala // invalidate ALAT
+ ;;
+ srlz.i // ensure interruption collection is off
+ ;;
+ bsw.0
+ ;;
+ adds r16 = PT(CR_IPSR)+16,r12
+ adds r17 = PT(CR_IIP)+16,r12
+ mov r21=r13 // get current
+ ;;
+ ld8 r31=[r16],16 // load cr.ipsr
+ ld8 r30=[r17],16 // load cr.iip
+ ;;
+ ld8 r29=[r16],16 // load cr.ifs
+ ld8 r28=[r17],16 // load ar.unat
+ ;;
+ ld8 r27=[r16],16 // load ar.pfs
+ ld8 r26=[r17],16 // load ar.rsc
+ ;;
+ ld8 r25=[r16],16 // load ar.rnat
+ ld8 r24=[r17],16 // load ar.bspstore
+ ;;
+ ld8 r23=[r16],16 // load predicates
+ ld8 r22=[r17],16 // load b0
+ ;;
+ ld8 r20=[r16],16 // load ar.rsc value for "loadrs"
+ ld8.fill r1=[r17],16 //load r1
+ ;;
+ ld8.fill r12=[r16],16 //load r12
+ ld8.fill r13=[r17],PT(R2)-PT(R13) //load r13
+ ;;
+ ld8 r19=[r16],PT(R3)-PT(AR_FPSR) //load ar_fpsr
+ ld8.fill r2=[r17],PT(AR_CCV)-PT(R2) //load r2
+ ;;
+ ld8.fill r3=[r16] //load r3
+ ld8 r18=[r17] //load ar_ccv
+ ;;
+ mov ar.fpsr=r19
+ mov ar.ccv=r18
+ shr.u r18=r20,16
+ ;;
+kvm_rbs_switch:
+ mov r19=96
+
+kvm_dont_preserve_current_frame:
+/*
+ * To prevent leaking bits between the hypervisor and guest domain,
+ * we must clear the stacked registers in the "invalid" partition here.
+ * 5 registers/cycle on McKinley).
+ */
+# define pRecurse p6
+# define pReturn p7
+# define Nregs 14
+
+ alloc loc0=ar.pfs,2,Nregs-2,2,0
+ shr.u loc1=r18,9 // RNaTslots <= floor(dirtySize / (64*8))
+ sub r19=r19,r18 // r19 = (physStackedSize + 8) - dirtySize
+ ;;
+ mov ar.rsc=r20 // load ar.rsc to be used for "loadrs"
+ shladd in0=loc1,3,r19
+ mov in1=0
+ ;;
+ TEXT_ALIGN(32)
+kvm_rse_clear_invalid:
+ alloc loc0=ar.pfs,2,Nregs-2,2,0
+ cmp.lt pRecurse,p0=Nregs*8,in0
+ // if more than Nregs regs left to clear, (re)curse
+ add out0=-Nregs*8,in0
+ add out1=1,in1 // increment recursion count
+ mov loc1=0
+ mov loc2=0
+ ;;
+ mov loc3=0
+ mov loc4=0
+ mov loc5=0
+ mov loc6=0
+ mov loc7=0
+(pRecurse) br.call.dptk.few b0=kvm_rse_clear_invalid
+ ;;
+ mov loc8=0
+ mov loc9=0
+ cmp.ne pReturn,p0=r0,in1
+ // if recursion count != 0, we need to do a br.ret
+ mov loc10=0
+ mov loc11=0
+(pReturn) br.ret.dptk.many b0
+
+# undef pRecurse
+# undef pReturn
+
+// loadrs has already been shifted
+ alloc r16=ar.pfs,0,0,0,0 // drop current register frame
+ ;;
+ loadrs
+ ;;
+ mov ar.bspstore=r24
+ ;;
+ mov ar.unat=r28
+ mov ar.rnat=r25
+ mov ar.rsc=r26
+ ;;
+ mov cr.ipsr=r31
+ mov cr.iip=r30
+ mov cr.ifs=r29
+ mov ar.pfs=r27
+ adds r18=VMM_VPD_BASE_OFFSET,r21
+ ;;
+ ld8 r18=[r18] //vpd
+ adds r17=VMM_VCPU_ISR_OFFSET,r21
+ ;;
+ ld8 r17=[r17]
+ adds r19=VMM_VPD_VPSR_OFFSET,r18
+ ;;
+ ld8 r19=[r19] //vpsr
+ adds r20=VMM_VCPU_VSA_BASE_OFFSET,r21
+ ;;
+ ld8 r20=[r20]
+ ;;
+//vsa_sync_write_start
+ mov r25=r18
+ adds r16= VMM_VCPU_GP_OFFSET,r21
+ ;;
+ ld8 r16= [r16] // Put gp in r24
+ movl r24=@gprel(ia64_vmm_entry) // calculate return address
+ ;;
+ add r24=r24,r16
+ ;;
+ add r16=PAL_VPS_SYNC_WRITE,r20
+ ;;
+ mov b0=r16
+ br.cond.sptk b0 // call the service
+ ;;
+END(ia64_leave_hypervisor)
+// fall through
+GLOBAL_ENTRY(ia64_vmm_entry)
+/*
+ * must be at bank 0
+ * parameter:
+ * r17:cr.isr
+ * r18:vpd
+ * r19:vpsr
+ * r20:__vsa_base
+ * r22:b0
+ * r23:predicate
+ */
+ mov r24=r22
+ mov r25=r18
+ tbit.nz p1,p2 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic
+ ;;
+ (p1) add r29=PAL_VPS_RESUME_NORMAL,r20
+ (p1) br.sptk.many ia64_vmm_entry_out
+ ;;
+ tbit.nz p1,p2 = r17,IA64_ISR_IR_BIT //p1=cr.isr.ir
+ ;;
+ (p1) add r29=PAL_VPS_RESUME_NORMAL,r20
+ (p2) add r29=PAL_VPS_RESUME_HANDLER,r20
+ (p2) ld8 r26=[r25]
+ ;;
+ia64_vmm_entry_out:
+ mov pr=r23,-2
+ mov b0=r29
+ ;;
+ br.cond.sptk b0 // call pal service
+END(ia64_vmm_entry)
+
+
+
+/*
+ * extern u64 ia64_call_vsa(u64 proc, u64 arg1, u64 arg2,
+ * u64 arg3, u64 arg4, u64 arg5,
+ * u64 arg6, u64 arg7);
+ *
+ * XXX: The currently defined services use only 4 args at the max. The
+ * rest are not consumed.
+ */
+GLOBAL_ENTRY(ia64_call_vsa)
+ .regstk 4,4,0,0
+
+rpsave = loc0
+pfssave = loc1
+psrsave = loc2
+entry = loc3
+hostret = r24
+
+ alloc pfssave=ar.pfs,4,4,0,0
+ mov rpsave=rp
+ adds entry=VMM_VCPU_VSA_BASE_OFFSET, r13
+ ;;
+ ld8 entry=[entry]
+1: mov hostret=ip
+ mov r25=in1 // copy arguments
+ mov r26=in2
+ mov r27=in3
+ mov psrsave=psr
+ ;;
+ tbit.nz p6,p0=psrsave,14 // IA64_PSR_I
+ tbit.nz p7,p0=psrsave,13 // IA64_PSR_IC
+ ;;
+ add hostret=2f-1b,hostret // calculate return address
+ add entry=entry,in0
+ ;;
+ rsm psr.i | psr.ic
+ ;;
+ srlz.i
+ mov b6=entry
+ br.cond.sptk b6 // call the service
+2:
+ // Architectural sequence for enabling interrupts if necessary
+(p7) ssm psr.ic
+ ;;
+(p7) srlz.i
+ ;;
+//(p6) ssm psr.i
+ ;;
+ mov rp=rpsave
+ mov ar.pfs=pfssave
+ mov r8=r31
+ ;;
+ srlz.d
+ br.ret.sptk rp
+
+END(ia64_call_vsa)
+
+#define INIT_BSPSTORE ((4<<30)-(12<<20)-0x100)
+
+GLOBAL_ENTRY(vmm_reset_entry)
+ //set up ipsr, iip, vpd.vpsr, dcr
+ // For IPSR: it/dt/rt=1, i/ic=1, si=1, vm/bn=1
+ // For DCR: all bits 0
+ adds r14=-VMM_PT_REGS_SIZE, r12
+ ;;
+ movl r6=0x501008826000 // IPSR dt/rt/it:1;i/ic:1, si:1, vm/bn:1
+ movl r10=0x8000000000000000
+ adds r16=PT(CR_IIP), r14
+ adds r20=PT(R1), r14
+ ;;
+ rsm psr.ic | psr.i
+ ;;
+ srlz.i
+ ;;
+ bsw.0
+ ;;
+ mov r21 =r13
+ ;;
+ bsw.1
+ ;;
+ mov ar.rsc = 0
+ ;;
+ flushrs
+ ;;
+ mov ar.bspstore = 0
+ // clear BSPSTORE
+ ;;
+ mov cr.ipsr=r6
+ mov cr.ifs=r10
+ ld8 r4 = [r16] // Set init iip for first run.
+ ld8 r1 = [r20]
+ ;;
+ mov cr.iip=r4
+ ;;
+ adds r16=VMM_VPD_BASE_OFFSET,r13
+ adds r20=VMM_VCPU_VSA_BASE_OFFSET,r13
+ ;;
+ ld8 r18=[r16]
+ ld8 r20=[r20]
+ ;;
+ adds r19=VMM_VPD_VPSR_OFFSET,r18
+ ;;
+ ld8 r19=[r19]
+ mov r17=r0
+ mov r22=r0
+ mov r23=r0
+ br.cond.sptk ia64_vmm_entry
+ br.ret.sptk b0
+END(vmm_reset_entry)
diff --git a/arch/ia64/kvm/vti.h b/arch/ia64/kvm/vti.h
new file mode 100644
index 000000000000..f6c5617e16af
--- /dev/null
+++ b/arch/ia64/kvm/vti.h
@@ -0,0 +1,290 @@
+/*
+ * vti.h: prototype for generial vt related interface
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
+ * Fred Yang (fred.yang@intel.com)
+ * Kun Tian (Kevin Tian) (kevin.tian@intel.com)
+ *
+ * Copyright (c) 2007, Intel Corporation.
+ * Zhang xiantao <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 _KVM_VT_I_H
+#define _KVM_VT_I_H
+
+#ifndef __ASSEMBLY__
+#include <asm/page.h>
+
+#include <linux/kvm_host.h>
+
+/* define itr.i and itr.d in ia64_itr function */
+#define ITR 0x01
+#define DTR 0x02
+#define IaDTR 0x03
+
+#define IA64_TR_VMM 6 /*itr6, dtr6 : maps vmm code, vmbuffer*/
+#define IA64_TR_VM_DATA 7 /*dtr7 : maps current vm data*/
+
+#define RR6 (6UL<<61)
+#define RR7 (7UL<<61)
+
+
+/* config_options in pal_vp_init_env */
+#define VP_INITIALIZE 1UL
+#define VP_FR_PMC 1UL<<1
+#define VP_OPCODE 1UL<<8
+#define VP_CAUSE 1UL<<9
+#define VP_FW_ACC 1UL<<63
+
+/* init vp env with initializing vm_buffer */
+#define VP_INIT_ENV_INITALIZE (VP_INITIALIZE | VP_FR_PMC |\
+ VP_OPCODE | VP_CAUSE | VP_FW_ACC)
+/* init vp env without initializing vm_buffer */
+#define VP_INIT_ENV VP_FR_PMC | VP_OPCODE | VP_CAUSE | VP_FW_ACC
+
+#define PAL_VP_CREATE 265
+/* Stacked Virt. Initializes a new VPD for the operation of
+ * a new virtual processor in the virtual environment.
+ */
+#define PAL_VP_ENV_INFO 266
+/*Stacked Virt. Returns the parameters needed to enter a virtual environment.*/
+#define PAL_VP_EXIT_ENV 267
+/*Stacked Virt. Allows a logical processor to exit a virtual environment.*/
+#define PAL_VP_INIT_ENV 268
+/*Stacked Virt. Allows a logical processor to enter a virtual environment.*/
+#define PAL_VP_REGISTER 269
+/*Stacked Virt. Register a different host IVT for the virtual processor.*/
+#define PAL_VP_RESUME 270
+/* Renamed from PAL_VP_RESUME */
+#define PAL_VP_RESTORE 270
+/*Stacked Virt. Resumes virtual processor operation on the logical processor.*/
+#define PAL_VP_SUSPEND 271
+/* Renamed from PAL_VP_SUSPEND */
+#define PAL_VP_SAVE 271
+/* Stacked Virt. Suspends operation for the specified virtual processor on
+ * the logical processor.
+ */
+#define PAL_VP_TERMINATE 272
+/* Stacked Virt. Terminates operation for the specified virtual processor.*/
+
+union vac {
+ unsigned long value;
+ struct {
+ int a_int:1;
+ int a_from_int_cr:1;
+ int a_to_int_cr:1;
+ int a_from_psr:1;
+ int a_from_cpuid:1;
+ int a_cover:1;
+ int a_bsw:1;
+ long reserved:57;
+ };
+};
+
+union vdc {
+ unsigned long value;
+ struct {
+ int d_vmsw:1;
+ int d_extint:1;
+ int d_ibr_dbr:1;
+ int d_pmc:1;
+ int d_to_pmd:1;
+ int d_itm:1;
+ long reserved:58;
+ };
+};
+
+struct vpd {
+ union vac vac;
+ union vdc vdc;
+ unsigned long virt_env_vaddr;
+ unsigned long reserved1[29];
+ unsigned long vhpi;
+ unsigned long reserved2[95];
+ unsigned long vgr[16];
+ unsigned long vbgr[16];
+ unsigned long vnat;
+ unsigned long vbnat;
+ unsigned long vcpuid[5];
+ unsigned long reserved3[11];
+ unsigned long vpsr;
+ unsigned long vpr;
+ unsigned long reserved4[76];
+ union {
+ unsigned long vcr[128];
+ struct {
+ unsigned long dcr;
+ unsigned long itm;
+ unsigned long iva;
+ unsigned long rsv1[5];
+ unsigned long pta;
+ unsigned long rsv2[7];
+ unsigned long ipsr;
+ unsigned long isr;
+ unsigned long rsv3;
+ unsigned long iip;
+ unsigned long ifa;
+ unsigned long itir;
+ unsigned long iipa;
+ unsigned long ifs;
+ unsigned long iim;
+ unsigned long iha;
+ unsigned long rsv4[38];
+ unsigned long lid;
+ unsigned long ivr;
+ unsigned long tpr;
+ unsigned long eoi;
+ unsigned long irr[4];
+ unsigned long itv;
+ unsigned long pmv;
+ unsigned long cmcv;
+ unsigned long rsv5[5];
+ unsigned long lrr0;
+ unsigned long lrr1;
+ unsigned long rsv6[46];
+ };
+ };
+ unsigned long reserved5[128];
+ unsigned long reserved6[3456];
+ unsigned long vmm_avail[128];
+ unsigned long reserved7[4096];
+};
+
+#define PAL_PROC_VM_BIT (1UL << 40)
+#define PAL_PROC_VMSW_BIT (1UL << 54)
+
+static inline s64 ia64_pal_vp_env_info(u64 *buffer_size,
+ u64 *vp_env_info)
+{
+ struct ia64_pal_retval iprv;
+ PAL_CALL_STK(iprv, PAL_VP_ENV_INFO, 0, 0, 0);
+ *buffer_size = iprv.v0;
+ *vp_env_info = iprv.v1;
+ return iprv.status;
+}
+
+static inline s64 ia64_pal_vp_exit_env(u64 iva)
+{
+ struct ia64_pal_retval iprv;
+
+ PAL_CALL_STK(iprv, PAL_VP_EXIT_ENV, (u64)iva, 0, 0);
+ return iprv.status;
+}
+
+static inline s64 ia64_pal_vp_init_env(u64 config_options, u64 pbase_addr,
+ u64 vbase_addr, u64 *vsa_base)
+{
+ struct ia64_pal_retval iprv;
+
+ PAL_CALL_STK(iprv, PAL_VP_INIT_ENV, config_options, pbase_addr,
+ vbase_addr);
+ *vsa_base = iprv.v0;
+
+ return iprv.status;
+}
+
+static inline s64 ia64_pal_vp_restore(u64 *vpd, u64 pal_proc_vector)
+{
+ struct ia64_pal_retval iprv;
+
+ PAL_CALL_STK(iprv, PAL_VP_RESTORE, (u64)vpd, pal_proc_vector, 0);
+
+ return iprv.status;
+}
+
+static inline s64 ia64_pal_vp_save(u64 *vpd, u64 pal_proc_vector)
+{
+ struct ia64_pal_retval iprv;
+
+ PAL_CALL_STK(iprv, PAL_VP_SAVE, (u64)vpd, pal_proc_vector, 0);
+
+ return iprv.status;
+}
+
+#endif
+
+/*VPD field offset*/
+#define VPD_VAC_START_OFFSET 0
+#define VPD_VDC_START_OFFSET 8
+#define VPD_VHPI_START_OFFSET 256
+#define VPD_VGR_START_OFFSET 1024
+#define VPD_VBGR_START_OFFSET 1152
+#define VPD_VNAT_START_OFFSET 1280
+#define VPD_VBNAT_START_OFFSET 1288
+#define VPD_VCPUID_START_OFFSET 1296
+#define VPD_VPSR_START_OFFSET 1424
+#define VPD_VPR_START_OFFSET 1432
+#define VPD_VRSE_CFLE_START_OFFSET 1440
+#define VPD_VCR_START_OFFSET 2048
+#define VPD_VTPR_START_OFFSET 2576
+#define VPD_VRR_START_OFFSET 3072
+#define VPD_VMM_VAIL_START_OFFSET 31744
+
+/*Virtualization faults*/
+
+#define EVENT_MOV_TO_AR 1
+#define EVENT_MOV_TO_AR_IMM 2
+#define EVENT_MOV_FROM_AR 3
+#define EVENT_MOV_TO_CR 4
+#define EVENT_MOV_FROM_CR 5
+#define EVENT_MOV_TO_PSR 6
+#define EVENT_MOV_FROM_PSR 7
+#define EVENT_ITC_D 8
+#define EVENT_ITC_I 9
+#define EVENT_MOV_TO_RR 10
+#define EVENT_MOV_TO_DBR 11
+#define EVENT_MOV_TO_IBR 12
+#define EVENT_MOV_TO_PKR 13
+#define EVENT_MOV_TO_PMC 14
+#define EVENT_MOV_TO_PMD 15
+#define EVENT_ITR_D 16
+#define EVENT_ITR_I 17
+#define EVENT_MOV_FROM_RR 18
+#define EVENT_MOV_FROM_DBR 19
+#define EVENT_MOV_FROM_IBR 20
+#define EVENT_MOV_FROM_PKR 21
+#define EVENT_MOV_FROM_PMC 22
+#define EVENT_MOV_FROM_CPUID 23
+#define EVENT_SSM 24
+#define EVENT_RSM 25
+#define EVENT_PTC_L 26
+#define EVENT_PTC_G 27
+#define EVENT_PTC_GA 28
+#define EVENT_PTR_D 29
+#define EVENT_PTR_I 30
+#define EVENT_THASH 31
+#define EVENT_TTAG 32
+#define EVENT_TPA 33
+#define EVENT_TAK 34
+#define EVENT_PTC_E 35
+#define EVENT_COVER 36
+#define EVENT_RFI 37
+#define EVENT_BSW_0 38
+#define EVENT_BSW_1 39
+#define EVENT_VMSW 40
+
+/**PAL virtual services offsets */
+#define PAL_VPS_RESUME_NORMAL 0x0000
+#define PAL_VPS_RESUME_HANDLER 0x0400
+#define PAL_VPS_SYNC_READ 0x0800
+#define PAL_VPS_SYNC_WRITE 0x0c00
+#define PAL_VPS_SET_PENDING_INTERRUPT 0x1000
+#define PAL_VPS_THASH 0x1400
+#define PAL_VPS_TTAG 0x1800
+#define PAL_VPS_RESTORE 0x1c00
+#define PAL_VPS_SAVE 0x2000
+
+#endif/* _VT_I_H*/
diff --git a/arch/ia64/kvm/vtlb.c b/arch/ia64/kvm/vtlb.c
new file mode 100644
index 000000000000..def4576d22b1
--- /dev/null
+++ b/arch/ia64/kvm/vtlb.c
@@ -0,0 +1,636 @@
+/*
+ * vtlb.c: guest virtual tlb handling module.
+ * Copyright (c) 2004, Intel Corporation.
+ * Yaozu Dong (Eddie Dong) <Eddie.dong@intel.com>
+ * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com>
+ *
+ * Copyright (c) 2007, Intel Corporation.
+ * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com>
+ * Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "vcpu.h"
+
+#include <linux/rwsem.h>
+
+#include <asm/tlb.h>
+
+/*
+ * Check to see if the address rid:va is translated by the TLB
+ */
+
+static int __is_tr_translated(struct thash_data *trp, u64 rid, u64 va)
+{
+ return ((trp->p) && (trp->rid == rid)
+ && ((va-trp->vadr) < PSIZE(trp->ps)));
+}
+
+/*
+ * Only for GUEST TR format.
+ */
+static int __is_tr_overlap(struct thash_data *trp, u64 rid, u64 sva, u64 eva)
+{
+ u64 sa1, ea1;
+
+ if (!trp->p || trp->rid != rid)
+ return 0;
+
+ sa1 = trp->vadr;
+ ea1 = sa1 + PSIZE(trp->ps) - 1;
+ eva -= 1;
+ if ((sva > ea1) || (sa1 > eva))
+ return 0;
+ else
+ return 1;
+
+}
+
+void machine_tlb_purge(u64 va, u64 ps)
+{
+ ia64_ptcl(va, ps << 2);
+}
+
+void local_flush_tlb_all(void)
+{
+ int i, j;
+ unsigned long flags, count0, count1;
+ unsigned long stride0, stride1, addr;
+
+ addr = current_vcpu->arch.ptce_base;
+ count0 = current_vcpu->arch.ptce_count[0];
+ count1 = current_vcpu->arch.ptce_count[1];
+ stride0 = current_vcpu->arch.ptce_stride[0];
+ stride1 = current_vcpu->arch.ptce_stride[1];
+
+ local_irq_save(flags);
+ for (i = 0; i < count0; ++i) {
+ for (j = 0; j < count1; ++j) {
+ ia64_ptce(addr);
+ addr += stride1;
+ }
+ addr += stride0;
+ }
+ local_irq_restore(flags);
+ ia64_srlz_i(); /* srlz.i implies srlz.d */
+}
+
+int vhpt_enabled(struct kvm_vcpu *vcpu, u64 vadr, enum vhpt_ref ref)
+{
+ union ia64_rr vrr;
+ union ia64_pta vpta;
+ struct ia64_psr vpsr;
+
+ vpsr = *(struct ia64_psr *)&VCPU(vcpu, vpsr);
+ vrr.val = vcpu_get_rr(vcpu, vadr);
+ vpta.val = vcpu_get_pta(vcpu);
+
+ if (vrr.ve & vpta.ve) {
+ switch (ref) {
+ case DATA_REF:
+ case NA_REF:
+ return vpsr.dt;
+ case INST_REF:
+ return vpsr.dt && vpsr.it && vpsr.ic;
+ case RSE_REF:
+ return vpsr.dt && vpsr.rt;
+
+ }
+ }
+ return 0;
+}
+
+struct thash_data *vsa_thash(union ia64_pta vpta, u64 va, u64 vrr, u64 *tag)
+{
+ u64 index, pfn, rid, pfn_bits;
+
+ pfn_bits = vpta.size - 5 - 8;
+ pfn = REGION_OFFSET(va) >> _REGION_PAGE_SIZE(vrr);
+ rid = _REGION_ID(vrr);
+ index = ((rid & 0xff) << pfn_bits)|(pfn & ((1UL << pfn_bits) - 1));
+ *tag = ((rid >> 8) & 0xffff) | ((pfn >> pfn_bits) << 16);
+
+ return (struct thash_data *)((vpta.base << PTA_BASE_SHIFT) +
+ (index << 5));
+}
+
+struct thash_data *__vtr_lookup(struct kvm_vcpu *vcpu, u64 va, int type)
+{
+
+ struct thash_data *trp;
+ int i;
+ u64 rid;
+
+ rid = vcpu_get_rr(vcpu, va);
+ rid = rid & RR_RID_MASK;;
+ if (type == D_TLB) {
+ if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) {
+ for (trp = (struct thash_data *)&vcpu->arch.dtrs, i = 0;
+ i < NDTRS; i++, trp++) {
+ if (__is_tr_translated(trp, rid, va))
+ return trp;
+ }
+ }
+ } else {
+ if (vcpu_quick_region_check(vcpu->arch.itr_regions, va)) {
+ for (trp = (struct thash_data *)&vcpu->arch.itrs, i = 0;
+ i < NITRS; i++, trp++) {
+ if (__is_tr_translated(trp, rid, va))
+ return trp;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void vhpt_insert(u64 pte, u64 itir, u64 ifa, u64 gpte)
+{
+ union ia64_rr rr;
+ struct thash_data *head;
+ unsigned long ps, gpaddr;
+
+ ps = itir_ps(itir);
+
+ gpaddr = ((gpte & _PAGE_PPN_MASK) >> ps << ps) |
+ (ifa & ((1UL << ps) - 1));
+
+ rr.val = ia64_get_rr(ifa);
+ head = (struct thash_data *)ia64_thash(ifa);
+ head->etag = INVALID_TI_TAG;
+ ia64_mf();
+ head->page_flags = pte & ~PAGE_FLAGS_RV_MASK;
+ head->itir = rr.ps << 2;
+ head->etag = ia64_ttag(ifa);
+ head->gpaddr = gpaddr;
+}
+
+void mark_pages_dirty(struct kvm_vcpu *v, u64 pte, u64 ps)
+{
+ u64 i, dirty_pages = 1;
+ u64 base_gfn = (pte&_PAGE_PPN_MASK) >> PAGE_SHIFT;
+ spinlock_t *lock = __kvm_va(v->arch.dirty_log_lock_pa);
+ void *dirty_bitmap = (void *)v - (KVM_VCPU_OFS + v->vcpu_id * VCPU_SIZE)
+ + KVM_MEM_DIRTY_LOG_OFS;
+ dirty_pages <<= ps <= PAGE_SHIFT ? 0 : ps - PAGE_SHIFT;
+
+ vmm_spin_lock(lock);
+ for (i = 0; i < dirty_pages; i++) {
+ /* avoid RMW */
+ if (!test_bit(base_gfn + i, dirty_bitmap))
+ set_bit(base_gfn + i , dirty_bitmap);
+ }
+ vmm_spin_unlock(lock);
+}
+
+void thash_vhpt_insert(struct kvm_vcpu *v, u64 pte, u64 itir, u64 va, int type)
+{
+ u64 phy_pte, psr;
+ union ia64_rr mrr;
+
+ mrr.val = ia64_get_rr(va);
+ phy_pte = translate_phy_pte(&pte, itir, va);
+
+ if (itir_ps(itir) >= mrr.ps) {
+ vhpt_insert(phy_pte, itir, va, pte);
+ } else {
+ phy_pte &= ~PAGE_FLAGS_RV_MASK;
+ psr = ia64_clear_ic();
+ ia64_itc(type, va, phy_pte, itir_ps(itir));
+ ia64_set_psr(psr);
+ }
+
+ if (!(pte&VTLB_PTE_IO))
+ mark_pages_dirty(v, pte, itir_ps(itir));
+}
+
+/*
+ * vhpt lookup
+ */
+struct thash_data *vhpt_lookup(u64 va)
+{
+ struct thash_data *head;
+ u64 tag;
+
+ head = (struct thash_data *)ia64_thash(va);
+ tag = ia64_ttag(va);
+ if (head->etag == tag)
+ return head;
+ return NULL;
+}
+
+u64 guest_vhpt_lookup(u64 iha, u64 *pte)
+{
+ u64 ret;
+ struct thash_data *data;
+
+ data = __vtr_lookup(current_vcpu, iha, D_TLB);
+ if (data != NULL)
+ thash_vhpt_insert(current_vcpu, data->page_flags,
+ data->itir, iha, D_TLB);
+
+ asm volatile ("rsm psr.ic|psr.i;;"
+ "srlz.d;;"
+ "ld8.s r9=[%1];;"
+ "tnat.nz p6,p7=r9;;"
+ "(p6) mov %0=1;"
+ "(p6) mov r9=r0;"
+ "(p7) extr.u r9=r9,0,53;;"
+ "(p7) mov %0=r0;"
+ "(p7) st8 [%2]=r9;;"
+ "ssm psr.ic;;"
+ "srlz.d;;"
+ /* "ssm psr.i;;" Once interrupts in vmm open, need fix*/
+ : "=r"(ret) : "r"(iha), "r"(pte):"memory");
+
+ return ret;
+}
+
+/*
+ * purge software guest tlb
+ */
+
+static void vtlb_purge(struct kvm_vcpu *v, u64 va, u64 ps)
+{
+ struct thash_data *cur;
+ u64 start, curadr, size, psbits, tag, rr_ps, num;
+ union ia64_rr vrr;
+ struct thash_cb *hcb = &v->arch.vtlb;
+
+ vrr.val = vcpu_get_rr(v, va);
+ psbits = VMX(v, psbits[(va >> 61)]);
+ start = va & ~((1UL << ps) - 1);
+ while (psbits) {
+ curadr = start;
+ rr_ps = __ffs(psbits);
+ psbits &= ~(1UL << rr_ps);
+ num = 1UL << ((ps < rr_ps) ? 0 : (ps - rr_ps));
+ size = PSIZE(rr_ps);
+ vrr.ps = rr_ps;
+ while (num) {
+ cur = vsa_thash(hcb->pta, curadr, vrr.val, &tag);
+ if (cur->etag == tag && cur->ps == rr_ps)
+ cur->etag = INVALID_TI_TAG;
+ curadr += size;
+ num--;
+ }
+ }
+}
+
+
+/*
+ * purge VHPT and machine TLB
+ */
+static void vhpt_purge(struct kvm_vcpu *v, u64 va, u64 ps)
+{
+ struct thash_data *cur;
+ u64 start, size, tag, num;
+ union ia64_rr rr;
+
+ start = va & ~((1UL << ps) - 1);
+ rr.val = ia64_get_rr(va);
+ size = PSIZE(rr.ps);
+ num = 1UL << ((ps < rr.ps) ? 0 : (ps - rr.ps));
+ while (num) {
+ cur = (struct thash_data *)ia64_thash(start);
+ tag = ia64_ttag(start);
+ if (cur->etag == tag)
+ cur->etag = INVALID_TI_TAG;
+ start += size;
+ num--;
+ }
+ machine_tlb_purge(va, ps);
+}
+
+/*
+ * Insert an entry into hash TLB or VHPT.
+ * NOTES:
+ * 1: When inserting VHPT to thash, "va" is a must covered
+ * address by the inserted machine VHPT entry.
+ * 2: The format of entry is always in TLB.
+ * 3: The caller need to make sure the new entry will not overlap
+ * with any existed entry.
+ */
+void vtlb_insert(struct kvm_vcpu *v, u64 pte, u64 itir, u64 va)
+{
+ struct thash_data *head;
+ union ia64_rr vrr;
+ u64 tag;
+ struct thash_cb *hcb = &v->arch.vtlb;
+
+ vrr.val = vcpu_get_rr(v, va);
+ vrr.ps = itir_ps(itir);
+ VMX(v, psbits[va >> 61]) |= (1UL << vrr.ps);
+ head = vsa_thash(hcb->pta, va, vrr.val, &tag);
+ head->page_flags = pte;
+ head->itir = itir;
+ head->etag = tag;
+}
+
+int vtr_find_overlap(struct kvm_vcpu *vcpu, u64 va, u64 ps, int type)
+{
+ struct thash_data *trp;
+ int i;
+ u64 end, rid;
+
+ rid = vcpu_get_rr(vcpu, va);
+ rid = rid & RR_RID_MASK;
+ end = va + PSIZE(ps);
+ if (type == D_TLB) {
+ if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) {
+ for (trp = (struct thash_data *)&vcpu->arch.dtrs, i = 0;
+ i < NDTRS; i++, trp++) {
+ if (__is_tr_overlap(trp, rid, va, end))
+ return i;
+ }
+ }
+ } else {
+ if (vcpu_quick_region_check(vcpu->arch.itr_regions, va)) {
+ for (trp = (struct thash_data *)&vcpu->arch.itrs, i = 0;
+ i < NITRS; i++, trp++) {
+ if (__is_tr_overlap(trp, rid, va, end))
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * Purge entries in VTLB and VHPT
+ */
+void thash_purge_entries(struct kvm_vcpu *v, u64 va, u64 ps)
+{
+ if (vcpu_quick_region_check(v->arch.tc_regions, va))
+ vtlb_purge(v, va, ps);
+ vhpt_purge(v, va, ps);
+}
+
+void thash_purge_entries_remote(struct kvm_vcpu *v, u64 va, u64 ps)
+{
+ u64 old_va = va;
+ va = REGION_OFFSET(va);
+ if (vcpu_quick_region_check(v->arch.tc_regions, old_va))
+ vtlb_purge(v, va, ps);
+ vhpt_purge(v, va, ps);
+}
+
+u64 translate_phy_pte(u64 *pte, u64 itir, u64 va)
+{
+ u64 ps, ps_mask, paddr, maddr;
+ union pte_flags phy_pte;
+
+ ps = itir_ps(itir);
+ ps_mask = ~((1UL << ps) - 1);
+ phy_pte.val = *pte;
+ paddr = *pte;
+ paddr = ((paddr & _PAGE_PPN_MASK) & ps_mask) | (va & ~ps_mask);
+ maddr = kvm_lookup_mpa(paddr >> PAGE_SHIFT);
+ if (maddr & GPFN_IO_MASK) {
+ *pte |= VTLB_PTE_IO;
+ return -1;
+ }
+ maddr = ((maddr & _PAGE_PPN_MASK) & PAGE_MASK) |
+ (paddr & ~PAGE_MASK);
+ phy_pte.ppn = maddr >> ARCH_PAGE_SHIFT;
+ return phy_pte.val;
+}
+
+/*
+ * Purge overlap TCs and then insert the new entry to emulate itc ops.
+ * Notes: Only TC entry can purge and insert.
+ * 1 indicates this is MMIO
+ */
+int thash_purge_and_insert(struct kvm_vcpu *v, u64 pte, u64 itir,
+ u64 ifa, int type)
+{
+ u64 ps;
+ u64 phy_pte;
+ union ia64_rr vrr, mrr;
+ int ret = 0;
+
+ ps = itir_ps(itir);
+ vrr.val = vcpu_get_rr(v, ifa);
+ mrr.val = ia64_get_rr(ifa);
+
+ phy_pte = translate_phy_pte(&pte, itir, ifa);
+
+ /* Ensure WB attribute if pte is related to a normal mem page,
+ * which is required by vga acceleration since qemu maps shared
+ * vram buffer with WB.
+ */
+ if (!(pte & VTLB_PTE_IO) && ((pte & _PAGE_MA_MASK) != _PAGE_MA_NAT)) {
+ pte &= ~_PAGE_MA_MASK;
+ phy_pte &= ~_PAGE_MA_MASK;
+ }
+
+ if (pte & VTLB_PTE_IO)
+ ret = 1;
+
+ vtlb_purge(v, ifa, ps);
+ vhpt_purge(v, ifa, ps);
+
+ if (ps == mrr.ps) {
+ if (!(pte&VTLB_PTE_IO)) {
+ vhpt_insert(phy_pte, itir, ifa, pte);
+ } else {
+ vtlb_insert(v, pte, itir, ifa);
+ vcpu_quick_region_set(VMX(v, tc_regions), ifa);
+ }
+ } else if (ps > mrr.ps) {
+ vtlb_insert(v, pte, itir, ifa);
+ vcpu_quick_region_set(VMX(v, tc_regions), ifa);
+ if (!(pte&VTLB_PTE_IO))
+ vhpt_insert(phy_pte, itir, ifa, pte);
+ } else {
+ u64 psr;
+ phy_pte &= ~PAGE_FLAGS_RV_MASK;
+ psr = ia64_clear_ic();
+ ia64_itc(type, ifa, phy_pte, ps);
+ ia64_set_psr(psr);
+ }
+ if (!(pte&VTLB_PTE_IO))
+ mark_pages_dirty(v, pte, ps);
+
+ return ret;
+}
+
+/*
+ * Purge all TCs or VHPT entries including those in Hash table.
+ *
+ */
+
+void thash_purge_all(struct kvm_vcpu *v)
+{
+ int i;
+ struct thash_data *head;
+ struct thash_cb *vtlb, *vhpt;
+ vtlb = &v->arch.vtlb;
+ vhpt = &v->arch.vhpt;
+
+ for (i = 0; i < 8; i++)
+ VMX(v, psbits[i]) = 0;
+
+ head = vtlb->hash;
+ for (i = 0; i < vtlb->num; i++) {
+ head->page_flags = 0;
+ head->etag = INVALID_TI_TAG;
+ head->itir = 0;
+ head->next = 0;
+ head++;
+ };
+
+ head = vhpt->hash;
+ for (i = 0; i < vhpt->num; i++) {
+ head->page_flags = 0;
+ head->etag = INVALID_TI_TAG;
+ head->itir = 0;
+ head->next = 0;
+ head++;
+ };
+
+ local_flush_tlb_all();
+}
+
+
+/*
+ * Lookup the hash table and its collision chain to find an entry
+ * covering this address rid:va or the entry.
+ *
+ * INPUT:
+ * in: TLB format for both VHPT & TLB.
+ */
+
+struct thash_data *vtlb_lookup(struct kvm_vcpu *v, u64 va, int is_data)
+{
+ struct thash_data *cch;
+ u64 psbits, ps, tag;
+ union ia64_rr vrr;
+
+ struct thash_cb *hcb = &v->arch.vtlb;
+
+ cch = __vtr_lookup(v, va, is_data);;
+ if (cch)
+ return cch;
+
+ if (vcpu_quick_region_check(v->arch.tc_regions, va) == 0)
+ return NULL;
+
+ psbits = VMX(v, psbits[(va >> 61)]);
+ vrr.val = vcpu_get_rr(v, va);
+ while (psbits) {
+ ps = __ffs(psbits);
+ psbits &= ~(1UL << ps);
+ vrr.ps = ps;
+ cch = vsa_thash(hcb->pta, va, vrr.val, &tag);
+ if (cch->etag == tag && cch->ps == ps)
+ return cch;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Initialize internal control data before service.
+ */
+void thash_init(struct thash_cb *hcb, u64 sz)
+{
+ int i;
+ struct thash_data *head;
+
+ hcb->pta.val = (unsigned long)hcb->hash;
+ hcb->pta.vf = 1;
+ hcb->pta.ve = 1;
+ hcb->pta.size = sz;
+ head = hcb->hash;
+ for (i = 0; i < hcb->num; i++) {
+ head->page_flags = 0;
+ head->itir = 0;
+ head->etag = INVALID_TI_TAG;
+ head->next = 0;
+ head++;
+ }
+}
+
+u64 kvm_lookup_mpa(u64 gpfn)
+{
+ u64 *base = (u64 *) KVM_P2M_BASE;
+ return *(base + gpfn);
+}
+
+u64 kvm_gpa_to_mpa(u64 gpa)
+{
+ u64 pte = kvm_lookup_mpa(gpa >> PAGE_SHIFT);
+ return (pte >> PAGE_SHIFT << PAGE_SHIFT) | (gpa & ~PAGE_MASK);
+}
+
+
+/*
+ * Fetch guest bundle code.
+ * INPUT:
+ * gip: guest ip
+ * pbundle: used to return fetched bundle.
+ */
+int fetch_code(struct kvm_vcpu *vcpu, u64 gip, IA64_BUNDLE *pbundle)
+{
+ u64 gpip = 0; /* guest physical IP*/
+ u64 *vpa;
+ struct thash_data *tlb;
+ u64 maddr;
+
+ if (!(VCPU(vcpu, vpsr) & IA64_PSR_IT)) {
+ /* I-side physical mode */
+ gpip = gip;
+ } else {
+ tlb = vtlb_lookup(vcpu, gip, I_TLB);
+ if (tlb)
+ gpip = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) |
+ (gip & (PSIZE(tlb->ps) - 1));
+ }
+ if (gpip) {
+ maddr = kvm_gpa_to_mpa(gpip);
+ } else {
+ tlb = vhpt_lookup(gip);
+ if (tlb == NULL) {
+ ia64_ptcl(gip, ARCH_PAGE_SHIFT << 2);
+ return IA64_FAULT;
+ }
+ maddr = (tlb->ppn >> (tlb->ps - 12) << tlb->ps)
+ | (gip & (PSIZE(tlb->ps) - 1));
+ }
+ vpa = (u64 *)__kvm_va(maddr);
+
+ pbundle->i64[0] = *vpa++;
+ pbundle->i64[1] = *vpa;
+
+ return IA64_NO_FAULT;
+}
+
+
+void kvm_init_vhpt(struct kvm_vcpu *v)
+{
+ v->arch.vhpt.num = VHPT_NUM_ENTRIES;
+ thash_init(&v->arch.vhpt, VHPT_SHIFT);
+ ia64_set_pta(v->arch.vhpt.pta.val);
+ /*Enable VHPT here?*/
+}
+
+void kvm_init_vtlb(struct kvm_vcpu *v)
+{
+ v->arch.vtlb.num = VTLB_NUM_ENTRIES;
+ thash_init(&v->arch.vtlb, VTLB_SHIFT);
+}
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 5c1de53c8c1c..fc6c6636ffda 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -682,15 +682,6 @@ mem_init (void)
}
#ifdef CONFIG_MEMORY_HOTPLUG
-void online_page(struct page *page)
-{
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalram_pages++;
- num_physpages++;
-}
-
int arch_add_memory(int nid, u64 start, u64 size)
{
pg_data_t *pgdat;
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 2b412454cb41..ded7dd2f67b2 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -186,7 +186,7 @@ int setup_irq(unsigned int irq, struct irq_node *node)
if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
printk("%s: Incorrect IRQ %d from %s\n",
- __FUNCTION__, irq, node->devname);
+ __func__, irq, node->devname);
return -ENXIO;
}
@@ -249,7 +249,7 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long flags;
if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
- printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+ printk("%s: Incorrect IRQ %d\n", __func__, irq);
return;
}
@@ -267,7 +267,7 @@ void free_irq(unsigned int irq, void *dev_id)
node->handler = NULL;
} else
printk("%s: Removing probably wrong IRQ %d\n",
- __FUNCTION__, irq);
+ __func__, irq);
if (!irq_list[irq]) {
if (contr->shutdown)
@@ -288,7 +288,7 @@ void enable_irq(unsigned int irq)
if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
printk("%s: Incorrect IRQ %d\n",
- __FUNCTION__, irq);
+ __func__, irq);
return;
}
@@ -312,7 +312,7 @@ void disable_irq(unsigned int irq)
if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
printk("%s: Incorrect IRQ %d\n",
- __FUNCTION__, irq);
+ __func__, irq);
return;
}
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 50603d3dce84..3c943d2ec570 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -190,7 +190,7 @@ void oss_irq_enable(int irq) {
break;
#ifdef DEBUG_IRQUSE
default:
- printk("%s unknown irq %d\n",__FUNCTION__, irq);
+ printk("%s unknown irq %d\n", __func__, irq);
break;
#endif
}
@@ -230,7 +230,7 @@ void oss_irq_disable(int irq) {
break;
#ifdef DEBUG_IRQUSE
default:
- printk("%s unknown irq %d\n", __FUNCTION__, irq);
+ printk("%s unknown irq %d\n", __func__, irq);
break;
#endif
}
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index f42caa79e4e8..a2bb01f59642 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -79,7 +79,6 @@ void show_mem(void)
printk("\nMem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
for_each_online_pgdat(pgdat) {
for (i = 0; i < pgdat->node_spanned_pages; i++) {
struct page *page = pgdat->node_mem_map + i;
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 46161cef08b9..9f0e3d59bf92 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -47,7 +47,7 @@ static int q40_irq_startup(unsigned int irq)
switch (irq) {
case 1: case 2: case 8: case 9:
case 11: case 12: case 13:
- printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq);
+ printk("%s: ISA IRQ %d not implemented by HW\n", __func__, irq);
return -ENXIO;
}
return 0;
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8724ed3298d3..e5a7c5d96364 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -81,7 +81,9 @@ config MIPS_COBALT
config MACH_DECSTATION
bool "DECstations"
select BOOT_ELF32
+ select CEVT_DS1287
select CEVT_R4K
+ select CSRC_IOASIC
select CSRC_R4K
select CPU_DADDI_WORKAROUNDS if 64BIT
select CPU_R4000_WORKAROUNDS if 64BIT
@@ -221,6 +223,7 @@ config MIPS_MALTA
select DMA_NONCOHERENT
select GENERIC_ISA_DMA
select IRQ_CPU
+ select IRQ_GIC
select HW_HAS_PCI
select I8253
select I8259
@@ -309,12 +312,12 @@ config MACH_VR41XX
select GENERIC_HARDIRQS_NO__DO_IRQ
config PNX8550_JBS
- bool "Philips PNX8550 based JBS board"
+ bool "NXP PNX8550 based JBS board"
select PNX8550
select SYS_SUPPORTS_LITTLE_ENDIAN
config PNX8550_STB810
- bool "Philips PNX8550 based STB810 board"
+ bool "NXP PNX8550 based STB810 board"
select PNX8550
select SYS_SUPPORTS_LITTLE_ENDIAN
@@ -612,6 +615,7 @@ config TOSHIBA_JMR3927
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_BIG_ENDIAN
select GENERIC_HARDIRQS_NO__DO_IRQ
+ select GPIO_TXX9
config TOSHIBA_RBTX4927
bool "Toshiba RBTX49[23]7 board"
@@ -653,7 +657,7 @@ config TOSHIBA_RBTX4938
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_KGDB
select GENERIC_HARDIRQS_NO__DO_IRQ
- select GENERIC_GPIO
+ select GPIO_TXX9
help
This Toshiba board is based on the TX4938 processor. Say Y here to
support this machine type
@@ -767,6 +771,9 @@ config BOOT_RAW
config CEVT_BCM1480
bool
+config CEVT_DS1287
+ bool
+
config CEVT_GT641XX
bool
@@ -782,12 +789,20 @@ config CEVT_TXX9
config CSRC_BCM1480
bool
+config CSRC_IOASIC
+ bool
+
config CSRC_R4K
bool
config CSRC_SB1250
bool
+config GPIO_TXX9
+ select GENERIC_GPIO
+ select HAVE_GPIO_LIB
+ bool
+
config CFE
bool
@@ -840,6 +855,9 @@ config MIPS_NILE4
config MIPS_DISABLE_OBSOLETE_IDE
bool
+config SYNC_R4K
+ bool
+
config NO_IOPORT
def_bool n
@@ -909,6 +927,9 @@ config IRQ_TXX9
config IRQ_GT641XX
bool
+config IRQ_GIC
+ bool
+
config MIPS_BOARDS_GEN
bool
@@ -1811,6 +1832,17 @@ config NR_CPUS
performance should round up your number of processors to the next
power of two.
+config MIPS_CMP
+ bool "MIPS CMP framework support"
+ depends on SMP
+ select SYNC_R4K
+ select SYS_SUPPORTS_SCHED_SMT
+ select WEAK_ORDERING
+ default n
+ help
+ This is a placeholder option for the GCMP work. It will need to
+ be handled differently...
+
source "kernel/time/Kconfig"
#
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index fd7124c1b75a..f18cf92650e3 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -73,14 +73,4 @@ config RUNTIME_DEBUG
include/asm-mips/debug.h for debuging macros.
If unsure, say N.
-config MIPS_UNCACHED
- bool "Run uncached"
- depends on DEBUG_KERNEL && !SMP && !SGI_IP27
- help
- If you say Y here there kernel will disable all CPU caches. This will
- reduce the system's performance dramatically but can help finding
- otherwise hard to track bugs. It can also useful if you're doing
- hardware debugging with a logic analyzer and need to see all traffic
- on the bus.
-
endmenu
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 1c62381f5c23..69648d01acc0 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -410,21 +410,21 @@ load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
#
-# Common Philips PNX8550
+# Common NXP PNX8550
#
-core-$(CONFIG_SOC_PNX8550) += arch/mips/philips/pnx8550/common/
+core-$(CONFIG_SOC_PNX8550) += arch/mips/nxp/pnx8550/common/
cflags-$(CONFIG_SOC_PNX8550) += -Iinclude/asm-mips/mach-pnx8550
#
-# Philips PNX8550 JBS board
+# NXP PNX8550 JBS board
#
-libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/
+libs-$(CONFIG_PNX8550_JBS) += arch/mips/nxp/pnx8550/jbs/
#cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550
load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
-# Philips PNX8550 STB810 board
+# NXP PNX8550 STB810 board
#
-libs-$(CONFIG_PNX8550_STB810) += arch/mips/philips/pnx8550/stb810/
+libs-$(CONFIG_PNX8550_STB810) += arch/mips/nxp/pnx8550/stb810/
load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000
# NEC EMMA2RH boards
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c
index 5c0d35d6e22a..8c93a05d7382 100644
--- a/arch/mips/au1000/common/cputable.c
+++ b/arch/mips/au1000/common/cputable.c
@@ -11,10 +11,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/threads.h>
-#include <linux/init.h>
+
#include <asm/mach-au1x00/au1000.h>
struct cpu_spec* cur_cpu_spec[NR_CPUS];
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index 57f17b41098d..53377dfc0640 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -31,18 +31,12 @@
*/
#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/system.h>
-
#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
diff --git a/arch/mips/au1000/common/dbg_io.c b/arch/mips/au1000/common/dbg_io.c
index 79e0b0a51ace..eae1bb2ca26e 100644
--- a/arch/mips/au1000/common/dbg_io.c
+++ b/arch/mips/au1000/common/dbg_io.c
@@ -1,5 +1,4 @@
-#include <asm/io.h>
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_KGDB
@@ -55,8 +54,7 @@ typedef unsigned int uint32;
#define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff)
#define UART16550_WRITE(y, z) (au_writel(z&0xff, DEBUG_BASE + y))
-extern unsigned long get_au1x00_uart_baud_base(void);
-extern unsigned long cal_r4koff(void);
+extern unsigned long calc_clock(void);
void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
{
@@ -64,7 +62,7 @@ void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
if (UART16550_READ(UART_MOD_CNTRL) != 0x3) {
UART16550_WRITE(UART_MOD_CNTRL, 3);
}
- cal_r4koff();
+ calc_clock();
/* disable interrupts */
UART16550_WRITE(UART_IER, 0);
diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c
index c78260d4e837..95f69ea146e9 100644
--- a/arch/mips/au1000/common/dma.c
+++ b/arch/mips/au1000/common/dma.c
@@ -33,12 +33,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <asm/system.h>
+
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1000_dma.h>
diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c
index 0b658f1db4ce..525452589971 100644
--- a/arch/mips/au1000/common/gpio.c
+++ b/arch/mips/au1000/common/gpio.c
@@ -27,13 +27,8 @@
* others have a second one : GPIO2
*/
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/types.h>
#include <linux/module.h>
-#include <asm/addrspace.h>
-
#include <asm/mach-au1x00/au1000.h>
#include <asm/gpio.h>
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 3c7714f057ac..f0626992fd75 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -1,7 +1,6 @@
/*
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
+ * Copyright 2001, 2007-2008 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. <source@mvista.com>
*
* Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
*
@@ -27,7 +26,6 @@
*/
#include <linux/bitops.h>
#include <linux/init.h>
-#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -591,7 +589,7 @@ void __init arch_init_irq(void)
imp++;
}
- set_c0_status(ALLINTS);
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
/* Board specific IRQ initialization.
*/
diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c
index ce771487567d..7e966b31e3e1 100644
--- a/arch/mips/au1000/common/pci.c
+++ b/arch/mips/au1000/common/pci.c
@@ -30,7 +30,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/types.h>
+
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index 39d681265297..31d2a2270878 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -3,18 +3,65 @@
*
* Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
*
+ * (C) Copyright Embedded Alley Solutions, Inc 2005
+ * Author: Pantelis Antoniou <pantelis@embeddedalley.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/device.h>
+
#include <linux/platform_device.h>
-#include <linux/kernel.h>
+#include <linux/serial_8250.h>
#include <linux/init.h>
-#include <linux/resource.h>
#include <asm/mach-au1x00/au1xxx.h>
+#define PORT(_base, _irq) \
+ { \
+ .iobase = _base, \
+ .membase = (void __iomem *)_base,\
+ .mapbase = CPHYSADDR(_base), \
+ .irq = _irq, \
+ .regshift = 2, \
+ .iotype = UPIO_AU, \
+ .flags = UPF_SKIP_TEST \
+ }
+
+static struct plat_serial8250_port au1x00_uart_data[] = {
+#if defined(CONFIG_SERIAL_8250_AU1X00)
+#if defined(CONFIG_SOC_AU1000)
+ PORT(UART0_ADDR, AU1000_UART0_INT),
+ PORT(UART1_ADDR, AU1000_UART1_INT),
+ PORT(UART2_ADDR, AU1000_UART2_INT),
+ PORT(UART3_ADDR, AU1000_UART3_INT),
+#elif defined(CONFIG_SOC_AU1500)
+ PORT(UART0_ADDR, AU1500_UART0_INT),
+ PORT(UART3_ADDR, AU1500_UART3_INT),
+#elif defined(CONFIG_SOC_AU1100)
+ PORT(UART0_ADDR, AU1100_UART0_INT),
+ PORT(UART1_ADDR, AU1100_UART1_INT),
+ PORT(UART3_ADDR, AU1100_UART3_INT),
+#elif defined(CONFIG_SOC_AU1550)
+ PORT(UART0_ADDR, AU1550_UART0_INT),
+ PORT(UART1_ADDR, AU1550_UART1_INT),
+ PORT(UART3_ADDR, AU1550_UART3_INT),
+#elif defined(CONFIG_SOC_AU1200)
+ PORT(UART0_ADDR, AU1200_UART0_INT),
+ PORT(UART1_ADDR, AU1200_UART1_INT),
+#endif
+#endif /* CONFIG_SERIAL_8250_AU1X00 */
+ { },
+};
+
+static struct platform_device au1xx0_uart_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_AU1X00,
+ .dev = {
+ .platform_data = au1x00_uart_data,
+ },
+};
+
/* OHCI (USB full speed host controller) */
static struct resource au1xxx_usb_ohci_resources[] = {
[0] = {
@@ -186,19 +233,6 @@ static struct resource au1200_lcd_resources[] = {
}
};
-static struct resource au1200_ide0_resources[] = {
- [0] = {
- .start = AU1XXX_ATA_PHYS_ADDR,
- .end = AU1XXX_ATA_PHYS_ADDR + AU1XXX_ATA_PHYS_LEN - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AU1XXX_ATA_INT,
- .end = AU1XXX_ATA_INT,
- .flags = IORESOURCE_IRQ,
- }
-};
-
static u64 au1200_lcd_dmamask = ~(u32)0;
static struct platform_device au1200_lcd_device = {
@@ -212,20 +246,6 @@ static struct platform_device au1200_lcd_device = {
.resource = au1200_lcd_resources,
};
-
-static u64 ide0_dmamask = ~(u32)0;
-
-static struct platform_device au1200_ide0_device = {
- .name = "au1200-ide",
- .id = 0,
- .dev = {
- .dma_mask = &ide0_dmamask,
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(au1200_ide0_resources),
- .resource = au1200_ide0_resources,
-};
-
static u64 au1xxx_mmc_dmamask = ~(u32)0;
static struct platform_device au1xxx_mmc_device = {
@@ -245,31 +265,6 @@ static struct platform_device au1x00_pcmcia_device = {
.id = 0,
};
-#ifdef CONFIG_MIPS_DB1200
-
-static struct resource smc91x_resources[] = {
- [0] = {
- .name = "smc91x-regs",
- .start = AU1XXX_SMC91111_PHYS_ADDR,
- .end = AU1XXX_SMC91111_PHYS_ADDR + 0xfffff,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AU1XXX_SMC91111_IRQ,
- .end = AU1XXX_SMC91111_IRQ,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device smc91x_device = {
- .name = "smc91x",
- .id = -1,
- .num_resources = ARRAY_SIZE(smc91x_resources),
- .resource = smc91x_resources,
-};
-
-#endif
-
/* All Alchemy demoboards with I2C have this #define in their headers */
#ifdef SMBUS_PSC_BASE
static struct resource pbdb_smbus_resources[] = {
@@ -289,6 +284,7 @@ static struct platform_device pbdb_smbus_device = {
#endif
static struct platform_device *au1xxx_platform_devices[] __initdata = {
+ &au1xx0_uart_device,
&au1xxx_usb_ohci_device,
&au1x00_pcmcia_device,
#ifdef CONFIG_FB_AU1100
@@ -299,12 +295,8 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
&au1xxx_usb_gdt_device,
&au1xxx_usb_otg_device,
&au1200_lcd_device,
- &au1200_ide0_device,
&au1xxx_mmc_device,
#endif
-#ifdef CONFIG_MIPS_DB1200
- &smc91x_device,
-#endif
#ifdef SMBUS_PSC_BASE
&pbdb_smbus_device,
#endif
@@ -312,6 +304,13 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
int __init au1xxx_platform_init(void)
{
+ unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
+ int i;
+
+ /* Fill up uartclk. */
+ for (i = 0; au1x00_uart_data[i].flags ; i++)
+ au1x00_uart_data[i].uartclk = uartclk;
+
return platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices));
}
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 54047d69b820..a8cd2c1b9e1b 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -29,17 +29,14 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/pm_legacy.h>
-#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/jiffies.h>
-#include <asm/string.h>
#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/mach-au1x00/au1000.h>
@@ -47,17 +44,13 @@
#define DEBUG 1
#ifdef DEBUG
-# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__, ## args)
#else
# define DPRINTK(fmt, args...)
#endif
static void au1000_calibrate_delay(void);
-extern void set_au1x00_speed(unsigned int new_freq);
-extern unsigned int get_au1x00_speed(void);
-extern unsigned long get_au1x00_uart_baud_base(void);
-extern void set_au1x00_uart_baud_base(unsigned long new_baud_base);
extern unsigned long save_local_and_disable(int controller);
extern void restore_local_and_enable(int controller, unsigned long mask);
extern void local_enable_irq(unsigned int irq_nr);
@@ -258,7 +251,6 @@ int au_sleep(void)
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
void __user *buffer, size_t * len, loff_t *ppos)
{
- int retval = 0;
#ifdef SLEEP_TEST_TIMEOUT
#define TMPBUFLEN2 16
char buf[TMPBUFLEN2], *p;
@@ -278,36 +270,12 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
p = buf;
sleep_ticks = simple_strtoul(p, &p, 0);
#endif
- retval = pm_send_all(PM_SUSPEND, (void *) 2);
-
- if (retval)
- return retval;
au_sleep();
- retval = pm_send_all(PM_RESUME, (void *) 0);
- }
- return retval;
-}
-
-static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
- void __user *buffer, size_t * len, loff_t *ppos)
-{
- int retval = 0;
-
- if (!write) {
- *len = 0;
- } else {
- retval = pm_send_all(PM_SUSPEND, (void *) 2);
- if (retval)
- return retval;
- suspend_mode = 1;
-
- retval = pm_send_all(PM_RESUME, (void *) 0);
}
- return retval;
+ return 0;
}
-
static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
void __user *buffer, size_t * len, loff_t *ppos)
{
@@ -421,14 +389,6 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
static struct ctl_table pm_table[] = {
{
- .ctl_name = CTL_UNNUMBERED,
- .procname = "suspend",
- .data = NULL,
- .maxlen = 0,
- .mode = 0600,
- .proc_handler = &pm_do_suspend
- },
- {
.ctl_name = CTL_UNNUMBERED,
.procname = "sleep",
.data = NULL,
diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c
index 90d70695aa60..f10af829e4ec 100644
--- a/arch/mips/au1000/common/prom.c
+++ b/arch/mips/au1000/common/prom.c
@@ -33,8 +33,8 @@
* 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/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
diff --git a/arch/mips/au1000/common/puts.c b/arch/mips/au1000/common/puts.c
index 2705829cd466..e34c67e89293 100644
--- a/arch/mips/au1000/common/puts.c
+++ b/arch/mips/au1000/common/puts.c
@@ -28,7 +28,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/types.h>
#include <asm/mach-au1x00/au1000.h>
#define SERIAL_BASE UART_BASE
diff --git a/arch/mips/au1000/common/reset.c b/arch/mips/au1000/common/reset.c
index b8638d293cf9..60cec537c745 100644
--- a/arch/mips/au1000/common/reset.c
+++ b/arch/mips/au1000/common/reset.c
@@ -27,13 +27,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
+
#include <asm/mach-au1x00/au1000.h>
extern int au_sleep(void);
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 9e4ab80caab6..0e86f7a6b4a7 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -25,21 +25,14 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pm.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/time.h>
#include <au1000.h>
@@ -49,8 +42,6 @@ extern void __init board_setup(void);
extern void au1000_restart(char *);
extern void au1000_halt(void);
extern void au1000_power_off(void);
-extern void au1x_time_init(void);
-extern void au1x_timer_setup(struct irqaction *irq);
extern void set_cpuspec(void);
void __init plat_mem_setup(void)
diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S
index 683d9da84b66..4b3cf021a454 100644
--- a/arch/mips/au1000/common/sleeper.S
+++ b/arch/mips/au1000/common/sleeper.S
@@ -9,9 +9,9 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+
#include <asm/asm.h>
#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index e122bbc6cd88..bdb6d73b26fb 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com
+ * Copyright (C) 2001, 2006, 2008 MontaVista Software, <source@mvista.com>
* Copied and modified Carsten Langgaard's time.c
*
* Carsten Langgaard, carstenl@mips.com
@@ -34,23 +34,13 @@
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
-#include <linux/hardirq.h>
-#include <asm/compiler.h>
#include <asm/mipsregs.h>
#include <asm/time.h>
-#include <asm/div64.h>
#include <asm/mach-au1x00/au1000.h>
-#include <linux/mc146818rtc.h>
-#include <linux/timex.h>
-
-static unsigned long r4k_offset; /* Amount to increment compare reg each time */
-static unsigned long r4k_cur; /* What counter should be at next timer irq */
-int no_au1xxx_32khz;
+static int no_au1xxx_32khz;
extern int allow_au1k_wait; /* default off for CP0 Counter */
#ifdef CONFIG_PM
@@ -184,7 +174,7 @@ wakeup_counter0_set(int ticks)
* "wait" is enabled, and we need to detect if the 32KHz isn't present
* but requested......got it? :-) -- Dan
*/
-unsigned long cal_r4koff(void)
+unsigned long calc_clock(void)
{
unsigned long cpu_speed;
unsigned long flags;
@@ -229,19 +219,13 @@ unsigned long cal_r4koff(void)
// Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16)
set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
spin_unlock_irqrestore(&time_lock, flags);
- return (cpu_speed / HZ);
+ return cpu_speed;
}
void __init plat_time_init(void)
{
- unsigned int est_freq;
-
- printk("calculating r4koff... ");
- r4k_offset = cal_r4koff();
- printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+ unsigned int est_freq = calc_clock();
- //est_freq = 2*r4k_offset*HZ;
- est_freq = r4k_offset*HZ;
est_freq += 5000; /* round */
est_freq -= est_freq%10000;
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
@@ -249,9 +233,6 @@ void __init plat_time_init(void)
set_au1x00_speed(est_freq);
set_au1x00_lcd_clock(); // program the LCD clock
- r4k_cur = (read_c0_count() + r4k_offset);
- write_c0_compare(r4k_cur);
-
#ifdef CONFIG_PM
/*
* setup counter 0, since it keeps ticking after a
@@ -265,12 +246,8 @@ void __init plat_time_init(void)
* Check to ensure we really have a 32KHz oscillator before
* we do this.
*/
- if (no_au1xxx_32khz) {
+ if (no_au1xxx_32khz)
printk("WARNING: no 32KHz clock found.\n");
-
- /* Ensure we get CPO_COUNTER interrupts. */
- set_c0_status(IE_IRQ5);
- }
else {
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
au_writel(0, SYS_TOYWRITE);
diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c
index 99eafeada518..b7dcbad5c586 100644
--- a/arch/mips/au1000/db1x00/board_setup.c
+++ b/arch/mips/au1000/db1x00/board_setup.c
@@ -27,20 +27,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/mc146818rtc.h>
-#include <linux/delay.h>
-
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
+
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-db1x00/db1x00.h>
diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c
index e822c123eab8..d3b967caf70c 100644
--- a/arch/mips/au1000/db1x00/init.c
+++ b/arch/mips/au1000/db1x00/init.c
@@ -28,13 +28,8 @@
*/
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/db1x00/irqmap.c b/arch/mips/au1000/db1x00/irqmap.c
index 09cea03411b0..eaa50c7b6341 100644
--- a/arch/mips/au1000/db1x00/irqmap.c
+++ b/arch/mips/au1000/db1x00/irqmap.c
@@ -25,26 +25,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_MIPS_DB1500
diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c
index 310d5dff89fc..5736354829c6 100644
--- a/arch/mips/au1000/mtx-1/board_setup.c
+++ b/arch/mips/au1000/mtx-1/board_setup.c
@@ -28,19 +28,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/mach-au1x00/au1000.h>
extern int (*board_pci_idsel)(unsigned int devsel, int assert);
diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c
index e700fd312a24..c015cbce1cca 100644
--- a/arch/mips/au1000/mtx-1/init.c
+++ b/arch/mips/au1000/mtx-1/init.c
@@ -28,14 +28,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/string.h>
+
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/mtx-1/irqmap.c b/arch/mips/au1000/mtx-1/irqmap.c
index 49c612aeddcf..78d70c42c9db 100644
--- a/arch/mips/au1000/mtx-1/irqmap.c
+++ b/arch/mips/au1000/mtx-1/irqmap.c
@@ -25,26 +25,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
char irq_tab_alchemy[][5] __initdata = {
diff --git a/arch/mips/au1000/mtx-1/platform.c b/arch/mips/au1000/mtx-1/platform.c
index ce8637b3afa9..a7edbf0829ac 100644
--- a/arch/mips/au1000/mtx-1/platform.c
+++ b/arch/mips/au1000/mtx-1/platform.c
@@ -19,7 +19,6 @@
*/
#include <linux/init.h>
-#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/gpio_keys.h>
diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c
index 5198c4f98b43..33f15acc1b17 100644
--- a/arch/mips/au1000/pb1000/board_setup.c
+++ b/arch/mips/au1000/pb1000/board_setup.c
@@ -23,19 +23,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
#include <linux/delay.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-pb1x00/pb1000.h>
diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c
index 2515b9fb24af..549447df71d6 100644
--- a/arch/mips/au1000/pb1000/init.c
+++ b/arch/mips/au1000/pb1000/init.c
@@ -26,14 +26,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/pb1000/irqmap.c b/arch/mips/au1000/pb1000/irqmap.c
index 88e354508204..b3d56b0af321 100644
--- a/arch/mips/au1000/pb1000/irqmap.c
+++ b/arch/mips/au1000/pb1000/irqmap.c
@@ -25,26 +25,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c
index 42874a6b31d1..656164c8e9ca 100644
--- a/arch/mips/au1000/pb1100/board_setup.c
+++ b/arch/mips/au1000/pb1100/board_setup.c
@@ -23,19 +23,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
#include <linux/delay.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-pb1x00/pb1100.h>
diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c
index 490c3801c275..c91344648ed3 100644
--- a/arch/mips/au1000/pb1100/init.c
+++ b/arch/mips/au1000/pb1100/init.c
@@ -27,14 +27,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/pb1100/irqmap.c b/arch/mips/au1000/pb1100/irqmap.c
index 880456bf8c11..b5021e3d477f 100644
--- a/arch/mips/au1000/pb1100/irqmap.c
+++ b/arch/mips/au1000/pb1100/irqmap.c
@@ -25,26 +25,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile
index 970b1b1d5cda..4fe02ea65a60 100644
--- a/arch/mips/au1000/pb1200/Makefile
+++ b/arch/mips/au1000/pb1200/Makefile
@@ -3,5 +3,6 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y += platform.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c
index b98bebfa87c6..4493a792cc4c 100644
--- a/arch/mips/au1000/pb1200/board_setup.c
+++ b/arch/mips/au1000/pb1200/board_setup.c
@@ -23,27 +23,11 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/mc146818rtc.h>
-#include <linux/delay.h>
-
-#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
-#include <linux/ide.h>
-#endif
-
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <au1000.h>
-#include <au1xxx_dbdma.h>
#include <prom.h>
#ifdef CONFIG_MIPS_PB1200
@@ -52,8 +36,6 @@
#ifdef CONFIG_MIPS_DB1200
#include <asm/mach-db1x00/db1200.h>
-#define PB1200_ETH_INT DB1200_ETH_INT
-#define PB1200_IDE_INT DB1200_IDE_INT
#endif
extern void _board_init_irq(void);
diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c
index 069ed45f04f2..72af5500660b 100644
--- a/arch/mips/au1000/pb1200/init.c
+++ b/arch/mips/au1000/pb1200/init.c
@@ -27,14 +27,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
index 8fcd0df86f93..e61eb8e0b76b 100644
--- a/arch/mips/au1000/pb1200/irqmap.c
+++ b/arch/mips/au1000/pb1200/irqmap.c
@@ -22,26 +22,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
+
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_MIPS_PB1200
diff --git a/arch/mips/au1000/pb1200/platform.c b/arch/mips/au1000/pb1200/platform.c
new file mode 100644
index 000000000000..5930110b9b6d
--- /dev/null
+++ b/arch/mips/au1000/pb1200/platform.c
@@ -0,0 +1,84 @@
+/*
+ * Pb1200/DBAu1200 board platform device registration
+ *
+ * Copyright (C) 2008 MontaVista Software Inc. <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1xxx.h>
+
+static struct resource ide_resources[] = {
+ [0] = {
+ .start = IDE_PHYS_ADDR,
+ .end = IDE_PHYS_ADDR + IDE_PHYS_LEN - 1,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = IDE_INT,
+ .end = IDE_INT,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static u64 ide_dmamask = ~(u32)0;
+
+static struct platform_device ide_device = {
+ .name = "au1200-ide",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ide_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(ide_resources),
+ .resource = ide_resources
+};
+
+static struct resource smc91c111_resources[] = {
+ [0] = {
+ .name = "smc91x-regs",
+ .start = SMC91C111_PHYS_ADDR,
+ .end = SMC91C111_PHYS_ADDR + 0xf,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = SMC91C111_INT,
+ .end = SMC91C111_INT,
+ .flags = IORESOURCE_IRQ
+ },
+};
+
+static struct platform_device smc91c111_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smc91c111_resources),
+ .resource = smc91c111_resources
+};
+
+static struct platform_device *board_platform_devices[] __initdata = {
+ &ide_device,
+ &smc91c111_device
+};
+
+static int __init board_register_devices(void)
+{
+ return platform_add_devices(board_platform_devices,
+ ARRAY_SIZE(board_platform_devices));
+}
+
+arch_initcall(board_register_devices);
diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c
index 5446836869d6..24c652e8ec4b 100644
--- a/arch/mips/au1000/pb1500/board_setup.c
+++ b/arch/mips/au1000/pb1500/board_setup.c
@@ -23,19 +23,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
#include <linux/delay.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-pb1x00/pb1500.h>
diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c
index db558c967048..488507c07db9 100644
--- a/arch/mips/au1000/pb1500/init.c
+++ b/arch/mips/au1000/pb1500/init.c
@@ -27,14 +27,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/pb1500/irqmap.c b/arch/mips/au1000/pb1500/irqmap.c
index 810f695e24bb..4817ab44d07f 100644
--- a/arch/mips/au1000/pb1500/irqmap.c
+++ b/arch/mips/au1000/pb1500/irqmap.c
@@ -25,26 +25,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
char irq_tab_alchemy[][5] __initdata = {
diff --git a/arch/mips/au1000/pb1550/board_setup.c b/arch/mips/au1000/pb1550/board_setup.c
index e3cfb0d73180..45d60872b565 100644
--- a/arch/mips/au1000/pb1550/board_setup.c
+++ b/arch/mips/au1000/pb1550/board_setup.c
@@ -27,20 +27,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/mc146818rtc.h>
-#include <linux/delay.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-pb1x00/pb1550.h>
diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c
index b716363ea564..f6b2fc587980 100644
--- a/arch/mips/au1000/pb1550/init.c
+++ b/arch/mips/au1000/pb1550/init.c
@@ -27,14 +27,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/pb1550/irqmap.c b/arch/mips/au1000/pb1550/irqmap.c
index 56becab28e5d..e1dac37af08a 100644
--- a/arch/mips/au1000/pb1550/irqmap.c
+++ b/arch/mips/au1000/pb1550/irqmap.c
@@ -25,26 +25,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
char irq_tab_alchemy[][5] __initdata = {
diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/au1000/xxs1500/board_setup.c
index b2e413e597a8..79d1798621bf 100644
--- a/arch/mips/au1000/xxs1500/board_setup.c
+++ b/arch/mips/au1000/xxs1500/board_setup.c
@@ -23,19 +23,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/console.h>
#include <linux/delay.h>
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/pgtable.h>
#include <asm/mach-au1x00/au1000.h>
void board_reset(void)
diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c
index 7e6878c1b0a5..24fc6e132dc0 100644
--- a/arch/mips/au1000/xxs1500/init.c
+++ b/arch/mips/au1000/xxs1500/init.c
@@ -26,14 +26,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <prom.h>
diff --git a/arch/mips/au1000/xxs1500/irqmap.c b/arch/mips/au1000/xxs1500/irqmap.c
index a343da134334..dd6e3d1eb4d4 100644
--- a/arch/mips/au1000/xxs1500/irqmap.c
+++ b/arch/mips/au1000/xxs1500/irqmap.c
@@ -25,26 +25,9 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/errno.h>
+
#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig
index 6db0bdaefb27..4f6bce99d5cf 100644
--- a/arch/mips/configs/mipssim_defconfig
+++ b/arch/mips/configs/mipssim_defconfig
@@ -641,7 +641,6 @@ CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp"
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_RUNTIME_DEBUG is not set
-# CONFIG_MIPS_UNCACHED is not set
#
# Security options
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig
index 518a60892b78..780c7fc24b82 100644
--- a/arch/mips/configs/pnx8550-jbs_defconfig
+++ b/arch/mips/configs/pnx8550-jbs_defconfig
@@ -1223,7 +1223,6 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
# CONFIG_KGDB is not set
CONFIG_SYS_SUPPORTS_KGDB=y
# CONFIG_RUNTIME_DEBUG is not set
-# CONFIG_MIPS_UNCACHED is not set
#
# Security options
diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig
index 68351eb81bc8..267f21ed1d0f 100644
--- a/arch/mips/configs/pnx8550-stb810_defconfig
+++ b/arch/mips/configs/pnx8550-stb810_defconfig
@@ -1213,7 +1213,6 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
# CONFIG_KGDB is not set
CONFIG_SYS_SUPPORTS_KGDB=y
# CONFIG_RUNTIME_DEBUG is not set
-# CONFIG_MIPS_UNCACHED is not set
#
# Security options
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
index 60349062595a..3965fda94a89 100644
--- a/arch/mips/dec/time.c
+++ b/arch/mips/dec/time.c
@@ -9,30 +9,15 @@
*
*/
#include <linux/bcd.h>
-#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/mc146818rtc.h>
-#include <linux/mm.h>
-#include <linux/module.h>
#include <linux/param.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/time.h>
-#include <linux/types.h>
-
-#include <asm/bootinfo.h>
-#include <asm/cpu.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/sections.h>
-#include <asm/time.h>
+#include <asm/cpu-features.h>
+#include <asm/ds1287.h>
+#include <asm/time.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/ioasic.h>
-#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/machtype.h>
unsigned long read_persistent_clock(void)
@@ -139,42 +124,32 @@ int rtc_mips_set_mmss(unsigned long nowtime)
return retval;
}
-static int dec_timer_state(void)
+void __init plat_time_init(void)
{
- return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
-}
+ u32 start, end;
+ int i = HZ / 10;
-static void dec_timer_ack(void)
-{
- CMOS_READ(RTC_REG_C); /* Ack the RTC interrupt. */
-}
-
-static cycle_t dec_ioasic_hpt_read(void)
-{
- /*
- * The free-running counter is 32-bit which is good for about
- * 2 minutes, 50 seconds at possible count rates of up to 25MHz.
- */
- return ioasic_read(IO_REG_FCTR);
-}
+ /* Set up the rate of periodic DS1287 interrupts. */
+ ds1287_set_base_clock(HZ);
+ if (cpu_has_counter) {
+ while (!ds1287_timer_state())
+ ;
-void __init plat_time_init(void)
-{
- mips_timer_ack = dec_timer_ack;
+ start = read_c0_count();
- if (!cpu_has_counter && IOASIC)
- /* For pre-R4k systems we use the I/O ASIC's counter. */
- clocksource_mips.read = dec_ioasic_hpt_read;
+ while (i--)
+ while (!ds1287_timer_state())
+ ;
- /* Set up the rate of periodic DS1287 interrupts. */
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A);
-}
+ end = read_c0_count();
-void __init plat_timer_setup(struct irqaction *irq)
-{
- setup_irq(dec_interrupt[DEC_IRQ_RTC], irq);
+ mips_hpt_frequency = (end - start) * 10;
+ printk(KERN_INFO "MIPS counter frequency %dHz\n",
+ mips_hpt_frequency);
+ } else if (IOASIC)
+ /* For pre-R4k systems we use the I/O ASIC's counter. */
+ dec_ioasic_clocksource_init();
- /* Enable periodic DS1287 interrupts. */
- CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B);
+ ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]);
}
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c
index c886d804d303..f39c444e42d4 100644
--- a/arch/mips/jmr3927/rbhma3100/setup.c
+++ b/arch/mips/jmr3927/rbhma3100/setup.c
@@ -36,11 +36,13 @@
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/gpio.h>
#ifdef CONFIG_SERIAL_TXX9
#include <linux/serial_core.h>
#endif
#include <asm/txx9tmr.h>
+#include <asm/txx9pio.h>
#include <asm/reboot.h>
#include <asm/jmr3927/jmr3927.h>
#include <asm/mipsregs.h>
@@ -340,9 +342,12 @@ static void __init tx3927_setup(void)
/* PIO */
/* PIO[15:12] connected to LEDs */
- tx3927_pioptr->dir = 0x0000f000;
- tx3927_pioptr->maskcpu = 0;
- tx3927_pioptr->maskext = 0;
+ __raw_writel(0x0000f000, &tx3927_pioptr->dir);
+ __raw_writel(0, &tx3927_pioptr->maskcpu);
+ __raw_writel(0, &tx3927_pioptr->maskext);
+ txx9_gpio_init(TX3927_PIO_REG, 0, 16);
+ gpio_request(11, "dipsw1");
+ gpio_request(10, "dipsw2");
{
unsigned int conf;
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 6fcdb6fda2e2..45545be3eb86 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -10,12 +10,15 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
+obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o
obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o
obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
+obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o
obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
+obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o
@@ -50,6 +53,8 @@ obj-$(CONFIG_MIPS_MT) += mips-mt.o
obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
+obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
+obj-$(CONFIG_CPU_MIPSR2) += spram.o
obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
@@ -62,6 +67,7 @@ obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o
obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o
obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o
obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o
+obj-$(CONFIG_IRQ_GIC) += irq-gic.o
obj-$(CONFIG_32BIT) += scall32-o32.o
obj-$(CONFIG_64BIT) += scall64-64.o
@@ -77,6 +83,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o
obj-$(CONFIG_I8253) += i8253.o
+obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
+
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ca136298acdc..5bf03b3c4150 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -17,252 +17,252 @@
#include <asm/ptrace.h>
#include <asm/processor.h>
-#define text(t) __asm__("\n@@@" t)
+#define text(t) __asm__("\n->#" t)
#define _offset(type, member) (&(((type *)NULL)->member))
#define offset(string, ptr, member) \
- __asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
+ __asm__("\n->" string " %0" : : "i" (_offset(ptr, member)))
#define constant(string, member) \
- __asm__("\n@@@" string "%X0" : : "ri" (member))
+ __asm__("\n->" string " %0" : : "ri" (member))
#define size(string, size) \
- __asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
+ __asm__("\n->" string " %0" : : "i" (sizeof(size)))
#define linefeed text("")
void output_ptreg_defines(void)
{
- text("/* MIPS pt_regs offsets. */");
- offset("#define PT_R0 ", struct pt_regs, regs[0]);
- offset("#define PT_R1 ", struct pt_regs, regs[1]);
- offset("#define PT_R2 ", struct pt_regs, regs[2]);
- offset("#define PT_R3 ", struct pt_regs, regs[3]);
- offset("#define PT_R4 ", struct pt_regs, regs[4]);
- offset("#define PT_R5 ", struct pt_regs, regs[5]);
- offset("#define PT_R6 ", struct pt_regs, regs[6]);
- offset("#define PT_R7 ", struct pt_regs, regs[7]);
- offset("#define PT_R8 ", struct pt_regs, regs[8]);
- offset("#define PT_R9 ", struct pt_regs, regs[9]);
- offset("#define PT_R10 ", struct pt_regs, regs[10]);
- offset("#define PT_R11 ", struct pt_regs, regs[11]);
- offset("#define PT_R12 ", struct pt_regs, regs[12]);
- offset("#define PT_R13 ", struct pt_regs, regs[13]);
- offset("#define PT_R14 ", struct pt_regs, regs[14]);
- offset("#define PT_R15 ", struct pt_regs, regs[15]);
- offset("#define PT_R16 ", struct pt_regs, regs[16]);
- offset("#define PT_R17 ", struct pt_regs, regs[17]);
- offset("#define PT_R18 ", struct pt_regs, regs[18]);
- offset("#define PT_R19 ", struct pt_regs, regs[19]);
- offset("#define PT_R20 ", struct pt_regs, regs[20]);
- offset("#define PT_R21 ", struct pt_regs, regs[21]);
- offset("#define PT_R22 ", struct pt_regs, regs[22]);
- offset("#define PT_R23 ", struct pt_regs, regs[23]);
- offset("#define PT_R24 ", struct pt_regs, regs[24]);
- offset("#define PT_R25 ", struct pt_regs, regs[25]);
- offset("#define PT_R26 ", struct pt_regs, regs[26]);
- offset("#define PT_R27 ", struct pt_regs, regs[27]);
- offset("#define PT_R28 ", struct pt_regs, regs[28]);
- offset("#define PT_R29 ", struct pt_regs, regs[29]);
- offset("#define PT_R30 ", struct pt_regs, regs[30]);
- offset("#define PT_R31 ", struct pt_regs, regs[31]);
- offset("#define PT_LO ", struct pt_regs, lo);
- offset("#define PT_HI ", struct pt_regs, hi);
+ text("MIPS pt_regs offsets.");
+ offset("PT_R0", struct pt_regs, regs[0]);
+ offset("PT_R1", struct pt_regs, regs[1]);
+ offset("PT_R2", struct pt_regs, regs[2]);
+ offset("PT_R3", struct pt_regs, regs[3]);
+ offset("PT_R4", struct pt_regs, regs[4]);
+ offset("PT_R5", struct pt_regs, regs[5]);
+ offset("PT_R6", struct pt_regs, regs[6]);
+ offset("PT_R7", struct pt_regs, regs[7]);
+ offset("PT_R8", struct pt_regs, regs[8]);
+ offset("PT_R9", struct pt_regs, regs[9]);
+ offset("PT_R10", struct pt_regs, regs[10]);
+ offset("PT_R11", struct pt_regs, regs[11]);
+ offset("PT_R12", struct pt_regs, regs[12]);
+ offset("PT_R13", struct pt_regs, regs[13]);
+ offset("PT_R14", struct pt_regs, regs[14]);
+ offset("PT_R15", struct pt_regs, regs[15]);
+ offset("PT_R16", struct pt_regs, regs[16]);
+ offset("PT_R17", struct pt_regs, regs[17]);
+ offset("PT_R18", struct pt_regs, regs[18]);
+ offset("PT_R19", struct pt_regs, regs[19]);
+ offset("PT_R20", struct pt_regs, regs[20]);
+ offset("PT_R21", struct pt_regs, regs[21]);
+ offset("PT_R22", struct pt_regs, regs[22]);
+ offset("PT_R23", struct pt_regs, regs[23]);
+ offset("PT_R24", struct pt_regs, regs[24]);
+ offset("PT_R25", struct pt_regs, regs[25]);
+ offset("PT_R26", struct pt_regs, regs[26]);
+ offset("PT_R27", struct pt_regs, regs[27]);
+ offset("PT_R28", struct pt_regs, regs[28]);
+ offset("PT_R29", struct pt_regs, regs[29]);
+ offset("PT_R30", struct pt_regs, regs[30]);
+ offset("PT_R31", struct pt_regs, regs[31]);
+ offset("PT_LO", struct pt_regs, lo);
+ offset("PT_HI", struct pt_regs, hi);
#ifdef CONFIG_CPU_HAS_SMARTMIPS
- offset("#define PT_ACX ", struct pt_regs, acx);
+ offset("PT_ACX", struct pt_regs, acx);
#endif
- offset("#define PT_EPC ", struct pt_regs, cp0_epc);
- offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr);
- offset("#define PT_STATUS ", struct pt_regs, cp0_status);
- offset("#define PT_CAUSE ", struct pt_regs, cp0_cause);
+ offset("PT_EPC", struct pt_regs, cp0_epc);
+ offset("PT_BVADDR", struct pt_regs, cp0_badvaddr);
+ offset("PT_STATUS", struct pt_regs, cp0_status);
+ offset("PT_CAUSE", struct pt_regs, cp0_cause);
#ifdef CONFIG_MIPS_MT_SMTC
- offset("#define PT_TCSTATUS ", struct pt_regs, cp0_tcstatus);
+ offset("PT_TCSTATUS", struct pt_regs, cp0_tcstatus);
#endif /* CONFIG_MIPS_MT_SMTC */
- size("#define PT_SIZE ", struct pt_regs);
+ size("PT_SIZE", struct pt_regs);
linefeed;
}
void output_task_defines(void)
{
- text("/* MIPS task_struct offsets. */");
- offset("#define TASK_STATE ", struct task_struct, state);
- offset("#define TASK_THREAD_INFO ", struct task_struct, stack);
- offset("#define TASK_FLAGS ", struct task_struct, flags);
- offset("#define TASK_MM ", struct task_struct, mm);
- offset("#define TASK_PID ", struct task_struct, pid);
- size( "#define TASK_STRUCT_SIZE ", struct task_struct);
+ text("MIPS task_struct offsets.");
+ offset("TASK_STATE", struct task_struct, state);
+ offset("TASK_THREAD_INFO", struct task_struct, stack);
+ offset("TASK_FLAGS", struct task_struct, flags);
+ offset("TASK_MM", struct task_struct, mm);
+ offset("TASK_PID", struct task_struct, pid);
+ size( "TASK_STRUCT_SIZE", struct task_struct);
linefeed;
}
void output_thread_info_defines(void)
{
- text("/* MIPS thread_info offsets. */");
- offset("#define TI_TASK ", struct thread_info, task);
- offset("#define TI_EXEC_DOMAIN ", struct thread_info, exec_domain);
- offset("#define TI_FLAGS ", struct thread_info, flags);
- offset("#define TI_TP_VALUE ", struct thread_info, tp_value);
- offset("#define TI_CPU ", struct thread_info, cpu);
- offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count);
- offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit);
- offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block);
- offset("#define TI_REGS ", struct thread_info, regs);
- constant("#define _THREAD_SIZE ", THREAD_SIZE);
- constant("#define _THREAD_MASK ", THREAD_MASK);
+ text("MIPS thread_info offsets.");
+ offset("TI_TASK", struct thread_info, task);
+ offset("TI_EXEC_DOMAIN", struct thread_info, exec_domain);
+ offset("TI_FLAGS", struct thread_info, flags);
+ offset("TI_TP_VALUE", struct thread_info, tp_value);
+ offset("TI_CPU", struct thread_info, cpu);
+ offset("TI_PRE_COUNT", struct thread_info, preempt_count);
+ offset("TI_ADDR_LIMIT", struct thread_info, addr_limit);
+ offset("TI_RESTART_BLOCK", struct thread_info, restart_block);
+ offset("TI_REGS", struct thread_info, regs);
+ constant("_THREAD_SIZE", THREAD_SIZE);
+ constant("_THREAD_MASK", THREAD_MASK);
linefeed;
}
void output_thread_defines(void)
{
- text("/* MIPS specific thread_struct offsets. */");
- offset("#define THREAD_REG16 ", struct task_struct, thread.reg16);
- offset("#define THREAD_REG17 ", struct task_struct, thread.reg17);
- offset("#define THREAD_REG18 ", struct task_struct, thread.reg18);
- offset("#define THREAD_REG19 ", struct task_struct, thread.reg19);
- offset("#define THREAD_REG20 ", struct task_struct, thread.reg20);
- offset("#define THREAD_REG21 ", struct task_struct, thread.reg21);
- offset("#define THREAD_REG22 ", struct task_struct, thread.reg22);
- offset("#define THREAD_REG23 ", struct task_struct, thread.reg23);
- offset("#define THREAD_REG29 ", struct task_struct, thread.reg29);
- offset("#define THREAD_REG30 ", struct task_struct, thread.reg30);
- offset("#define THREAD_REG31 ", struct task_struct, thread.reg31);
- offset("#define THREAD_STATUS ", struct task_struct,
+ text("MIPS specific thread_struct offsets.");
+ offset("THREAD_REG16", struct task_struct, thread.reg16);
+ offset("THREAD_REG17", struct task_struct, thread.reg17);
+ offset("THREAD_REG18", struct task_struct, thread.reg18);
+ offset("THREAD_REG19", struct task_struct, thread.reg19);
+ offset("THREAD_REG20", struct task_struct, thread.reg20);
+ offset("THREAD_REG21", struct task_struct, thread.reg21);
+ offset("THREAD_REG22", struct task_struct, thread.reg22);
+ offset("THREAD_REG23", struct task_struct, thread.reg23);
+ offset("THREAD_REG29", struct task_struct, thread.reg29);
+ offset("THREAD_REG30", struct task_struct, thread.reg30);
+ offset("THREAD_REG31", struct task_struct, thread.reg31);
+ offset("THREAD_STATUS", struct task_struct,
thread.cp0_status);
- offset("#define THREAD_FPU ", struct task_struct, thread.fpu);
+ offset("THREAD_FPU", struct task_struct, thread.fpu);
- offset("#define THREAD_BVADDR ", struct task_struct, \
+ offset("THREAD_BVADDR", struct task_struct, \
thread.cp0_badvaddr);
- offset("#define THREAD_BUADDR ", struct task_struct, \
+ offset("THREAD_BUADDR", struct task_struct, \
thread.cp0_baduaddr);
- offset("#define THREAD_ECODE ", struct task_struct, \
+ offset("THREAD_ECODE", struct task_struct, \
thread.error_code);
- offset("#define THREAD_TRAPNO ", struct task_struct, thread.trap_no);
- offset("#define THREAD_TRAMP ", struct task_struct, \
+ offset("THREAD_TRAPNO", struct task_struct, thread.trap_no);
+ offset("THREAD_TRAMP", struct task_struct, \
thread.irix_trampoline);
- offset("#define THREAD_OLDCTX ", struct task_struct, \
+ offset("THREAD_OLDCTX", struct task_struct, \
thread.irix_oldctx);
linefeed;
}
void output_thread_fpu_defines(void)
{
- offset("#define THREAD_FPR0 ",
+ offset("THREAD_FPR0",
struct task_struct, thread.fpu.fpr[0]);
- offset("#define THREAD_FPR1 ",
+ offset("THREAD_FPR1",
struct task_struct, thread.fpu.fpr[1]);
- offset("#define THREAD_FPR2 ",
+ offset("THREAD_FPR2",
struct task_struct, thread.fpu.fpr[2]);
- offset("#define THREAD_FPR3 ",
+ offset("THREAD_FPR3",
struct task_struct, thread.fpu.fpr[3]);
- offset("#define THREAD_FPR4 ",
+ offset("THREAD_FPR4",
struct task_struct, thread.fpu.fpr[4]);
- offset("#define THREAD_FPR5 ",
+ offset("THREAD_FPR5",
struct task_struct, thread.fpu.fpr[5]);
- offset("#define THREAD_FPR6 ",
+ offset("THREAD_FPR6",
struct task_struct, thread.fpu.fpr[6]);
- offset("#define THREAD_FPR7 ",
+ offset("THREAD_FPR7",
struct task_struct, thread.fpu.fpr[7]);
- offset("#define THREAD_FPR8 ",
+ offset("THREAD_FPR8",
struct task_struct, thread.fpu.fpr[8]);
- offset("#define THREAD_FPR9 ",
+ offset("THREAD_FPR9",
struct task_struct, thread.fpu.fpr[9]);
- offset("#define THREAD_FPR10 ",
+ offset("THREAD_FPR10",
struct task_struct, thread.fpu.fpr[10]);
- offset("#define THREAD_FPR11 ",
+ offset("THREAD_FPR11",
struct task_struct, thread.fpu.fpr[11]);
- offset("#define THREAD_FPR12 ",
+ offset("THREAD_FPR12",
struct task_struct, thread.fpu.fpr[12]);
- offset("#define THREAD_FPR13 ",
+ offset("THREAD_FPR13",
struct task_struct, thread.fpu.fpr[13]);
- offset("#define THREAD_FPR14 ",
+ offset("THREAD_FPR14",
struct task_struct, thread.fpu.fpr[14]);
- offset("#define THREAD_FPR15 ",
+ offset("THREAD_FPR15",
struct task_struct, thread.fpu.fpr[15]);
- offset("#define THREAD_FPR16 ",
+ offset("THREAD_FPR16",
struct task_struct, thread.fpu.fpr[16]);
- offset("#define THREAD_FPR17 ",
+ offset("THREAD_FPR17",
struct task_struct, thread.fpu.fpr[17]);
- offset("#define THREAD_FPR18 ",
+ offset("THREAD_FPR18",
struct task_struct, thread.fpu.fpr[18]);
- offset("#define THREAD_FPR19 ",
+ offset("THREAD_FPR19",
struct task_struct, thread.fpu.fpr[19]);
- offset("#define THREAD_FPR20 ",
+ offset("THREAD_FPR20",
struct task_struct, thread.fpu.fpr[20]);
- offset("#define THREAD_FPR21 ",
+ offset("THREAD_FPR21",
struct task_struct, thread.fpu.fpr[21]);
- offset("#define THREAD_FPR22 ",
+ offset("THREAD_FPR22",
struct task_struct, thread.fpu.fpr[22]);
- offset("#define THREAD_FPR23 ",
+ offset("THREAD_FPR23",
struct task_struct, thread.fpu.fpr[23]);
- offset("#define THREAD_FPR24 ",
+ offset("THREAD_FPR24",
struct task_struct, thread.fpu.fpr[24]);
- offset("#define THREAD_FPR25 ",
+ offset("THREAD_FPR25",
struct task_struct, thread.fpu.fpr[25]);
- offset("#define THREAD_FPR26 ",
+ offset("THREAD_FPR26",
struct task_struct, thread.fpu.fpr[26]);
- offset("#define THREAD_FPR27 ",
+ offset("THREAD_FPR27",
struct task_struct, thread.fpu.fpr[27]);
- offset("#define THREAD_FPR28 ",
+ offset("THREAD_FPR28",
struct task_struct, thread.fpu.fpr[28]);
- offset("#define THREAD_FPR29 ",
+ offset("THREAD_FPR29",
struct task_struct, thread.fpu.fpr[29]);
- offset("#define THREAD_FPR30 ",
+ offset("THREAD_FPR30",
struct task_struct, thread.fpu.fpr[30]);
- offset("#define THREAD_FPR31 ",
+ offset("THREAD_FPR31",
struct task_struct, thread.fpu.fpr[31]);
- offset("#define THREAD_FCR31 ",
+ offset("THREAD_FCR31",
struct task_struct, thread.fpu.fcr31);
linefeed;
}
void output_mm_defines(void)
{
- text("/* Size of struct page */");
- size("#define STRUCT_PAGE_SIZE ", struct page);
+ text("Size of struct page");
+ size("STRUCT_PAGE_SIZE", struct page);
linefeed;
- text("/* Linux mm_struct offsets. */");
- offset("#define MM_USERS ", struct mm_struct, mm_users);
- offset("#define MM_PGD ", struct mm_struct, pgd);
- offset("#define MM_CONTEXT ", struct mm_struct, context);
+ text("Linux mm_struct offsets.");
+ offset("MM_USERS", struct mm_struct, mm_users);
+ offset("MM_PGD", struct mm_struct, pgd);
+ offset("MM_CONTEXT", struct mm_struct, context);
linefeed;
- constant("#define _PAGE_SIZE ", PAGE_SIZE);
- constant("#define _PAGE_SHIFT ", PAGE_SHIFT);
+ constant("_PAGE_SIZE", PAGE_SIZE);
+ constant("_PAGE_SHIFT", PAGE_SHIFT);
linefeed;
- constant("#define _PGD_T_SIZE ", sizeof(pgd_t));
- constant("#define _PMD_T_SIZE ", sizeof(pmd_t));
- constant("#define _PTE_T_SIZE ", sizeof(pte_t));
+ constant("_PGD_T_SIZE", sizeof(pgd_t));
+ constant("_PMD_T_SIZE", sizeof(pmd_t));
+ constant("_PTE_T_SIZE", sizeof(pte_t));
linefeed;
- constant("#define _PGD_T_LOG2 ", PGD_T_LOG2);
- constant("#define _PMD_T_LOG2 ", PMD_T_LOG2);
- constant("#define _PTE_T_LOG2 ", PTE_T_LOG2);
+ constant("_PGD_T_LOG2", PGD_T_LOG2);
+ constant("_PMD_T_LOG2", PMD_T_LOG2);
+ constant("_PTE_T_LOG2", PTE_T_LOG2);
linefeed;
- constant("#define _PGD_ORDER ", PGD_ORDER);
- constant("#define _PMD_ORDER ", PMD_ORDER);
- constant("#define _PTE_ORDER ", PTE_ORDER);
+ constant("_PGD_ORDER", PGD_ORDER);
+ constant("_PMD_ORDER", PMD_ORDER);
+ constant("_PTE_ORDER", PTE_ORDER);
linefeed;
- constant("#define _PMD_SHIFT ", PMD_SHIFT);
- constant("#define _PGDIR_SHIFT ", PGDIR_SHIFT);
+ constant("_PMD_SHIFT", PMD_SHIFT);
+ constant("_PGDIR_SHIFT", PGDIR_SHIFT);
linefeed;
- constant("#define _PTRS_PER_PGD ", PTRS_PER_PGD);
- constant("#define _PTRS_PER_PMD ", PTRS_PER_PMD);
- constant("#define _PTRS_PER_PTE ", PTRS_PER_PTE);
+ constant("_PTRS_PER_PGD", PTRS_PER_PGD);
+ constant("_PTRS_PER_PMD", PTRS_PER_PMD);
+ constant("_PTRS_PER_PTE", PTRS_PER_PTE);
linefeed;
}
#ifdef CONFIG_32BIT
void output_sc_defines(void)
{
- text("/* Linux sigcontext offsets. */");
- offset("#define SC_REGS ", struct sigcontext, sc_regs);
- offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs);
- offset("#define SC_ACX ", struct sigcontext, sc_acx);
- offset("#define SC_MDHI ", struct sigcontext, sc_mdhi);
- offset("#define SC_MDLO ", struct sigcontext, sc_mdlo);
- offset("#define SC_PC ", struct sigcontext, sc_pc);
- offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr);
- offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir);
- offset("#define SC_HI1 ", struct sigcontext, sc_hi1);
- offset("#define SC_LO1 ", struct sigcontext, sc_lo1);
- offset("#define SC_HI2 ", struct sigcontext, sc_hi2);
- offset("#define SC_LO2 ", struct sigcontext, sc_lo2);
- offset("#define SC_HI3 ", struct sigcontext, sc_hi3);
- offset("#define SC_LO3 ", struct sigcontext, sc_lo3);
+ text("Linux sigcontext offsets.");
+ offset("SC_REGS", struct sigcontext, sc_regs);
+ offset("SC_FPREGS", struct sigcontext, sc_fpregs);
+ offset("SC_ACX", struct sigcontext, sc_acx);
+ offset("SC_MDHI", struct sigcontext, sc_mdhi);
+ offset("SC_MDLO", struct sigcontext, sc_mdlo);
+ offset("SC_PC", struct sigcontext, sc_pc);
+ offset("SC_FPC_CSR", struct sigcontext, sc_fpc_csr);
+ offset("SC_FPC_EIR", struct sigcontext, sc_fpc_eir);
+ offset("SC_HI1", struct sigcontext, sc_hi1);
+ offset("SC_LO1", struct sigcontext, sc_lo1);
+ offset("SC_HI2", struct sigcontext, sc_hi2);
+ offset("SC_LO2", struct sigcontext, sc_lo2);
+ offset("SC_HI3", struct sigcontext, sc_hi3);
+ offset("SC_LO3", struct sigcontext, sc_lo3);
linefeed;
}
#endif
@@ -270,13 +270,13 @@ void output_sc_defines(void)
#ifdef CONFIG_64BIT
void output_sc_defines(void)
{
- text("/* Linux sigcontext offsets. */");
- offset("#define SC_REGS ", struct sigcontext, sc_regs);
- offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs);
- offset("#define SC_MDHI ", struct sigcontext, sc_mdhi);
- offset("#define SC_MDLO ", struct sigcontext, sc_mdlo);
- offset("#define SC_PC ", struct sigcontext, sc_pc);
- offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr);
+ text("Linux sigcontext offsets.");
+ offset("SC_REGS", struct sigcontext, sc_regs);
+ offset("SC_FPREGS", struct sigcontext, sc_fpregs);
+ offset("SC_MDHI", struct sigcontext, sc_mdhi);
+ offset("SC_MDLO", struct sigcontext, sc_mdlo);
+ offset("SC_PC", struct sigcontext, sc_pc);
+ offset("SC_FPC_CSR", struct sigcontext, sc_fpc_csr);
linefeed;
}
#endif
@@ -284,56 +284,56 @@ void output_sc_defines(void)
#ifdef CONFIG_MIPS32_COMPAT
void output_sc32_defines(void)
{
- text("/* Linux 32-bit sigcontext offsets. */");
- offset("#define SC32_FPREGS ", struct sigcontext32, sc_fpregs);
- offset("#define SC32_FPC_CSR ", struct sigcontext32, sc_fpc_csr);
- offset("#define SC32_FPC_EIR ", struct sigcontext32, sc_fpc_eir);
+ text("Linux 32-bit sigcontext offsets.");
+ offset("SC32_FPREGS", struct sigcontext32, sc_fpregs);
+ offset("SC32_FPC_CSR", struct sigcontext32, sc_fpc_csr);
+ offset("SC32_FPC_EIR", struct sigcontext32, sc_fpc_eir);
linefeed;
}
#endif
void output_signal_defined(void)
{
- text("/* Linux signal numbers. */");
- constant("#define _SIGHUP ", SIGHUP);
- constant("#define _SIGINT ", SIGINT);
- constant("#define _SIGQUIT ", SIGQUIT);
- constant("#define _SIGILL ", SIGILL);
- constant("#define _SIGTRAP ", SIGTRAP);
- constant("#define _SIGIOT ", SIGIOT);
- constant("#define _SIGABRT ", SIGABRT);
- constant("#define _SIGEMT ", SIGEMT);
- constant("#define _SIGFPE ", SIGFPE);
- constant("#define _SIGKILL ", SIGKILL);
- constant("#define _SIGBUS ", SIGBUS);
- constant("#define _SIGSEGV ", SIGSEGV);
- constant("#define _SIGSYS ", SIGSYS);
- constant("#define _SIGPIPE ", SIGPIPE);
- constant("#define _SIGALRM ", SIGALRM);
- constant("#define _SIGTERM ", SIGTERM);
- constant("#define _SIGUSR1 ", SIGUSR1);
- constant("#define _SIGUSR2 ", SIGUSR2);
- constant("#define _SIGCHLD ", SIGCHLD);
- constant("#define _SIGPWR ", SIGPWR);
- constant("#define _SIGWINCH ", SIGWINCH);
- constant("#define _SIGURG ", SIGURG);
- constant("#define _SIGIO ", SIGIO);
- constant("#define _SIGSTOP ", SIGSTOP);
- constant("#define _SIGTSTP ", SIGTSTP);
- constant("#define _SIGCONT ", SIGCONT);
- constant("#define _SIGTTIN ", SIGTTIN);
- constant("#define _SIGTTOU ", SIGTTOU);
- constant("#define _SIGVTALRM ", SIGVTALRM);
- constant("#define _SIGPROF ", SIGPROF);
- constant("#define _SIGXCPU ", SIGXCPU);
- constant("#define _SIGXFSZ ", SIGXFSZ);
+ text("Linux signal numbers.");
+ constant("_SIGHUP", SIGHUP);
+ constant("_SIGINT", SIGINT);
+ constant("_SIGQUIT", SIGQUIT);
+ constant("_SIGILL", SIGILL);
+ constant("_SIGTRAP", SIGTRAP);
+ constant("_SIGIOT", SIGIOT);
+ constant("_SIGABRT", SIGABRT);
+ constant("_SIGEMT", SIGEMT);
+ constant("_SIGFPE", SIGFPE);
+ constant("_SIGKILL", SIGKILL);
+ constant("_SIGBUS", SIGBUS);
+ constant("_SIGSEGV", SIGSEGV);
+ constant("_SIGSYS", SIGSYS);
+ constant("_SIGPIPE", SIGPIPE);
+ constant("_SIGALRM", SIGALRM);
+ constant("_SIGTERM", SIGTERM);
+ constant("_SIGUSR1", SIGUSR1);
+ constant("_SIGUSR2", SIGUSR2);
+ constant("_SIGCHLD", SIGCHLD);
+ constant("_SIGPWR", SIGPWR);
+ constant("_SIGWINCH", SIGWINCH);
+ constant("_SIGURG", SIGURG);
+ constant("_SIGIO", SIGIO);
+ constant("_SIGSTOP", SIGSTOP);
+ constant("_SIGTSTP", SIGTSTP);
+ constant("_SIGCONT", SIGCONT);
+ constant("_SIGTTIN", SIGTTIN);
+ constant("_SIGTTOU", SIGTTOU);
+ constant("_SIGVTALRM", SIGVTALRM);
+ constant("_SIGPROF", SIGPROF);
+ constant("_SIGXCPU", SIGXCPU);
+ constant("_SIGXFSZ", SIGXFSZ);
linefeed;
}
void output_irq_cpustat_t_defines(void)
{
- text("/* Linux irq_cpustat_t offsets. */");
- offset("#define IC_SOFTIRQ_PENDING ", irq_cpustat_t, __softirq_pending);
- size("#define IC_IRQ_CPUSTAT_T ", irq_cpustat_t);
+ text("Linux irq_cpustat_t offsets.");
+ offset("IC_SOFTIRQ_PENDING", irq_cpustat_t, __softirq_pending);
+ size("IC_IRQ_CPUSTAT_T", irq_cpustat_t);
linefeed;
}
diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c
new file mode 100644
index 000000000000..df4acb68bfb5
--- /dev/null
+++ b/arch/mips/kernel/cevt-ds1287.c
@@ -0,0 +1,129 @@
+/*
+ * DS1287 clockevent driver
+ *
+ * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/time.h>
+
+int ds1287_timer_state(void)
+{
+ return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
+}
+
+int ds1287_set_base_clock(unsigned int hz)
+{
+ u8 rate;
+
+ switch (hz) {
+ case 128:
+ rate = 0x9;
+ break;
+ case 256:
+ rate = 0x8;
+ break;
+ case 1024:
+ rate = 0x6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A);
+
+ return 0;
+}
+
+static int ds1287_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ return -EINVAL;
+}
+
+static void ds1287_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ u8 val;
+
+ spin_lock(&rtc_lock);
+
+ val = CMOS_READ(RTC_REG_B);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ val |= RTC_PIE;
+ break;
+ default:
+ val &= ~RTC_PIE;
+ break;
+ }
+
+ CMOS_WRITE(val, RTC_REG_B);
+
+ spin_unlock(&rtc_lock);
+}
+
+static void ds1287_event_handler(struct clock_event_device *dev)
+{
+}
+
+static struct clock_event_device ds1287_clockevent = {
+ .name = "ds1287",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .cpumask = CPU_MASK_CPU0,
+ .set_next_event = ds1287_set_next_event,
+ .set_mode = ds1287_set_mode,
+ .event_handler = ds1287_event_handler,
+};
+
+static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = &ds1287_clockevent;
+
+ /* Ack the RTC interrupt. */
+ CMOS_READ(RTC_REG_C);
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction ds1287_irqaction = {
+ .handler = ds1287_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .name = "ds1287",
+};
+
+int __init ds1287_clockevent_init(int irq)
+{
+ struct clock_event_device *cd;
+
+ cd = &ds1287_clockevent;
+ cd->rating = 100;
+ cd->irq = irq;
+ clockevent_set_clock(cd, 32768);
+ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
+
+ clockevents_register_device(&ds1287_clockevent);
+
+ return setup_irq(irq, &ds1287_irqaction);
+}
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c
index c36772631fe0..6e2f58520afb 100644
--- a/arch/mips/kernel/cevt-gt641xx.c
+++ b/arch/mips/kernel/cevt-gt641xx.c
@@ -25,8 +25,6 @@
#include <asm/gt64120.h>
#include <asm/time.h>
-#include <irq.h>
-
static DEFINE_SPINLOCK(gt641xx_timer_lock);
static unsigned int gt641xx_base_clock;
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 89c3304cb93c..335a6ae3d594 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -169,6 +169,7 @@ static inline void check_wait(void)
case CPU_24K:
case CPU_34K:
+ case CPU_1004K:
cpu_wait = r4k_wait;
if (read_c0_config7() & MIPS_CONF7_WII)
cpu_wait = r4k_wait_irqoff;
@@ -675,6 +676,12 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
return;
}
+#ifdef CONFIG_CPU_MIPSR2
+extern void spram_config(void);
+#else
+static inline void spram_config(void) {}
+#endif
+
static inline void cpu_probe_mips(struct cpuinfo_mips *c)
{
decode_configs(c);
@@ -711,7 +718,12 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
case PRID_IMP_74K:
c->cputype = CPU_74K;
break;
+ case PRID_IMP_1004K:
+ c->cputype = CPU_1004K;
+ break;
}
+
+ spram_config();
}
static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
@@ -778,7 +790,7 @@ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
}
}
-static inline void cpu_probe_philips(struct cpuinfo_mips *c)
+static inline void cpu_probe_nxp(struct cpuinfo_mips *c)
{
decode_configs(c);
switch (c->processor_id & 0xff00) {
@@ -787,7 +799,7 @@ static inline void cpu_probe_philips(struct cpuinfo_mips *c)
c->isa_level = MIPS_CPU_ISA_M32R1;
break;
default:
- panic("Unknown Philips Core!"); /* REVISIT: die? */
+ panic("Unknown NXP Core!"); /* REVISIT: die? */
break;
}
}
@@ -876,6 +888,7 @@ static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c)
case CPU_24K: name = "MIPS 24K"; break;
case CPU_25KF: name = "MIPS 25Kf"; break;
case CPU_34K: name = "MIPS 34K"; break;
+ case CPU_1004K: name = "MIPS 1004K"; break;
case CPU_74K: name = "MIPS 74K"; break;
case CPU_VR4111: name = "NEC VR4111"; break;
case CPU_VR4121: name = "NEC VR4121"; break;
@@ -925,8 +938,8 @@ __cpuinit void cpu_probe(void)
case PRID_COMP_SANDCRAFT:
cpu_probe_sandcraft(c);
break;
- case PRID_COMP_PHILIPS:
- cpu_probe_philips(c);
+ case PRID_COMP_NXP:
+ cpu_probe_nxp(c);
break;
default:
c->cputype = CPU_UNKNOWN;
diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c
new file mode 100644
index 000000000000..1d5f63cf8997
--- /dev/null
+++ b/arch/mips/kernel/csrc-ioasic.c
@@ -0,0 +1,65 @@
+/*
+ * DEC I/O ASIC's counter clocksource
+ *
+ * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/clocksource.h>
+#include <linux/init.h>
+
+#include <asm/ds1287.h>
+#include <asm/time.h>
+#include <asm/dec/ioasic.h>
+#include <asm/dec/ioasic_addrs.h>
+
+static cycle_t dec_ioasic_hpt_read(void)
+{
+ return ioasic_read(IO_REG_FCTR);
+}
+
+static struct clocksource clocksource_dec = {
+ .name = "dec-ioasic",
+ .read = dec_ioasic_hpt_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void __init dec_ioasic_clocksource_init(void)
+{
+ unsigned int freq;
+ u32 start, end;
+ int i = HZ / 10;
+
+
+ while (!ds1287_timer_state())
+ ;
+
+ start = dec_ioasic_hpt_read();
+
+ while (i--)
+ while (!ds1287_timer_state())
+ ;
+
+ end = dec_ioasic_hpt_read();
+
+ freq = (end - start) * 10;
+ printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
+
+ clocksource_dec.rating = 200 + freq / 10000000;
+ clocksource_set_clock(&clocksource_dec, freq);
+
+ clocksource_register(&clocksource_dec);
+}
diff --git a/arch/mips/kernel/gpio_txx9.c b/arch/mips/kernel/gpio_txx9.c
new file mode 100644
index 000000000000..b1436a857998
--- /dev/null
+++ b/arch/mips/kernel/gpio_txx9.c
@@ -0,0 +1,87 @@
+/*
+ * A gpio chip driver for TXx9 SoCs
+ *
+ * Copyright (C) 2008 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * 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/init.h>
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <asm/txx9pio.h>
+
+static DEFINE_SPINLOCK(txx9_gpio_lock);
+
+static struct txx9_pio_reg __iomem *txx9_pioptr;
+
+static int txx9_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ return __raw_readl(&txx9_pioptr->din) & (1 << offset);
+}
+
+static void txx9_gpio_set_raw(unsigned int offset, int value)
+{
+ u32 val;
+ val = __raw_readl(&txx9_pioptr->dout);
+ if (value)
+ val |= 1 << offset;
+ else
+ val &= ~(1 << offset);
+ __raw_writel(val, &txx9_pioptr->dout);
+}
+
+static void txx9_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&txx9_gpio_lock, flags);
+ txx9_gpio_set_raw(offset, value);
+ mmiowb();
+ spin_unlock_irqrestore(&txx9_gpio_lock, flags);
+}
+
+static int txx9_gpio_dir_in(struct gpio_chip *chip, unsigned int offset)
+{
+ spin_lock_irq(&txx9_gpio_lock);
+ __raw_writel(__raw_readl(&txx9_pioptr->dir) & ~(1 << offset),
+ &txx9_pioptr->dir);
+ mmiowb();
+ spin_unlock_irq(&txx9_gpio_lock);
+ return 0;
+}
+
+static int txx9_gpio_dir_out(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ spin_lock_irq(&txx9_gpio_lock);
+ txx9_gpio_set_raw(offset, value);
+ __raw_writel(__raw_readl(&txx9_pioptr->dir) | (1 << offset),
+ &txx9_pioptr->dir);
+ mmiowb();
+ spin_unlock_irq(&txx9_gpio_lock);
+ return 0;
+}
+
+static struct gpio_chip txx9_gpio_chip = {
+ .get = txx9_gpio_get,
+ .set = txx9_gpio_set,
+ .direction_input = txx9_gpio_dir_in,
+ .direction_output = txx9_gpio_dir_out,
+ .label = "TXx9",
+};
+
+int __init txx9_gpio_init(unsigned long baseaddr,
+ unsigned int base, unsigned int num)
+{
+ txx9_pioptr = ioremap(baseaddr, sizeof(struct txx9_pio_reg));
+ if (!txx9_pioptr)
+ return -ENODEV;
+ txx9_gpio_chip.base = base;
+ txx9_gpio_chip.ngpio = num;
+ return gpiochip_add(&txx9_gpio_chip);
+}
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
new file mode 100644
index 000000000000..f0a4bb19e096
--- /dev/null
+++ b/arch/mips/kernel/irq-gic.c
@@ -0,0 +1,295 @@
+#undef DEBUG
+
+#include <linux/bitmap.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/gic.h>
+#include <asm/gcmpregs.h>
+#include <asm/mips-boards/maltaint.h>
+#include <asm/irq.h>
+#include <linux/hardirq.h>
+#include <asm-generic/bitops/find.h>
+
+
+static unsigned long _gic_base;
+static unsigned int _irqbase, _mapsize, numvpes, numintrs;
+static struct gic_intr_map *_intrmap;
+
+static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
+static struct gic_pending_regs pending_regs[NR_CPUS];
+static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
+
+#define gic_wedgeb2bok 0 /*
+ * Can GIC handle b2b writes to wedge register?
+ */
+#if gic_wedgeb2bok == 0
+static DEFINE_SPINLOCK(gic_wedgeb2b_lock);
+#endif
+
+void gic_send_ipi(unsigned int intr)
+{
+#if gic_wedgeb2bok == 0
+ unsigned long flags;
+#endif
+ pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__,
+ read_c0_status());
+ if (!gic_wedgeb2bok)
+ spin_lock_irqsave(&gic_wedgeb2b_lock, flags);
+ GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
+ if (!gic_wedgeb2bok) {
+ (void) GIC_REG(SHARED, GIC_SH_CONFIG);
+ spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags);
+ }
+}
+
+/* This is Malta specific and needs to be exported */
+static void vpe_local_setup(unsigned int numvpes)
+{
+ int i;
+ unsigned long timer_interrupt = 5, perf_interrupt = 5;
+ unsigned int vpe_ctl;
+
+ /*
+ * Setup the default performance counter timer interrupts
+ * for all VPEs
+ */
+ for (i = 0; i < numvpes; i++) {
+ GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+
+ /* Are Interrupts locally routable? */
+ GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
+ if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
+ GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
+ GIC_MAP_TO_PIN_MSK | timer_interrupt);
+
+ if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
+ GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
+ GIC_MAP_TO_PIN_MSK | perf_interrupt);
+ }
+}
+
+unsigned int gic_get_int(void)
+{
+ unsigned int i;
+ unsigned long *pending, *intrmask, *pcpu_mask;
+ unsigned long *pending_abs, *intrmask_abs;
+
+ /* Get per-cpu bitmaps */
+ pending = pending_regs[smp_processor_id()].pending;
+ intrmask = intrmask_regs[smp_processor_id()].intrmask;
+ pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
+
+ pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
+ GIC_SH_PEND_31_0_OFS);
+ intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
+ GIC_SH_MASK_31_0_OFS);
+
+ for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
+ GICREAD(*pending_abs, pending[i]);
+ GICREAD(*intrmask_abs, intrmask[i]);
+ pending_abs++;
+ intrmask_abs++;
+ }
+
+ bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
+ bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
+
+ i = find_first_bit(pending, GIC_NUM_INTRS);
+
+ pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i);
+
+ return i;
+}
+
+static unsigned int gic_irq_startup(unsigned int irq)
+{
+ pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
+ irq -= _irqbase;
+ /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
+ GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
+ 1 << (irq % 32));
+ return 0;
+}
+
+static void gic_irq_ack(unsigned int irq)
+{
+#if gic_wedgeb2bok == 0
+ unsigned long flags;
+#endif
+ pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
+ irq -= _irqbase;
+ GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
+ 1 << (irq % 32));
+
+ if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) {
+ if (!gic_wedgeb2bok)
+ spin_lock_irqsave(&gic_wedgeb2b_lock, flags);
+ GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
+ if (!gic_wedgeb2bok) {
+ (void) GIC_REG(SHARED, GIC_SH_CONFIG);
+ spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags);
+ }
+ }
+}
+
+static void gic_mask_irq(unsigned int irq)
+{
+ pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
+ irq -= _irqbase;
+ /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
+ GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
+ 1 << (irq % 32));
+}
+
+static void gic_unmask_irq(unsigned int irq)
+{
+ pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
+ irq -= _irqbase;
+ /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
+ GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
+ 1 << (irq % 32));
+}
+
+#ifdef CONFIG_SMP
+
+static DEFINE_SPINLOCK(gic_lock);
+
+static void gic_set_affinity(unsigned int irq, cpumask_t cpumask)
+{
+ cpumask_t tmp = CPU_MASK_NONE;
+ unsigned long flags;
+ int i;
+
+ pr_debug(KERN_DEBUG "%s called\n", __func__);
+ irq -= _irqbase;
+
+ cpus_and(tmp, cpumask, cpu_online_map);
+ if (cpus_empty(tmp))
+ return;
+
+ /* Assumption : cpumask refers to a single CPU */
+ spin_lock_irqsave(&gic_lock, flags);
+ for (;;) {
+ /* Re-route this IRQ */
+ GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
+
+ /*
+ * FIXME: assumption that _intrmap is ordered and has no holes
+ */
+
+ /* Update the intr_map */
+ _intrmap[irq].cpunum = first_cpu(tmp);
+
+ /* Update the pcpu_masks */
+ for (i = 0; i < NR_CPUS; i++)
+ clear_bit(irq, pcpu_masks[i].pcpu_mask);
+ set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
+
+ }
+ irq_desc[irq].affinity = cpumask;
+ spin_unlock_irqrestore(&gic_lock, flags);
+
+}
+#endif
+
+static struct irq_chip gic_irq_controller = {
+ .name = "MIPS GIC",
+ .startup = gic_irq_startup,
+ .ack = gic_irq_ack,
+ .mask = gic_mask_irq,
+ .mask_ack = gic_mask_irq,
+ .unmask = gic_unmask_irq,
+ .eoi = gic_unmask_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = gic_set_affinity,
+#endif
+};
+
+static void __init setup_intr(unsigned int intr, unsigned int cpu,
+ unsigned int pin, unsigned int polarity, unsigned int trigtype)
+{
+ /* Setup Intr to Pin mapping */
+ if (pin & GIC_MAP_TO_NMI_MSK) {
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
+ /* FIXME: hack to route NMI to all cpu's */
+ for (cpu = 0; cpu < NR_CPUS; cpu += 32) {
+ GICWRITE(GIC_REG_ADDR(SHARED,
+ GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)),
+ 0xffffffff);
+ }
+ } else {
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
+ GIC_MAP_TO_PIN_MSK | pin);
+ /* Setup Intr to CPU mapping */
+ GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
+ }
+
+ /* Setup Intr Polarity */
+ GIC_SET_POLARITY(intr, polarity);
+
+ /* Setup Intr Trigger Type */
+ GIC_SET_TRIGGER(intr, trigtype);
+
+ /* Init Intr Masks */
+ GIC_SET_INTR_MASK(intr, 0);
+}
+
+static void __init gic_basic_init(void)
+{
+ unsigned int i, cpu;
+
+ /* Setup defaults */
+ for (i = 0; i < GIC_NUM_INTRS; i++) {
+ GIC_SET_POLARITY(i, GIC_POL_POS);
+ GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
+ GIC_SET_INTR_MASK(i, 0);
+ }
+
+ /* Setup specifics */
+ for (i = 0; i < _mapsize; i++) {
+ cpu = _intrmap[i].cpunum;
+ if (cpu == X)
+ continue;
+
+ setup_intr(_intrmap[i].intrnum,
+ _intrmap[i].cpunum,
+ _intrmap[i].pin,
+ _intrmap[i].polarity,
+ _intrmap[i].trigtype);
+ /* Initialise per-cpu Interrupt software masks */
+ if (_intrmap[i].ipiflag)
+ set_bit(_intrmap[i].intrnum, pcpu_masks[cpu].pcpu_mask);
+ }
+
+ vpe_local_setup(numvpes);
+
+ for (i = _irqbase; i < (_irqbase + numintrs); i++)
+ set_irq_chip(i, &gic_irq_controller);
+}
+
+void __init gic_init(unsigned long gic_base_addr,
+ unsigned long gic_addrspace_size,
+ struct gic_intr_map *intr_map, unsigned int intr_map_size,
+ unsigned int irqbase)
+{
+ unsigned int gicconfig;
+
+ _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
+ gic_addrspace_size);
+ _irqbase = irqbase;
+ _intrmap = intr_map;
+ _mapsize = intr_map_size;
+
+ GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
+ numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
+ GIC_SH_CONFIG_NUMINTRS_SHF;
+ numintrs = ((numintrs + 1) * 8);
+
+ numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
+ GIC_SH_CONFIG_NUMVPES_SHF;
+
+ pr_debug("%s called\n", __func__);
+
+ gic_basic_init();
+}
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index 4edc7e451d91..963c16d266ab 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -17,6 +17,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/msc01_ic.h>
+#include <asm/traps.h>
static unsigned long _icctrl_msc;
#define MSC01_IC_REG_BASE _icctrl_msc
@@ -98,14 +99,13 @@ void ll_msc_irq(void)
}
}
-void
-msc_bind_eic_interrupt(unsigned int irq, unsigned int set)
+static void msc_bind_eic_interrupt(int irq, int set)
{
MSCIC_WRITE(MSC01_IC_RAMW,
(irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF));
}
-struct irq_chip msc_levelirq_type = {
+static struct irq_chip msc_levelirq_type = {
.name = "SOC-it-Level",
.ack = level_mask_and_ack_msc_irq,
.mask = mask_msc_irq,
@@ -115,7 +115,7 @@ struct irq_chip msc_levelirq_type = {
.end = end_msc_irq,
};
-struct irq_chip msc_edgeirq_type = {
+static struct irq_chip msc_edgeirq_type = {
.name = "SOC-it-Edge",
.ack = edge_mask_and_ack_msc_irq,
.mask = mask_msc_irq,
@@ -128,8 +128,6 @@ struct irq_chip msc_edgeirq_type = {
void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq)
{
- extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset);
-
_icctrl_msc = (unsigned long) ioremap(icubase, 0x40000);
/* Reset interrupt controller - initialises all registers to 0 */
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
index c0faabd52010..6c8e8c4246f7 100644
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -14,7 +14,7 @@
/* #define DEBUG_SIG */
#ifdef DEBUG_SIG
-# define DEBUGP(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
+# define DEBUGP(fmt, args...) printk("%s: " fmt, __func__, ##args)
#else
# define DEBUGP(fmt, args...)
#endif
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
new file mode 100644
index 000000000000..ca476c4f62a5
--- /dev/null
+++ b/arch/mips/kernel/smp-cmp.c
@@ -0,0 +1,265 @@
+/*
+ * This program is free software; you can distribute 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 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.
+ *
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ * Chris Dearman (chris@mips.com)
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+
+#include <asm/atomic.h>
+#include <asm/cacheflush.h>
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#include <asm/time.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/mips_mt.h>
+
+/*
+ * Crude manipulation of the CPU masks to control which
+ * which CPU's are brought online during initialisation
+ *
+ * Beware... this needs to be called after CPU discovery
+ * but before CPU bringup
+ */
+static int __init allowcpus(char *str)
+{
+ cpumask_t cpu_allow_map;
+ char buf[256];
+ int len;
+
+ cpus_clear(cpu_allow_map);
+ if (cpulist_parse(str, cpu_allow_map) == 0) {
+ cpu_set(0, cpu_allow_map);
+ cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map);
+ len = cpulist_scnprintf(buf, sizeof(buf)-1, cpu_possible_map);
+ buf[len] = '\0';
+ pr_debug("Allowable CPUs: %s\n", buf);
+ return 1;
+ } else
+ return 0;
+}
+__setup("allowcpus=", allowcpus);
+
+static void ipi_call_function(unsigned int cpu)
+{
+ unsigned int action = 0;
+
+ pr_debug("CPU%d: %s cpu %d status %08x\n",
+ smp_processor_id(), __func__, cpu, read_c0_status());
+
+ switch (cpu) {
+ case 0:
+ action = GIC_IPI_EXT_INTR_CALLFNC_VPE0;
+ break;
+ case 1:
+ action = GIC_IPI_EXT_INTR_CALLFNC_VPE1;
+ break;
+ case 2:
+ action = GIC_IPI_EXT_INTR_CALLFNC_VPE2;
+ break;
+ case 3:
+ action = GIC_IPI_EXT_INTR_CALLFNC_VPE3;
+ break;
+ }
+ gic_send_ipi(action);
+}
+
+
+static void ipi_resched(unsigned int cpu)
+{
+ unsigned int action = 0;
+
+ pr_debug("CPU%d: %s cpu %d status %08x\n",
+ smp_processor_id(), __func__, cpu, read_c0_status());
+
+ switch (cpu) {
+ case 0:
+ action = GIC_IPI_EXT_INTR_RESCHED_VPE0;
+ break;
+ case 1:
+ action = GIC_IPI_EXT_INTR_RESCHED_VPE1;
+ break;
+ case 2:
+ action = GIC_IPI_EXT_INTR_RESCHED_VPE2;
+ break;
+ case 3:
+ action = GIC_IPI_EXT_INTR_RESCHED_VPE3;
+ break;
+ }
+ gic_send_ipi(action);
+}
+
+/*
+ * FIXME: This isn't restricted to CMP
+ * The SMVP kernel could use GIC interrupts if available
+ */
+void cmp_send_ipi_single(int cpu, unsigned int action)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ switch (action) {
+ case SMP_CALL_FUNCTION:
+ ipi_call_function(cpu);
+ break;
+
+ case SMP_RESCHEDULE_YOURSELF:
+ ipi_resched(cpu);
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
+static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action)
+{
+ unsigned int i;
+
+ for_each_cpu_mask(i, mask)
+ cmp_send_ipi_single(i, action);
+}
+
+static void cmp_init_secondary(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+
+ /* Assume GIC is present */
+ change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
+ STATUSF_IP7);
+
+ /* Enable per-cpu interrupts: platform specific */
+
+ c->core = (read_c0_ebase() >> 1) & 0xff;
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
+ c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
+#endif
+#ifdef CONFIG_MIPS_MT_SMTC
+ c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
+#endif
+}
+
+static void cmp_smp_finish(void)
+{
+ pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
+
+ /* CDFIXME: remove this? */
+ write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+ if (cpu_has_fpu)
+ cpu_set(smp_processor_id(), mt_fpu_cpumask);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+ local_irq_enable();
+}
+
+static void cmp_cpus_done(void)
+{
+ pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
+}
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it running
+ * smp_bootstrap is the place to resume from
+ * __KSTK_TOS(idle) is apparently the stack pointer
+ * (unsigned long)idle->thread_info the gp
+ */
+static void cmp_boot_secondary(int cpu, struct task_struct *idle)
+{
+ struct thread_info *gp = task_thread_info(idle);
+ unsigned long sp = __KSTK_TOS(idle);
+ unsigned long pc = (unsigned long)&smp_bootstrap;
+ unsigned long a0 = 0;
+
+ pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(),
+ __func__, cpu);
+
+#if 0
+ /* Needed? */
+ flush_icache_range((unsigned long)gp,
+ (unsigned long)(gp + sizeof(struct thread_info)));
+#endif
+
+ amon_cpu_start(cpu, pc, sp, gp, a0);
+}
+
+/*
+ * Common setup before any secondaries are started
+ */
+void __init cmp_smp_setup(void)
+{
+ int i;
+ int ncpu = 0;
+
+ pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+ if (cpu_has_fpu)
+ cpu_set(0, mt_fpu_cpumask);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+ for (i = 1; i < NR_CPUS; i++) {
+ if (amon_cpu_avail(i)) {
+ cpu_set(i, phys_cpu_present_map);
+ __cpu_number_map[i] = ++ncpu;
+ __cpu_logical_map[ncpu] = i;
+ }
+ }
+
+ if (cpu_has_mipsmt) {
+ unsigned int nvpe, mvpconf0 = read_c0_mvpconf0();
+
+ nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
+ smp_num_siblings = nvpe;
+ }
+ pr_info("Detected %i available secondary CPU(s)\n", ncpu);
+}
+
+void __init cmp_prepare_cpus(unsigned int max_cpus)
+{
+ pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
+ smp_processor_id(), __func__, max_cpus);
+
+ /*
+ * FIXME: some of these options are per-system, some per-core and
+ * some per-cpu
+ */
+ mips_mt_set_cpuoptions();
+}
+
+struct plat_smp_ops cmp_smp_ops = {
+ .send_ipi_single = cmp_send_ipi_single,
+ .send_ipi_mask = cmp_send_ipi_mask,
+ .init_secondary = cmp_init_secondary,
+ .smp_finish = cmp_smp_finish,
+ .cpus_done = cmp_cpus_done,
+ .boot_secondary = cmp_boot_secondary,
+ .smp_setup = cmp_smp_setup,
+ .prepare_cpus = cmp_prepare_cpus,
+};
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 89e6f6aa5166..87a1816c1f45 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -36,110 +36,7 @@
#include <asm/mipsmtregs.h>
#include <asm/mips_mt.h>
-#define MIPS_CPU_IPI_RESCHED_IRQ 0
-#define MIPS_CPU_IPI_CALL_IRQ 1
-
-static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
-
-#if 0
-static void dump_mtregisters(int vpe, int tc)
-{
- printk("vpe %d tc %d\n", vpe, tc);
-
- settc(tc);
-
- printk(" c0 status 0x%lx\n", read_vpe_c0_status());
- printk(" vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol());
- printk(" vpeconf0 0x%lx\n", read_vpe_c0_vpeconf0());
- printk(" tcstatus 0x%lx\n", read_tc_c0_tcstatus());
- printk(" tcrestart 0x%lx\n", read_tc_c0_tcrestart());
- printk(" tcbind 0x%lx\n", read_tc_c0_tcbind());
- printk(" tchalt 0x%lx\n", read_tc_c0_tchalt());
-}
-#endif
-
-void __init sanitize_tlb_entries(void)
-{
- int i, tlbsiz;
- unsigned long mvpconf0, ncpu;
-
- if (!cpu_has_mipsmt)
- return;
-
- /* Enable VPC */
- set_c0_mvpcontrol(MVPCONTROL_VPC);
-
- back_to_back_c0_hazard();
-
- /* Disable TLB sharing */
- clear_c0_mvpcontrol(MVPCONTROL_STLB);
-
- mvpconf0 = read_c0_mvpconf0();
-
- printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0,
- (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT,
- (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT);
-
- tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT;
- ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
-
- printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu);
-
- if (tlbsiz > 0) {
- /* share them out across the vpe's */
- tlbsiz /= ncpu;
-
- printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz);
-
- for (i = 0; i < ncpu; i++) {
- settc(i);
-
- if (i == 0)
- write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25));
- else
- write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) |
- (tlbsiz << 25));
- }
- }
-
- clear_c0_mvpcontrol(MVPCONTROL_VPC);
-}
-
-static void ipi_resched_dispatch(void)
-{
- do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
-}
-
-static void ipi_call_dispatch(void)
-{
- do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
-}
-
-static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
-{
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
-{
- smp_call_function_interrupt();
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction irq_resched = {
- .handler = ipi_resched_interrupt,
- .flags = IRQF_DISABLED|IRQF_PERCPU,
- .name = "IPI_resched"
-};
-
-static struct irqaction irq_call = {
- .handler = ipi_call_interrupt,
- .flags = IRQF_DISABLED|IRQF_PERCPU,
- .name = "IPI_call"
-};
-
-static void __init smp_copy_vpe_config(void)
+static void __init smvp_copy_vpe_config(void)
{
write_vpe_c0_status(
(read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
@@ -156,7 +53,7 @@ static void __init smp_copy_vpe_config(void)
write_vpe_c0_count(read_c0_count());
}
-static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
+static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
unsigned int ncpu)
{
if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
@@ -182,12 +79,12 @@ static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
if (tc != 0)
- smp_copy_vpe_config();
+ smvp_copy_vpe_config();
return ncpu;
}
-static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0)
+static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
{
unsigned long tmp;
@@ -254,15 +151,20 @@ static void vsmp_send_ipi_mask(cpumask_t mask, unsigned int action)
static void __cpuinit vsmp_init_secondary(void)
{
- /* Enable per-cpu interrupts */
+ extern int gic_present;
/* This is Malta specific: IPI,performance and timer inetrrupts */
- write_c0_status((read_c0_status() & ~ST0_IM ) |
- (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7));
+ if (gic_present)
+ change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
+ STATUSF_IP6 | STATUSF_IP7);
+ else
+ change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
+ STATUSF_IP6 | STATUSF_IP7);
}
static void __cpuinit vsmp_smp_finish(void)
{
+ /* CDFIXME: remove this? */
write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
#ifdef CONFIG_MIPS_MT_FPAFF
@@ -323,7 +225,7 @@ static void __cpuinit vsmp_boot_secondary(int cpu, struct task_struct *idle)
/*
* Common setup before any secondaries are started
* Make sure all CPU's are in a sensible state before we boot any of the
- * secondarys
+ * secondaries
*/
static void __init vsmp_smp_setup(void)
{
@@ -356,8 +258,8 @@ static void __init vsmp_smp_setup(void)
for (tc = 0; tc <= ntc; tc++) {
settc(tc);
- smp_tc_init(tc, mvpconf0);
- ncpu = smp_vpe_init(tc, mvpconf0, ncpu);
+ smvp_tc_init(tc, mvpconf0);
+ ncpu = smvp_vpe_init(tc, mvpconf0, ncpu);
}
/* Release config state */
@@ -371,21 +273,6 @@ static void __init vsmp_smp_setup(void)
static void __init vsmp_prepare_cpus(unsigned int max_cpus)
{
mips_mt_set_cpuoptions();
-
- /* set up ipi interrupts */
- if (cpu_has_vint) {
- set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
- set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
- }
-
- cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
- cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
-
- setup_irq(cpu_ipi_resched_irq, &irq_resched);
- setup_irq(cpu_ipi_call_irq, &irq_call);
-
- set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
- set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
}
struct plat_smp_ops vsmp_smp_ops = {
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 9d41dab90a80..33780cc61ce9 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -35,6 +35,7 @@
#include <asm/atomic.h>
#include <asm/cpu.h>
#include <asm/processor.h>
+#include <asm/r4k-timer.h>
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/time.h>
@@ -125,6 +126,8 @@ asmlinkage __cpuinit void start_secondary(void)
cpu_set(cpu, cpu_callin_map);
+ synchronise_count_slave();
+
cpu_idle();
}
@@ -287,6 +290,7 @@ void smp_send_stop(void)
void __init smp_cpus_done(unsigned int max_cpus)
{
mp_ops->cpus_done();
+ synchronise_count_master();
}
/* called from main before smp_init() */
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index b42e71c71119..3e863186cd22 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -174,14 +174,6 @@ static int clock_hang_reported[NR_CPUS];
#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */
-/* Initialize shared TLB - the should probably migrate to smtc_setup_cpus() */
-
-void __init sanitize_tlb_entries(void)
-{
- printk("Deprecated sanitize_tlb_entries() invoked\n");
-}
-
-
/*
* Configure shared TLB - VPC configuration bit must be set by caller
*/
@@ -339,7 +331,8 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
/* In general, all TCs should have the same cpu_data indications */
memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
/* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
- if (cpu_data[0].cputype == CPU_34K)
+ if (cpu_data[0].cputype == CPU_34K ||
+ cpu_data[0].cputype == CPU_1004K)
cpu_data[cpu].options &= ~MIPS_CPU_FPU;
cpu_data[cpu].vpe_id = vpe;
cpu_data[cpu].tc_id = tc;
diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c
new file mode 100644
index 000000000000..6ddb507a87ef
--- /dev/null
+++ b/arch/mips/kernel/spram.c
@@ -0,0 +1,221 @@
+/*
+ * MIPS SPRAM support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2007, 2008 MIPS Technologies, Inc.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/stddef.h>
+
+#include <asm/cpu.h>
+#include <asm/fpu.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/r4kcache.h>
+#include <asm/hazards.h>
+
+/*
+ * These definitions are correct for the 24K/34K/74K SPRAM sample
+ * implementation. The 4KS interpreted the tags differently...
+ */
+#define SPRAM_TAG0_ENABLE 0x00000080
+#define SPRAM_TAG0_PA_MASK 0xfffff000
+#define SPRAM_TAG1_SIZE_MASK 0xfffff000
+
+#define SPRAM_TAG_STRIDE 8
+
+#define ERRCTL_SPRAM (1 << 28)
+
+/* errctl access */
+#define read_c0_errctl(x) read_c0_ecc(x)
+#define write_c0_errctl(x) write_c0_ecc(x)
+
+/*
+ * Different semantics to the set_c0_* function built by __BUILD_SET_C0
+ */
+static __cpuinit unsigned int bis_c0_errctl(unsigned int set)
+{
+ unsigned int res;
+ res = read_c0_errctl();
+ write_c0_errctl(res | set);
+ return res;
+}
+
+static __cpuinit void ispram_store_tag(unsigned int offset, unsigned int data)
+{
+ unsigned int errctl;
+
+ /* enable SPRAM tag access */
+ errctl = bis_c0_errctl(ERRCTL_SPRAM);
+ ehb();
+
+ write_c0_taglo(data);
+ ehb();
+
+ cache_op(Index_Store_Tag_I, CKSEG0|offset);
+ ehb();
+
+ write_c0_errctl(errctl);
+ ehb();
+}
+
+
+static __cpuinit unsigned int ispram_load_tag(unsigned int offset)
+{
+ unsigned int data;
+ unsigned int errctl;
+
+ /* enable SPRAM tag access */
+ errctl = bis_c0_errctl(ERRCTL_SPRAM);
+ ehb();
+ cache_op(Index_Load_Tag_I, CKSEG0 | offset);
+ ehb();
+ data = read_c0_taglo();
+ ehb();
+ write_c0_errctl(errctl);
+ ehb();
+
+ return data;
+}
+
+static __cpuinit void dspram_store_tag(unsigned int offset, unsigned int data)
+{
+ unsigned int errctl;
+
+ /* enable SPRAM tag access */
+ errctl = bis_c0_errctl(ERRCTL_SPRAM);
+ ehb();
+ write_c0_dtaglo(data);
+ ehb();
+ cache_op(Index_Store_Tag_D, CKSEG0 | offset);
+ ehb();
+ write_c0_errctl(errctl);
+ ehb();
+}
+
+
+static __cpuinit unsigned int dspram_load_tag(unsigned int offset)
+{
+ unsigned int data;
+ unsigned int errctl;
+
+ errctl = bis_c0_errctl(ERRCTL_SPRAM);
+ ehb();
+ cache_op(Index_Load_Tag_D, CKSEG0 | offset);
+ ehb();
+ data = read_c0_dtaglo();
+ ehb();
+ write_c0_errctl(errctl);
+ ehb();
+
+ return data;
+}
+
+static __cpuinit void probe_spram(char *type,
+ unsigned int base,
+ unsigned int (*read)(unsigned int),
+ void (*write)(unsigned int, unsigned int))
+{
+ unsigned int firstsize = 0, lastsize = 0;
+ unsigned int firstpa = 0, lastpa = 0, pa = 0;
+ unsigned int offset = 0;
+ unsigned int size, tag0, tag1;
+ unsigned int enabled;
+ int i;
+
+ /*
+ * The limit is arbitrary but avoids the loop running away if
+ * the SPRAM tags are implemented differently
+ */
+
+ for (i = 0; i < 8; i++) {
+ tag0 = read(offset);
+ tag1 = read(offset+SPRAM_TAG_STRIDE);
+ pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n",
+ type, i, tag0, tag1);
+
+ size = tag1 & SPRAM_TAG1_SIZE_MASK;
+
+ if (size == 0)
+ break;
+
+ if (i != 0) {
+ /* tags may repeat... */
+ if ((pa == firstpa && size == firstsize) ||
+ (pa == lastpa && size == lastsize))
+ break;
+ }
+
+ /* Align base with size */
+ base = (base + size - 1) & ~(size-1);
+
+ /* reprogram the base address base address and enable */
+ tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE;
+ write(offset, tag0);
+
+ base += size;
+
+ /* reread the tag */
+ tag0 = read(offset);
+ pa = tag0 & SPRAM_TAG0_PA_MASK;
+ enabled = tag0 & SPRAM_TAG0_ENABLE;
+
+ if (i == 0) {
+ firstpa = pa;
+ firstsize = size;
+ }
+
+ lastpa = pa;
+ lastsize = size;
+
+ if (strcmp(type, "DSPRAM") == 0) {
+ unsigned int *vp = (unsigned int *)(CKSEG1 | pa);
+ unsigned int v;
+#define TDAT 0x5a5aa5a5
+ vp[0] = TDAT;
+ vp[1] = ~TDAT;
+
+ mb();
+
+ v = vp[0];
+ if (v != TDAT)
+ printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",
+ vp, TDAT, v);
+ v = vp[1];
+ if (v != ~TDAT)
+ printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",
+ vp+1, ~TDAT, v);
+ }
+
+ pr_info("%s%d: PA=%08x,Size=%08x%s\n",
+ type, i, pa, size, enabled ? ",enabled" : "");
+ offset += 2 * SPRAM_TAG_STRIDE;
+ }
+}
+
+__cpuinit void spram_config(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+ unsigned int config0;
+
+ switch (c->cputype) {
+ case CPU_24K:
+ case CPU_34K:
+ case CPU_74K:
+ config0 = read_c0_config();
+ /* FIXME: addresses are Malta specific */
+ if (config0 & (1<<24)) {
+ probe_spram("ISPRAM", 0x1c000000,
+ &ispram_load_tag, &ispram_store_tag);
+ }
+ if (config0 & (1<<23))
+ probe_spram("DSPRAM", 0x1c100000,
+ &dspram_load_tag, &dspram_store_tag);
+ }
+}
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c
new file mode 100644
index 000000000000..9021108eb9c1
--- /dev/null
+++ b/arch/mips/kernel/sync-r4k.c
@@ -0,0 +1,159 @@
+/*
+ * Count register synchronisation.
+ *
+ * All CPUs will have their count registers synchronised to the CPU0 expirelo
+ * value. This can cause a small timewarp for CPU0. All other CPU's should
+ * not have done anything significant (but they may have had interrupts
+ * enabled briefly - prom_smp_finish() should not be responsible for enabling
+ * interrupts...)
+ *
+ * FIXME: broken for SMTC
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irqflags.h>
+#include <linux/r4k-timer.h>
+
+#include <asm/atomic.h>
+#include <asm/barrier.h>
+#include <asm/cpumask.h>
+#include <asm/mipsregs.h>
+
+static atomic_t __initdata count_start_flag = ATOMIC_INIT(0);
+static atomic_t __initdata count_count_start = ATOMIC_INIT(0);
+static atomic_t __initdata count_count_stop = ATOMIC_INIT(0);
+
+#define COUNTON 100
+#define NR_LOOPS 5
+
+void __init synchronise_count_master(void)
+{
+ int i;
+ unsigned long flags;
+ unsigned int initcount;
+ int nslaves;
+
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC needs to synchronise per VPE, not per CPU
+ * ignore for now
+ */
+ return;
+#endif
+
+ pr_info("Checking COUNT synchronization across %u CPUs: ",
+ num_online_cpus());
+
+ local_irq_save(flags);
+
+ /*
+ * Notify the slaves that it's time to start
+ */
+ atomic_set(&count_start_flag, 1);
+ smp_wmb();
+
+ /* Count will be initialised to expirelo for all CPU's */
+ initcount = expirelo;
+
+ /*
+ * We loop a few times to get a primed instruction cache,
+ * then the last pass is more or less synchronised and
+ * the master and slaves each set their cycle counters to a known
+ * value all at once. This reduces the chance of having random offsets
+ * between the processors, and guarantees that the maximum
+ * delay between the cycle counters is never bigger than
+ * the latency of information-passing (cachelines) between
+ * two CPUs.
+ */
+
+ nslaves = num_online_cpus()-1;
+ for (i = 0; i < NR_LOOPS; i++) {
+ /* slaves loop on '!= ncpus' */
+ while (atomic_read(&count_count_start) != nslaves)
+ mb();
+ atomic_set(&count_count_stop, 0);
+ smp_wmb();
+
+ /* this lets the slaves write their count register */
+ atomic_inc(&count_count_start);
+
+ /*
+ * Everyone initialises count in the last loop:
+ */
+ if (i == NR_LOOPS-1)
+ write_c0_count(initcount);
+
+ /*
+ * Wait for all slaves to leave the synchronization point:
+ */
+ while (atomic_read(&count_count_stop) != nslaves)
+ mb();
+ atomic_set(&count_count_start, 0);
+ smp_wmb();
+ atomic_inc(&count_count_stop);
+ }
+ /* Arrange for an interrupt in a short while */
+ write_c0_compare(read_c0_count() + COUNTON);
+
+ local_irq_restore(flags);
+
+ /*
+ * i386 code reported the skew here, but the
+ * count registers were almost certainly out of sync
+ * so no point in alarming people
+ */
+ printk("done.\n");
+}
+
+void __init synchronise_count_slave(void)
+{
+ int i;
+ unsigned long flags;
+ unsigned int initcount;
+ int ncpus;
+
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC needs to synchronise per VPE, not per CPU
+ * ignore for now
+ */
+ return;
+#endif
+
+ local_irq_save(flags);
+
+ /*
+ * Not every cpu is online at the time this gets called,
+ * so we first wait for the master to say everyone is ready
+ */
+
+ while (!atomic_read(&count_start_flag))
+ mb();
+
+ /* Count will be initialised to expirelo for all CPU's */
+ initcount = expirelo;
+
+ ncpus = num_online_cpus();
+ for (i = 0; i < NR_LOOPS; i++) {
+ atomic_inc(&count_count_start);
+ while (atomic_read(&count_count_start) != ncpus)
+ mb();
+
+ /*
+ * Everyone initialises count in the last loop:
+ */
+ if (i == NR_LOOPS-1)
+ write_c0_count(initcount);
+
+ atomic_inc(&count_count_stop);
+ while (atomic_read(&count_count_stop) != ncpus)
+ mb();
+ }
+ /* Arrange for an interrupt in a short while */
+ write_c0_compare(read_c0_count() + COUNTON);
+
+ local_irq_restore(flags);
+}
+#undef NR_LOOPS
+#endif
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index b45a7093ca2d..1f467d534642 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -38,7 +38,6 @@ int __weak rtc_mips_set_time(unsigned long sec)
{
return 0;
}
-EXPORT_SYMBOL(rtc_mips_set_time);
int __weak rtc_mips_set_mmss(unsigned long nowtime)
{
@@ -50,13 +49,11 @@ int update_persistent_clock(struct timespec now)
return rtc_mips_set_mmss(now.tv_sec);
}
-int null_perf_irq(void)
+static int null_perf_irq(void)
{
return 0;
}
-EXPORT_SYMBOL(null_perf_irq);
-
int (*perf_irq)(void) = null_perf_irq;
EXPORT_SYMBOL(perf_irq);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 984c0d0a7b4d..cb8b0e2c7954 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -22,6 +22,7 @@
#include <linux/kallsyms.h>
#include <linux/bootmem.h>
#include <linux/interrupt.h>
+#include <linux/ptrace.h>
#include <asm/bootinfo.h>
#include <asm/branch.h>
@@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset);
static void show_raw_backtrace(unsigned long reg29)
{
- unsigned long *sp = (unsigned long *)reg29;
+ unsigned long *sp = (unsigned long *)(reg29 & ~3);
unsigned long addr;
printk("Call Trace:");
#ifdef CONFIG_KALLSYMS
printk("\n");
#endif
- while (!kstack_end(sp)) {
- addr = *sp++;
- if (__kernel_text_address(addr))
- print_ip_sym(addr);
+#define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000)
+ if (IS_KVA01(sp)) {
+ while (!kstack_end(sp)) {
+ addr = *sp++;
+ if (__kernel_text_address(addr))
+ print_ip_sym(addr);
+ }
+ printk("\n");
}
- printk("\n");
}
#ifdef CONFIG_KALLSYMS
@@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack);
static void show_code(unsigned int __user *pc)
{
long i;
+ unsigned short __user *pc16 = NULL;
printk("\nCode:");
+ if ((unsigned long)pc & 1)
+ pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
for(i = -3 ; i < 6 ; i++) {
unsigned int insn;
- if (__get_user(insn, pc + i)) {
+ if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
printk(" (Bad address in epc)\n");
break;
}
- printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>'));
+ printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
}
}
@@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs)
void show_registers(const struct pt_regs *regs)
{
+ const int field = 2 * sizeof(unsigned long);
+
__show_regs(regs);
print_modules();
- printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
- current->comm, task_pid_nr(current), current_thread_info(), current);
+ printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n",
+ current->comm, current->pid, current_thread_info(), current,
+ field, current_thread_info()->tp_value);
+ if (cpu_has_userlocal) {
+ unsigned long tls;
+
+ tls = read_c0_userlocal();
+ if (tls != current_thread_info()->tp_value)
+ printk("*HwTLS: %0*lx\n", field, tls);
+ }
+
show_stacktrace(current, regs);
show_code((unsigned int __user *) regs->cp0_epc);
printk("\n");
@@ -657,35 +675,24 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
force_sig_info(SIGFPE, &info, current);
}
-asmlinkage void do_bp(struct pt_regs *regs)
+static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
+ const char *str)
{
- unsigned int opcode, bcode;
siginfo_t info;
-
- if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
- goto out_sigsegv;
-
- /*
- * There is the ancient bug in the MIPS assemblers that the break
- * code starts left to bit 16 instead to bit 6 in the opcode.
- * Gas is bug-compatible, but not always, grrr...
- * We handle both cases with a simple heuristics. --macro
- */
- bcode = ((opcode >> 6) & ((1 << 20) - 1));
- if (bcode < (1 << 10))
- bcode <<= 10;
+ char b[40];
/*
- * (A short test says that IRIX 5.3 sends SIGTRAP for all break
- * insns, even for break codes that indicate arithmetic failures.
- * Weird ...)
+ * A short test says that IRIX 5.3 sends SIGTRAP for all trap
+ * insns, even for trap and break codes that indicate arithmetic
+ * failures. Weird ...
* But should we continue the brokenness??? --macro
*/
- switch (bcode) {
- case BRK_OVERFLOW << 10:
- case BRK_DIVZERO << 10:
- die_if_kernel("Break instruction in kernel code", regs);
- if (bcode == (BRK_DIVZERO << 10))
+ switch (code) {
+ case BRK_OVERFLOW:
+ case BRK_DIVZERO:
+ scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
+ die_if_kernel(b, regs);
+ if (code == BRK_DIVZERO)
info.si_code = FPE_INTDIV;
else
info.si_code = FPE_INTOVF;
@@ -695,12 +702,34 @@ asmlinkage void do_bp(struct pt_regs *regs)
force_sig_info(SIGFPE, &info, current);
break;
case BRK_BUG:
- die("Kernel bug detected", regs);
+ die_if_kernel("Kernel bug detected", regs);
+ force_sig(SIGTRAP, current);
break;
default:
- die_if_kernel("Break instruction in kernel code", regs);
+ scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
+ die_if_kernel(b, regs);
force_sig(SIGTRAP, current);
}
+}
+
+asmlinkage void do_bp(struct pt_regs *regs)
+{
+ unsigned int opcode, bcode;
+
+ if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ goto out_sigsegv;
+
+ /*
+ * There is the ancient bug in the MIPS assemblers that the break
+ * code starts left to bit 16 instead to bit 6 in the opcode.
+ * Gas is bug-compatible, but not always, grrr...
+ * We handle both cases with a simple heuristics. --macro
+ */
+ bcode = ((opcode >> 6) & ((1 << 20) - 1));
+ if (bcode >= (1 << 10))
+ bcode >>= 10;
+
+ do_trap_or_bp(regs, bcode, "Break");
return;
out_sigsegv:
@@ -710,7 +739,6 @@ out_sigsegv:
asmlinkage void do_tr(struct pt_regs *regs)
{
unsigned int opcode, tcode = 0;
- siginfo_t info;
if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
goto out_sigsegv;
@@ -719,32 +747,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
if (!(opcode & OPCODE))
tcode = ((opcode >> 6) & ((1 << 10) - 1));
- /*
- * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
- * insns, even for trap codes that indicate arithmetic failures.
- * Weird ...)
- * But should we continue the brokenness??? --macro
- */
- switch (tcode) {
- case BRK_OVERFLOW:
- case BRK_DIVZERO:
- die_if_kernel("Trap instruction in kernel code", regs);
- if (tcode == BRK_DIVZERO)
- info.si_code = FPE_INTDIV;
- else
- info.si_code = FPE_INTOVF;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_addr = (void __user *) regs->cp0_epc;
- force_sig_info(SIGFPE, &info, current);
- break;
- case BRK_BUG:
- die("Kernel bug detected", regs);
- break;
- default:
- die_if_kernel("Trap instruction in kernel code", regs);
- force_sig(SIGTRAP, current);
- }
+ do_trap_or_bp(regs, tcode, "Trap");
return;
out_sigsegv:
@@ -985,6 +988,21 @@ asmlinkage void do_reserved(struct pt_regs *regs)
(regs->cp0_cause & 0x7f) >> 2);
}
+static int __initdata l1parity = 1;
+static int __init nol1parity(char *s)
+{
+ l1parity = 0;
+ return 1;
+}
+__setup("nol1par", nol1parity);
+static int __initdata l2parity = 1;
+static int __init nol2parity(char *s)
+{
+ l2parity = 0;
+ return 1;
+}
+__setup("nol2par", nol2parity);
+
/*
* Some MIPS CPUs can enable/disable for cache parity detection, but do
* it different ways.
@@ -994,6 +1012,62 @@ static inline void parity_protection_init(void)
switch (current_cpu_type()) {
case CPU_24K:
case CPU_34K:
+ case CPU_74K:
+ case CPU_1004K:
+ {
+#define ERRCTL_PE 0x80000000
+#define ERRCTL_L2P 0x00800000
+ unsigned long errctl;
+ unsigned int l1parity_present, l2parity_present;
+
+ errctl = read_c0_ecc();
+ errctl &= ~(ERRCTL_PE|ERRCTL_L2P);
+
+ /* probe L1 parity support */
+ write_c0_ecc(errctl | ERRCTL_PE);
+ back_to_back_c0_hazard();
+ l1parity_present = (read_c0_ecc() & ERRCTL_PE);
+
+ /* probe L2 parity support */
+ write_c0_ecc(errctl|ERRCTL_L2P);
+ back_to_back_c0_hazard();
+ l2parity_present = (read_c0_ecc() & ERRCTL_L2P);
+
+ if (l1parity_present && l2parity_present) {
+ if (l1parity)
+ errctl |= ERRCTL_PE;
+ if (l1parity ^ l2parity)
+ errctl |= ERRCTL_L2P;
+ } else if (l1parity_present) {
+ if (l1parity)
+ errctl |= ERRCTL_PE;
+ } else if (l2parity_present) {
+ if (l2parity)
+ errctl |= ERRCTL_L2P;
+ } else {
+ /* No parity available */
+ }
+
+ printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl);
+
+ write_c0_ecc(errctl);
+ back_to_back_c0_hazard();
+ errctl = read_c0_ecc();
+ printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl);
+
+ if (l1parity_present)
+ printk(KERN_INFO "Cache parity protection %sabled\n",
+ (errctl & ERRCTL_PE) ? "en" : "dis");
+
+ if (l2parity_present) {
+ if (l1parity_present && l1parity)
+ errctl ^= ERRCTL_L2P;
+ printk(KERN_INFO "L2 cache parity protection %sabled\n",
+ (errctl & ERRCTL_L2P) ? "en" : "dis");
+ }
+ }
+ break;
+
case CPU_5KC:
write_c0_ecc(0x80000000);
back_to_back_c0_hazard();
@@ -1306,6 +1380,17 @@ int cp0_compare_irq;
int cp0_perfcount_irq;
EXPORT_SYMBOL_GPL(cp0_perfcount_irq);
+static int __cpuinitdata noulri;
+
+static int __init ulri_disable(char *s)
+{
+ pr_info("Disabling ulri\n");
+ noulri = 1;
+
+ return 1;
+}
+__setup("noulri", ulri_disable);
+
void __cpuinit per_cpu_trap_init(void)
{
unsigned int cpu = smp_processor_id();
@@ -1342,16 +1427,14 @@ void __cpuinit per_cpu_trap_init(void)
change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
status_set);
-#ifdef CONFIG_CPU_MIPSR2
if (cpu_has_mips_r2) {
unsigned int enable = 0x0000000f;
- if (cpu_has_userlocal)
+ if (!noulri && cpu_has_userlocal)
enable |= (1 << 29);
write_c0_hwrena(enable);
}
-#endif
#ifdef CONFIG_MIPS_MT_SMTC
if (!secondaryTC) {
diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h
index 8977eb585a37..762786538449 100644
--- a/arch/mips/math-emu/ieee754dp.h
+++ b/arch/mips/math-emu/ieee754dp.h
@@ -46,7 +46,7 @@
#define DPDNORMX DPDNORMx(xm, xe)
#define DPDNORMY DPDNORMx(ym, ye)
-static __inline ieee754dp builddp(int s, int bx, u64 m)
+static inline ieee754dp builddp(int s, int bx, u64 m)
{
ieee754dp r;
diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h
index 9917c1e4d947..d9e3586b5bce 100644
--- a/arch/mips/math-emu/ieee754sp.h
+++ b/arch/mips/math-emu/ieee754sp.h
@@ -51,7 +51,7 @@
#define SPDNORMX SPDNORMx(xm, xe)
#define SPDNORMY SPDNORMx(ym, ye)
-static __inline ieee754sp buildsp(int s, int bx, unsigned m)
+static inline ieee754sp buildsp(int s, int bx, unsigned m)
{
ieee754sp r;
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile
index b31d8dfed1be..f7f87fc09d1e 100644
--- a/arch/mips/mips-boards/generic/Makefile
+++ b/arch/mips/mips-boards/generic/Makefile
@@ -20,6 +20,7 @@
obj-y := reset.o display.o init.o memory.o \
cmdline.o time.o
+obj-y += amon.o
obj-$(CONFIG_EARLY_PRINTK) += console.o
obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/mips-boards/generic/amon.c b/arch/mips/mips-boards/generic/amon.c
new file mode 100644
index 000000000000..b7633fda4180
--- /dev/null
+++ b/arch/mips/mips-boards/generic/amon.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+
+ * This program is free software; you can distribute 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 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.
+ *
+ * Arbitrary Monitor interface
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm-mips/addrspace.h>
+#include <asm-mips/mips-boards/launch.h>
+#include <asm-mips/mipsmtregs.h>
+
+int amon_cpu_avail(int cpu)
+{
+ struct cpulaunch *launch = (struct cpulaunch *)KSEG0ADDR(CPULAUNCH);
+
+ if (cpu < 0 || cpu >= NCPULAUNCH) {
+ pr_debug("avail: cpu%d is out of range\n", cpu);
+ return 0;
+ }
+
+ launch += cpu;
+ if (!(launch->flags & LAUNCH_FREADY)) {
+ pr_debug("avail: cpu%d is not ready\n", cpu);
+ return 0;
+ }
+ if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
+ pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
+ return 0;
+ }
+
+ return 1;
+}
+
+void amon_cpu_start(int cpu,
+ unsigned long pc, unsigned long sp,
+ unsigned long gp, unsigned long a0)
+{
+ volatile struct cpulaunch *launch =
+ (struct cpulaunch *)KSEG0ADDR(CPULAUNCH);
+
+ if (!amon_cpu_avail(cpu))
+ return;
+ if (cpu == smp_processor_id()) {
+ pr_debug("launch: I am cpu%d!\n", cpu);
+ return;
+ }
+ launch += cpu;
+
+ pr_debug("launch: starting cpu%d\n", cpu);
+
+ launch->pc = pc;
+ launch->gp = gp;
+ launch->sp = sp;
+ launch->a0 = a0;
+
+ /* Make sure target sees parameters before the go bit */
+ smp_mb();
+
+ launch->flags |= LAUNCH_FGO;
+ while ((launch->flags & LAUNCH_FGONE) == 0)
+ ;
+ pr_debug("launch: cpu%d gone!\n", cpu);
+}
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
index 1695dca5506b..83b9dc739203 100644
--- a/arch/mips/mips-boards/generic/init.c
+++ b/arch/mips/mips-boards/generic/init.c
@@ -226,7 +226,7 @@ void __init kgdb_config(void)
}
#endif
-void __init mips_nmi_setup(void)
+static void __init mips_nmi_setup(void)
{
void *base;
extern char except_vec_nmi;
@@ -238,7 +238,7 @@ void __init mips_nmi_setup(void)
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
-void __init mips_ejtag_setup(void)
+static void __init mips_ejtag_setup(void)
{
void *base;
extern char except_vec_ejtag_debug;
@@ -295,15 +295,21 @@ void __init prom_init(void)
break;
case MIPS_REVISION_CORID_CORE_MSC:
case MIPS_REVISION_CORID_CORE_FPGA2:
- case MIPS_REVISION_CORID_CORE_FPGA3:
- case MIPS_REVISION_CORID_CORE_FPGA4:
case MIPS_REVISION_CORID_CORE_24K:
- case MIPS_REVISION_CORID_CORE_EMUL_MSC:
+ /*
+ * SOCit/ROCit support is essentially identical
+ * but make an attempt to distinguish them
+ */
mips_revision_sconid = MIPS_REVISION_SCON_SOCIT;
break;
+ case MIPS_REVISION_CORID_CORE_FPGA3:
+ case MIPS_REVISION_CORID_CORE_FPGA4:
+ case MIPS_REVISION_CORID_CORE_FPGA5:
+ case MIPS_REVISION_CORID_CORE_EMUL_MSC:
default:
- mips_display_message("CC Error");
- while (1); /* We die here... */
+ /* See above */
+ mips_revision_sconid = MIPS_REVISION_SCON_ROCIT;
+ break;
}
}
@@ -418,6 +424,9 @@ void __init prom_init(void)
#ifdef CONFIG_SERIAL_8250_CONSOLE
console_config();
#endif
+#ifdef CONFIG_MIPS_CMP
+ register_smp_ops(&cmp_smp_ops);
+#endif
#ifdef CONFIG_MIPS_MT_SMP
register_smp_ops(&vsmp_smp_ops);
#endif
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
index dc272c188233..5e443bba5662 100644
--- a/arch/mips/mips-boards/generic/memory.c
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -37,7 +37,7 @@ enum yamon_memtypes {
yamon_prom,
yamon_free,
};
-struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
+static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
#ifdef DEBUG
static char *mtypes[3] = {
@@ -50,7 +50,7 @@ static char *mtypes[3] = {
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
-struct prom_pmemblock * __init prom_getmdesc(void)
+static struct prom_pmemblock * __init prom_getmdesc(void)
{
char *memsize_str;
unsigned int memsize;
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index b50e0fc406ac..008fd82b5840 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -55,16 +55,36 @@
unsigned long cpu_khz;
static int mips_cpu_timer_irq;
+static int mips_cpu_perf_irq;
extern int cp0_perfcount_irq;
+DEFINE_PER_CPU(unsigned int, tickcount);
+#define tickcount_this_cpu __get_cpu_var(tickcount)
+static unsigned long ledbitmask;
+
static void mips_timer_dispatch(void)
{
+#if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS)
+ /*
+ * Yes, this is very tacky, won't work as expected with SMTC and
+ * dyntick will break it,
+ * but it gives me a nice warm feeling during debug
+ */
+#define LEDBAR 0xbf000408
+ if (tickcount_this_cpu++ >= HZ) {
+ tickcount_this_cpu = 0;
+ change_bit(smp_processor_id(), &ledbitmask);
+ smp_wmb(); /* Make sure every one else sees the change */
+ /* This will pick up any recent changes made by other CPU's */
+ *(unsigned int *)LEDBAR = ledbitmask;
+ }
+#endif
do_IRQ(mips_cpu_timer_irq);
}
static void mips_perf_dispatch(void)
{
- do_IRQ(cp0_perfcount_irq);
+ do_IRQ(mips_cpu_perf_irq);
}
/*
@@ -127,21 +147,20 @@ unsigned long read_persistent_clock(void)
return mc146818_get_cmos_time();
}
-void __init plat_perf_setup(void)
+static void __init plat_perf_setup(void)
{
- cp0_perfcount_irq = -1;
-
#ifdef MSC01E_INT_BASE
if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
- cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
+ mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
} else
#endif
if (cp0_perfcount_irq >= 0) {
if (cpu_has_vint)
set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
+ mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
#ifdef CONFIG_SMP
- set_irq_handler(cp0_perfcount_irq, handle_percpu_irq);
+ set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq);
#endif
}
}
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
index 931ca4600a63..8dc6e2ac4c03 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -22,6 +22,7 @@
obj-y := malta_int.o malta_platform.o malta_setup.o
obj-$(CONFIG_MTD) += malta_mtd.o
+# FIXME FIXME FIXME
obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index dbe60eb55e29..8c495104b321 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -31,6 +31,7 @@
#include <linux/kernel.h>
#include <linux/random.h>
+#include <asm/traps.h>
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/irq_regs.h>
@@ -41,6 +42,14 @@
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/msc01_pci.h>
#include <asm/msc01_ic.h>
+#include <asm/gic.h>
+#include <asm/gcmpregs.h>
+
+int gcmp_present = -1;
+int gic_present;
+static unsigned long _msc01_biu_base;
+static unsigned long _gcmp_base;
+static unsigned int ipi_map[NR_CPUS];
static DEFINE_SPINLOCK(mips_irq_lock);
@@ -121,6 +130,17 @@ static void malta_hw0_irqdispatch(void)
do_IRQ(MALTA_INT_BASE + irq);
}
+static void malta_ipi_irqdispatch(void)
+{
+ int irq;
+
+ irq = gic_get_int();
+ if (irq < 0)
+ return; /* interrupt has already been cleared */
+
+ do_IRQ(MIPS_GIC_IRQ_BASE + irq);
+}
+
static void corehi_irqdispatch(void)
{
unsigned int intedge, intsteer, pcicmd, pcibadaddr;
@@ -257,12 +277,61 @@ asmlinkage void plat_irq_dispatch(void)
if (irq == MIPSCPU_INT_I8259A)
malta_hw0_irqdispatch();
+ else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
+ malta_ipi_irqdispatch();
else if (irq >= 0)
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
else
spurious_interrupt();
}
+#ifdef CONFIG_MIPS_MT_SMP
+
+
+#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
+#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
+
+#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
+#define C_RESCHED C_SW0
+#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
+#define C_CALL C_SW1
+static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
+
+static void ipi_resched_dispatch(void)
+{
+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
+}
+
+static void ipi_call_dispatch(void)
+{
+ do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
+}
+
+static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
+{
+ smp_call_function_interrupt();
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction irq_resched = {
+ .handler = ipi_resched_interrupt,
+ .flags = IRQF_DISABLED|IRQF_PERCPU,
+ .name = "IPI_resched"
+};
+
+static struct irqaction irq_call = {
+ .handler = ipi_call_interrupt,
+ .flags = IRQF_DISABLED|IRQF_PERCPU,
+ .name = "IPI_call"
+};
+#endif /* CONFIG_MIPS_MT_SMP */
+
static struct irqaction i8259irq = {
.handler = no_action,
.name = "XT-PIC cascade"
@@ -273,13 +342,13 @@ static struct irqaction corehi_irqaction = {
.name = "CoreHi"
};
-msc_irqmap_t __initdata msc_irqmap[] = {
+static msc_irqmap_t __initdata msc_irqmap[] = {
{MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
{MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
};
-int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
+static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
-msc_irqmap_t __initdata msc_eicirqmap[] = {
+static msc_irqmap_t __initdata msc_eicirqmap[] = {
{MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0},
@@ -291,15 +360,90 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
{MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
};
-int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
+
+static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
+
+/*
+ * This GIC specific tabular array defines the association between External
+ * Interrupts and CPUs/Core Interrupts. The nature of the External
+ * Interrupts is also defined here - polarity/trigger.
+ */
+static struct gic_intr_map gic_intr_map[] = {
+ { GIC_EXT_INTR(0), X, X, X, X, 0 },
+ { GIC_EXT_INTR(1), X, X, X, X, 0 },
+ { GIC_EXT_INTR(2), X, X, X, X, 0 },
+ { GIC_EXT_INTR(3), 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(4), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(5), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(6), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(7), 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(8), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(9), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(10), X, X, X, X, 0 },
+ { GIC_EXT_INTR(11), X, X, X, X, 0 },
+ { GIC_EXT_INTR(12), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(13), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(14), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
+ { GIC_EXT_INTR(15), X, X, X, X, 0 },
+ { GIC_EXT_INTR(16), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(17), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(18), 1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(19), 1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(20), 2, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(21), 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(22), 3, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+ { GIC_EXT_INTR(23), 3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
+};
+
+/*
+ * GCMP needs to be detected before any SMP initialisation
+ */
+int __init gcmp_probe(unsigned long addr, unsigned long size)
+{
+ if (gcmp_present >= 0)
+ return gcmp_present;
+
+ _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
+ _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
+ gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR;
+
+ if (gcmp_present)
+ printk(KERN_DEBUG "GCMP present\n");
+ return gcmp_present;
+}
+
+void __init fill_ipi_map(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) {
+ if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X))
+ ipi_map[gic_intr_map[i].cpunum] |=
+ (1 << (gic_intr_map[i].pin + 2));
+ }
+}
void __init arch_init_irq(void)
{
+ int gic_present, gcmp_present;
+
init_i8259_irqs();
if (!cpu_has_veic)
mips_cpu_irq_init();
+ gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
+ if (gcmp_present) {
+ GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
+ gic_present = 1;
+ } else {
+ _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
+ gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) &
+ MSC01_SC_CFG_GICPRES_MSK) >> MSC01_SC_CFG_GICPRES_SHF;
+ }
+ if (gic_present)
+ printk(KERN_DEBUG "GIC present\n");
+
switch (mips_revision_sconid) {
case MIPS_REVISION_SCON_SOCIT:
case MIPS_REVISION_SCON_ROCIT:
@@ -360,4 +504,206 @@ void __init arch_init_irq(void)
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
&corehi_irqaction);
}
+
+#if defined(CONFIG_MIPS_MT_SMP)
+ if (gic_present) {
+ /* FIXME */
+ int i;
+ struct {
+ unsigned int resched;
+ unsigned int call;
+ } ipiirq[] = {
+ {
+ .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0,
+ .call = GIC_IPI_EXT_INTR_CALLFNC_VPE0},
+ {
+ .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1,
+ .call = GIC_IPI_EXT_INTR_CALLFNC_VPE1
+ }, {
+ .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2,
+ .call = GIC_IPI_EXT_INTR_CALLFNC_VPE2
+ }, {
+ .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3,
+ .call = GIC_IPI_EXT_INTR_CALLFNC_VPE3
+ }
+ };
+#define NIPI (sizeof(ipiirq)/sizeof(ipiirq[0]))
+ fill_ipi_map();
+ gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
+ if (!gcmp_present) {
+ /* Enable the GIC */
+ i = REG(_msc01_biu_base, MSC01_SC_CFG);
+ REG(_msc01_biu_base, MSC01_SC_CFG) =
+ (i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
+ pr_debug("GIC Enabled\n");
+ }
+
+ /* set up ipi interrupts */
+ if (cpu_has_vint) {
+ set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
+ set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
+ }
+ /* Argh.. this really needs sorting out.. */
+ printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status());
+ write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
+ printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
+ write_c0_status(0x1100dc00);
+ printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
+ for (i = 0; i < NIPI; i++) {
+ setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched);
+ setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call);
+
+ set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq);
+ set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq);
+ }
+ } else {
+ /* set up ipi interrupts */
+ if (cpu_has_veic) {
+ set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch);
+ set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch);
+ cpu_ipi_resched_irq = MSC01E_INT_SW0;
+ cpu_ipi_call_irq = MSC01E_INT_SW1;
+ } else {
+ if (cpu_has_vint) {
+ set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
+ set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
+ }
+ cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
+ cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
+ }
+
+ setup_irq(cpu_ipi_resched_irq, &irq_resched);
+ setup_irq(cpu_ipi_call_irq, &irq_call);
+
+ set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
+ set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
+ }
+#endif
+}
+
+void malta_be_init(void)
+{
+ if (gcmp_present) {
+ /* Could change CM error mask register */
+ }
+}
+
+
+static char *tr[8] = {
+ "mem", "gcr", "gic", "mmio",
+ "0x04", "0x05", "0x06", "0x07"
+};
+
+static char *mcmd[32] = {
+ [0x00] = "0x00",
+ [0x01] = "Legacy Write",
+ [0x02] = "Legacy Read",
+ [0x03] = "0x03",
+ [0x04] = "0x04",
+ [0x05] = "0x05",
+ [0x06] = "0x06",
+ [0x07] = "0x07",
+ [0x08] = "Coherent Read Own",
+ [0x09] = "Coherent Read Share",
+ [0x0a] = "Coherent Read Discard",
+ [0x0b] = "Coherent Ready Share Always",
+ [0x0c] = "Coherent Upgrade",
+ [0x0d] = "Coherent Writeback",
+ [0x0e] = "0x0e",
+ [0x0f] = "0x0f",
+ [0x10] = "Coherent Copyback",
+ [0x11] = "Coherent Copyback Invalidate",
+ [0x12] = "Coherent Invalidate",
+ [0x13] = "Coherent Write Invalidate",
+ [0x14] = "Coherent Completion Sync",
+ [0x15] = "0x15",
+ [0x16] = "0x16",
+ [0x17] = "0x17",
+ [0x18] = "0x18",
+ [0x19] = "0x19",
+ [0x1a] = "0x1a",
+ [0x1b] = "0x1b",
+ [0x1c] = "0x1c",
+ [0x1d] = "0x1d",
+ [0x1e] = "0x1e",
+ [0x1f] = "0x1f"
+};
+
+static char *core[8] = {
+ "Invalid/OK", "Invalid/Data",
+ "Shared/OK", "Shared/Data",
+ "Modified/OK", "Modified/Data",
+ "Exclusive/OK", "Exclusive/Data"
+};
+
+static char *causes[32] = {
+ "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR",
+ "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07",
+ "0x08", "0x09", "0x0a", "0x0b",
+ "0x0c", "0x0d", "0x0e", "0x0f",
+ "0x10", "0x11", "0x12", "0x13",
+ "0x14", "0x15", "0x16", "INTVN_WR_ERR",
+ "INTVN_RD_ERR", "0x19", "0x1a", "0x1b",
+ "0x1c", "0x1d", "0x1e", "0x1f"
+};
+
+int malta_be_handler(struct pt_regs *regs, int is_fixup)
+{
+ /* This duplicates the handling in do_be which seems wrong */
+ int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
+
+ if (gcmp_present) {
+ unsigned long cm_error = GCMPGCB(GCMEC);
+ unsigned long cm_addr = GCMPGCB(GCMEA);
+ unsigned long cm_other = GCMPGCB(GCMEO);
+ unsigned long cause, ocause;
+ char buf[256];
+
+ cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK);
+ if (cause != 0) {
+ cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF;
+ if (cause < 16) {
+ unsigned long cca_bits = (cm_error >> 15) & 7;
+ unsigned long tr_bits = (cm_error >> 12) & 7;
+ unsigned long mcmd_bits = (cm_error >> 7) & 0x1f;
+ unsigned long stag_bits = (cm_error >> 3) & 15;
+ unsigned long sport_bits = (cm_error >> 0) & 7;
+
+ snprintf(buf, sizeof(buf),
+ "CCA=%lu TR=%s MCmd=%s STag=%lu "
+ "SPort=%lu\n",
+ cca_bits, tr[tr_bits], mcmd[mcmd_bits],
+ stag_bits, sport_bits);
+ } else {
+ /* glob state & sresp together */
+ unsigned long c3_bits = (cm_error >> 18) & 7;
+ unsigned long c2_bits = (cm_error >> 15) & 7;
+ unsigned long c1_bits = (cm_error >> 12) & 7;
+ unsigned long c0_bits = (cm_error >> 9) & 7;
+ unsigned long sc_bit = (cm_error >> 8) & 1;
+ unsigned long mcmd_bits = (cm_error >> 3) & 0x1f;
+ unsigned long sport_bits = (cm_error >> 0) & 7;
+ snprintf(buf, sizeof(buf),
+ "C3=%s C2=%s C1=%s C0=%s SC=%s "
+ "MCmd=%s SPort=%lu\n",
+ core[c3_bits], core[c2_bits],
+ core[c1_bits], core[c0_bits],
+ sc_bit ? "True" : "False",
+ mcmd[mcmd_bits], sport_bits);
+ }
+
+ ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
+ GCMP_GCB_GMEO_ERROR_2ND_SHF;
+
+ printk("CM_ERROR=%08lx %s <%s>\n", cm_error,
+ causes[cause], buf);
+ printk("CM_ADDR =%08lx\n", cm_addr);
+ printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
+
+ /* reprime cause register */
+ GCMPGCB(GCMEC) = 0;
+ }
+ }
+
+ return retval;
}
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 2cd8f5734b36..e7cad54936ca 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -1,7 +1,7 @@
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
- * Copyright (C) Dmitri Vorobiev
+ * Copyright (C) 2008 Dmitri Vorobiev
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
@@ -36,7 +36,10 @@
#include <linux/console.h>
#endif
-struct resource standard_io_resources[] = {
+extern void malta_be_init(void);
+extern int malta_be_handler(struct pt_regs *regs, int is_fixup);
+
+static struct resource standard_io_resources[] = {
{
.name = "dma1",
.start = 0x00,
@@ -220,4 +223,7 @@ void __init plat_mem_setup(void)
screen_info_setup();
#endif
mips_reboot_setup();
+
+ board_be_init = malta_be_init;
+ board_be_handler = malta_be_handler;
}
diff --git a/arch/mips/mipssim/sim_setup.c b/arch/mips/mipssim/sim_setup.c
index d49fe73426b7..7c7148ef2646 100644
--- a/arch/mips/mipssim/sim_setup.c
+++ b/arch/mips/mipssim/sim_setup.c
@@ -39,9 +39,6 @@
static void __init serial_init(void);
unsigned int _isbonito = 0;
-extern void __init sanitize_tlb_entries(void);
-
-
const char *get_system_type(void)
{
return "MIPSsim";
@@ -55,9 +52,6 @@ void __init plat_mem_setup(void)
pr_info("Linux started...\n");
-#ifdef CONFIG_MIPS_MT_SMP
- sanitize_tlb_entries();
-#endif
}
extern struct plat_smp_ops ssmtc_smp_ops;
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index c6f832e0f41c..48731020ca0e 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -4,30 +4,29 @@
obj-y += cache.o dma-default.o extable.o fault.o \
init.o pgtable.o tlbex.o tlbex-fault.o \
- uasm.o
+ uasm.o page.o
obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
obj-$(CONFIG_64BIT) += pgtable-64.o
obj-$(CONFIG_HIGHMEM) += highmem.o
-obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R10000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R3000) += c-r3k.o tlb-r3k.o pg-r4k.o
-obj-$(CONFIG_CPU_R4300) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R4X00) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R5000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r8k.o
-obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o pg-sb1.o \
- tlb-r4k.o
-obj-$(CONFIG_CPU_TX39XX) += c-tx39.o pg-r4k.o tlb-r3k.o
-obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
+obj-$(CONFIG_CPU_LOONGSON2) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_MIPS32) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_MIPS64) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_NEVADA) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_R10000) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_R3000) += c-r3k.o tlb-r3k.o
+obj-$(CONFIG_CPU_R4300) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_R4X00) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_R5000) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_R5432) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_R8000) += c-r4k.o cex-gen.o tlb-r8k.o
+obj-$(CONFIG_CPU_RM7000) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_RM9000) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_SB1) += c-r4k.o cerr-sb1.o cex-sb1.o tlb-r4k.o
+obj-$(CONFIG_CPU_TX39XX) += c-tx39.o tlb-r3k.o
+obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o
+obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 77aefb4ebedd..643c8bcffff3 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -14,6 +14,7 @@
#include <linux/linkage.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/bitops.h>
#include <asm/bcache.h>
@@ -53,6 +54,12 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
preempt_enable();
}
+#if defined(CONFIG_MIPS_CMP)
+#define cpu_has_safe_index_cacheops 0
+#else
+#define cpu_has_safe_index_cacheops 1
+#endif
+
/*
* Must die.
*/
@@ -481,6 +488,8 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
r4k_blast_dcache_page(addr);
+ if (exec && !cpu_icache_snoops_remote_store)
+ r4k_blast_scache_page(addr);
}
if (exec) {
if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
@@ -583,7 +592,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
* subset property so we have to flush the primary caches
* explicitly
*/
- if (size >= dcache_size) {
+ if (cpu_has_safe_index_cacheops && size >= dcache_size) {
r4k_blast_dcache();
} else {
R4600_HIT_CACHEOP_WAR_IMPL;
@@ -606,7 +615,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
return;
}
- if (size >= dcache_size) {
+ if (cpu_has_safe_index_cacheops && size >= dcache_size) {
r4k_blast_dcache();
} else {
R4600_HIT_CACHEOP_WAR_IMPL;
@@ -968,6 +977,7 @@ static void __cpuinit probe_pcache(void)
case CPU_24K:
case CPU_34K:
case CPU_74K:
+ case CPU_1004K:
if ((read_c0_config7() & (1 << 16))) {
/* effectively physically indexed dcache,
thus no virtual aliases. */
@@ -1216,9 +1226,25 @@ void au1x00_fixup_config_od(void)
}
}
+static int __cpuinitdata cca = -1;
+
+static int __init cca_setup(char *str)
+{
+ get_option(&str, &cca);
+
+ return 1;
+}
+
+__setup("cca=", cca_setup);
+
static void __cpuinit coherency_setup(void)
{
- change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
+ if (cca < 0 || cca > 7)
+ cca = read_c0_config() & CONF_CM_CMASK;
+ _page_cachable_default = cca << _CACHE_SHIFT;
+
+ pr_debug("Using cache attribute %d\n", cca);
+ change_c0_config(CONF_CM_CMASK, cca);
/*
* c0_status.cu=0 specifies that updates by the sc instruction use
@@ -1248,6 +1274,20 @@ static void __cpuinit coherency_setup(void)
}
}
+#if defined(CONFIG_DMA_NONCOHERENT)
+
+static int __cpuinitdata coherentio;
+
+static int __init setcoherentio(char *str)
+{
+ coherentio = 1;
+
+ return 1;
+}
+
+__setup("coherentio", setcoherentio);
+#endif
+
void __cpuinit r4k_cache_init(void)
{
extern void build_clear_page(void);
@@ -1307,14 +1347,22 @@ void __cpuinit r4k_cache_init(void)
flush_data_cache_page = r4k_flush_data_cache_page;
flush_icache_range = r4k_flush_icache_range;
-#ifdef CONFIG_DMA_NONCOHERENT
- _dma_cache_wback_inv = r4k_dma_cache_wback_inv;
- _dma_cache_wback = r4k_dma_cache_wback_inv;
- _dma_cache_inv = r4k_dma_cache_inv;
+#if defined(CONFIG_DMA_NONCOHERENT)
+ if (coherentio) {
+ _dma_cache_wback_inv = (void *)cache_noop;
+ _dma_cache_wback = (void *)cache_noop;
+ _dma_cache_inv = (void *)cache_noop;
+ } else {
+ _dma_cache_wback_inv = r4k_dma_cache_wback_inv;
+ _dma_cache_wback = r4k_dma_cache_wback_inv;
+ _dma_cache_inv = r4k_dma_cache_inv;
+ }
#endif
build_clear_page();
build_copy_page();
+#if !defined(CONFIG_MIPS_CMP)
local_r4k___flush_cache_all(NULL);
+#endif
coherency_setup();
}
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index f5903679ee6a..034e8506f6ea 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -130,8 +130,28 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address,
}
}
-static char cache_panic[] __cpuinitdata =
- "Yeee, unsupported cache architecture.";
+unsigned long _page_cachable_default;
+EXPORT_SYMBOL_GPL(_page_cachable_default);
+
+static inline void setup_protection_map(void)
+{
+ protection_map[0] = PAGE_NONE;
+ protection_map[1] = PAGE_READONLY;
+ protection_map[2] = PAGE_COPY;
+ protection_map[3] = PAGE_COPY;
+ protection_map[4] = PAGE_READONLY;
+ protection_map[5] = PAGE_READONLY;
+ protection_map[6] = PAGE_COPY;
+ protection_map[7] = PAGE_COPY;
+ protection_map[8] = PAGE_NONE;
+ protection_map[9] = PAGE_READONLY;
+ protection_map[10] = PAGE_SHARED;
+ protection_map[11] = PAGE_SHARED;
+ protection_map[12] = PAGE_READONLY;
+ protection_map[13] = PAGE_READONLY;
+ protection_map[14] = PAGE_SHARED;
+ protection_map[15] = PAGE_SHARED;
+}
void __devinit cpu_cache_init(void)
{
@@ -139,34 +159,29 @@ void __devinit cpu_cache_init(void)
extern void __weak r3k_cache_init(void);
r3k_cache_init();
- return;
}
if (cpu_has_6k_cache) {
extern void __weak r6k_cache_init(void);
r6k_cache_init();
- return;
}
if (cpu_has_4k_cache) {
extern void __weak r4k_cache_init(void);
r4k_cache_init();
- return;
}
if (cpu_has_8k_cache) {
extern void __weak r8k_cache_init(void);
r8k_cache_init();
- return;
}
if (cpu_has_tx39_cache) {
extern void __weak tx39_cache_init(void);
tx39_cache_init();
- return;
}
- panic(cache_panic);
+ setup_protection_map();
}
int __weak __uncached_access(struct file *file, unsigned long addr)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index c7aed133d11d..ecd562d2c348 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -142,7 +142,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
#endif
vaddr = __fix_to_virt(FIX_CMAP_END - idx);
pte = mk_pte(page, PAGE_KERNEL);
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
entrylo = pte.pte_high;
#else
entrylo = pte_val(pte) >> 6;
@@ -221,7 +221,7 @@ void copy_user_highpage(struct page *to, struct page *from,
copy_page(vto, vfrom);
kunmap_atomic(vfrom, KM_USER0);
}
- if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+ if ((!cpu_has_ic_fills_f_dc) ||
pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
flush_data_cache_page((unsigned long)vto);
kunmap_atomic(vto, KM_USER1);
@@ -229,8 +229,6 @@ void copy_user_highpage(struct page *to, struct page *from,
smp_wmb();
}
-EXPORT_SYMBOL(copy_user_highpage);
-
void copy_to_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr, void *dst, const void *src,
unsigned long len)
@@ -249,8 +247,6 @@ void copy_to_user_page(struct vm_area_struct *vma,
flush_cache_page(vma, vaddr, page_to_pfn(page));
}
-EXPORT_SYMBOL(copy_to_user_page);
-
void copy_from_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr, void *dst, const void *src,
unsigned long len)
@@ -267,9 +263,6 @@ void copy_from_user_page(struct vm_area_struct *vma,
}
}
-EXPORT_SYMBOL(copy_from_user_page);
-
-
#ifdef CONFIG_HIGHMEM
unsigned long highstart_pfn, highend_pfn;
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
new file mode 100644
index 000000000000..d827d6144369
--- /dev/null
+++ b/arch/mips/mm/page.c
@@ -0,0 +1,684 @@
+/*
+ * 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) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2008 Thiemo Seufer
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+#include <asm/bugs.h>
+#include <asm/cacheops.h>
+#include <asm/inst.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/prefetch.h>
+#include <asm/system.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/mmu_context.h>
+#include <asm/cpu.h>
+#include <asm/war.h>
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_dma.h>
+#endif
+
+#include "uasm.h"
+
+/* Registers used in the assembled routines. */
+#define ZERO 0
+#define AT 2
+#define A0 4
+#define A1 5
+#define A2 6
+#define T0 8
+#define T1 9
+#define T2 10
+#define T3 11
+#define T9 25
+#define RA 31
+
+/* Handle labels (which must be positive integers). */
+enum label_id {
+ label_clear_nopref = 1,
+ label_clear_pref,
+ label_copy_nopref,
+ label_copy_pref_both,
+ label_copy_pref_store,
+};
+
+UASM_L_LA(_clear_nopref)
+UASM_L_LA(_clear_pref)
+UASM_L_LA(_copy_nopref)
+UASM_L_LA(_copy_pref_both)
+UASM_L_LA(_copy_pref_store)
+
+/* We need one branch and therefore one relocation per target label. */
+static struct uasm_label __cpuinitdata labels[5];
+static struct uasm_reloc __cpuinitdata relocs[5];
+
+#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010)
+#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020)
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache: 0x058 bytes
+ * R4600 v1.7: 0x05c bytes
+ * R4600 v2.0: 0x060 bytes
+ * With prefetching, 16 word strides 0x120 bytes
+ */
+
+static u32 clear_page_array[0x120 / 4];
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+void clear_page_cpu(void *page) __attribute__((alias("clear_page_array")));
+#else
+void clear_page(void *page) __attribute__((alias("clear_page_array")));
+#endif
+
+EXPORT_SYMBOL(clear_page);
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache: 0x11c bytes
+ * R4600 v1.7: 0x080 bytes
+ * R4600 v2.0: 0x07c bytes
+ * With prefetching, 16 word strides 0x540 bytes
+ */
+static u32 copy_page_array[0x540 / 4];
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+void
+copy_page_cpu(void *to, void *from) __attribute__((alias("copy_page_array")));
+#else
+void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
+#endif
+
+EXPORT_SYMBOL(copy_page);
+
+
+static int pref_bias_clear_store __cpuinitdata;
+static int pref_bias_copy_load __cpuinitdata;
+static int pref_bias_copy_store __cpuinitdata;
+
+static u32 pref_src_mode __cpuinitdata;
+static u32 pref_dst_mode __cpuinitdata;
+
+static int clear_word_size __cpuinitdata;
+static int copy_word_size __cpuinitdata;
+
+static int half_clear_loop_size __cpuinitdata;
+static int half_copy_loop_size __cpuinitdata;
+
+static int cache_line_size __cpuinitdata;
+#define cache_line_mask() (cache_line_size - 1)
+
+static inline void __cpuinit
+pg_addiu(u32 **buf, unsigned int reg1, unsigned int reg2, unsigned int off)
+{
+ if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) {
+ if (off > 0x7fff) {
+ uasm_i_lui(buf, T9, uasm_rel_hi(off));
+ uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off));
+ } else
+ uasm_i_addiu(buf, T9, ZERO, off);
+ uasm_i_daddu(buf, reg1, reg2, T9);
+ } else {
+ if (off > 0x7fff) {
+ uasm_i_lui(buf, T9, uasm_rel_hi(off));
+ uasm_i_addiu(buf, T9, T9, uasm_rel_lo(off));
+ UASM_i_ADDU(buf, reg1, reg2, T9);
+ } else
+ UASM_i_ADDIU(buf, reg1, reg2, off);
+ }
+}
+
+static void __cpuinit set_prefetch_parameters(void)
+{
+ if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg)
+ clear_word_size = 8;
+ else
+ clear_word_size = 4;
+
+ if (cpu_has_64bit_gp_regs)
+ copy_word_size = 8;
+ else
+ copy_word_size = 4;
+
+ /*
+ * The pref's used here are using "streaming" hints, which cause the
+ * copied data to be kicked out of the cache sooner. A page copy often
+ * ends up copying a lot more data than is commonly used, so this seems
+ * to make sense in terms of reducing cache pollution, but I've no real
+ * performance data to back this up.
+ */
+ if (cpu_has_prefetch) {
+ /*
+ * XXX: Most prefetch bias values in here are based on
+ * guesswork.
+ */
+ cache_line_size = cpu_dcache_line_size();
+ switch (current_cpu_type()) {
+ case CPU_TX49XX:
+ /* TX49 supports only Pref_Load */
+ pref_bias_copy_load = 256;
+ break;
+
+ case CPU_RM9000:
+ /*
+ * As a workaround for erratum G105 which make the
+ * PrepareForStore hint unusable we fall back to
+ * StoreRetained on the RM9000. Once it is known which
+ * versions of the RM9000 we'll be able to condition-
+ * alize this.
+ */
+
+ case CPU_R10000:
+ case CPU_R12000:
+ case CPU_R14000:
+ /*
+ * Those values have been experimentally tuned for an
+ * Origin 200.
+ */
+ pref_bias_clear_store = 512;
+ pref_bias_copy_load = 256;
+ pref_bias_copy_store = 256;
+ pref_src_mode = Pref_LoadStreamed;
+ pref_dst_mode = Pref_StoreStreamed;
+ break;
+
+ case CPU_SB1:
+ case CPU_SB1A:
+ pref_bias_clear_store = 128;
+ pref_bias_copy_load = 128;
+ pref_bias_copy_store = 128;
+ /*
+ * SB1 pass1 Pref_LoadStreamed/Pref_StoreStreamed
+ * hints are broken.
+ */
+ if (current_cpu_type() == CPU_SB1 &&
+ (current_cpu_data.processor_id & 0xff) < 0x02) {
+ pref_src_mode = Pref_Load;
+ pref_dst_mode = Pref_Store;
+ } else {
+ pref_src_mode = Pref_LoadStreamed;
+ pref_dst_mode = Pref_StoreStreamed;
+ }
+ break;
+
+ default:
+ pref_bias_clear_store = 128;
+ pref_bias_copy_load = 256;
+ pref_bias_copy_store = 128;
+ pref_src_mode = Pref_LoadStreamed;
+ pref_dst_mode = Pref_PrepareForStore;
+ break;
+ }
+ } else {
+ if (cpu_has_cache_cdex_s)
+ cache_line_size = cpu_scache_line_size();
+ else if (cpu_has_cache_cdex_p)
+ cache_line_size = cpu_dcache_line_size();
+ }
+ /*
+ * Too much unrolling will overflow the available space in
+ * clear_space_array / copy_page_array. 8 words sounds generous,
+ * but a R4000 with 128 byte L2 line length can exceed even that.
+ */
+ half_clear_loop_size = min(8 * clear_word_size,
+ max(cache_line_size >> 1,
+ 4 * clear_word_size));
+ half_copy_loop_size = min(8 * copy_word_size,
+ max(cache_line_size >> 1,
+ 4 * copy_word_size));
+}
+
+static void __cpuinit build_clear_store(u32 **buf, int off)
+{
+ if (cpu_has_64bit_gp_regs || cpu_has_64bit_zero_reg) {
+ uasm_i_sd(buf, ZERO, off, A0);
+ } else {
+ uasm_i_sw(buf, ZERO, off, A0);
+ }
+}
+
+static inline void __cpuinit build_clear_pref(u32 **buf, int off)
+{
+ if (off & cache_line_mask())
+ return;
+
+ if (pref_bias_clear_store) {
+ uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off,
+ A0);
+ } else if (cpu_has_cache_cdex_s) {
+ uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0);
+ } else if (cpu_has_cache_cdex_p) {
+ if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) {
+ uasm_i_nop(buf);
+ uasm_i_nop(buf);
+ uasm_i_nop(buf);
+ uasm_i_nop(buf);
+ }
+
+ if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
+ uasm_i_lw(buf, ZERO, ZERO, AT);
+
+ uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0);
+ }
+}
+
+void __cpuinit build_clear_page(void)
+{
+ int off;
+ u32 *buf = (u32 *)&clear_page_array;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
+ int i;
+
+ memset(labels, 0, sizeof(labels));
+ memset(relocs, 0, sizeof(relocs));
+
+ set_prefetch_parameters();
+
+ /*
+ * This algorithm makes the following assumptions:
+ * - The prefetch bias is a multiple of 2 words.
+ * - The prefetch bias is less than one page.
+ */
+ BUG_ON(pref_bias_clear_store % (2 * clear_word_size));
+ BUG_ON(PAGE_SIZE < pref_bias_clear_store);
+
+ off = PAGE_SIZE - pref_bias_clear_store;
+ if (off > 0xffff || !pref_bias_clear_store)
+ pg_addiu(&buf, A2, A0, off);
+ else
+ uasm_i_ori(&buf, A2, A0, off);
+
+ if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
+ uasm_i_lui(&buf, AT, 0xa000);
+
+ off = min(8, pref_bias_clear_store / cache_line_size) *
+ cache_line_size;
+ while (off) {
+ build_clear_pref(&buf, -off);
+ off -= cache_line_size;
+ }
+ uasm_l_clear_pref(&l, buf);
+ do {
+ build_clear_pref(&buf, off);
+ build_clear_store(&buf, off);
+ off += clear_word_size;
+ } while (off < half_clear_loop_size);
+ pg_addiu(&buf, A0, A0, 2 * off);
+ off = -off;
+ do {
+ build_clear_pref(&buf, off);
+ if (off == -clear_word_size)
+ uasm_il_bne(&buf, &r, A0, A2, label_clear_pref);
+ build_clear_store(&buf, off);
+ off += clear_word_size;
+ } while (off < 0);
+
+ if (pref_bias_clear_store) {
+ pg_addiu(&buf, A2, A0, pref_bias_clear_store);
+ uasm_l_clear_nopref(&l, buf);
+ off = 0;
+ do {
+ build_clear_store(&buf, off);
+ off += clear_word_size;
+ } while (off < half_clear_loop_size);
+ pg_addiu(&buf, A0, A0, 2 * off);
+ off = -off;
+ do {
+ if (off == -clear_word_size)
+ uasm_il_bne(&buf, &r, A0, A2,
+ label_clear_nopref);
+ build_clear_store(&buf, off);
+ off += clear_word_size;
+ } while (off < 0);
+ }
+
+ uasm_i_jr(&buf, RA);
+ uasm_i_nop(&buf);
+
+ BUG_ON(buf > clear_page_array + ARRAY_SIZE(clear_page_array));
+
+ uasm_resolve_relocs(relocs, labels);
+
+ pr_debug("Synthesized clear page handler (%u instructions).\n",
+ (u32)(buf - clear_page_array));
+
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (buf - clear_page_array); i++)
+ pr_debug("\t.word 0x%08x\n", clear_page_array[i]);
+ pr_debug("\t.set pop\n");
+}
+
+static void __cpuinit build_copy_load(u32 **buf, int reg, int off)
+{
+ if (cpu_has_64bit_gp_regs) {
+ uasm_i_ld(buf, reg, off, A1);
+ } else {
+ uasm_i_lw(buf, reg, off, A1);
+ }
+}
+
+static void __cpuinit build_copy_store(u32 **buf, int reg, int off)
+{
+ if (cpu_has_64bit_gp_regs) {
+ uasm_i_sd(buf, reg, off, A0);
+ } else {
+ uasm_i_sw(buf, reg, off, A0);
+ }
+}
+
+static inline void build_copy_load_pref(u32 **buf, int off)
+{
+ if (off & cache_line_mask())
+ return;
+
+ if (pref_bias_copy_load)
+ uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1);
+}
+
+static inline void build_copy_store_pref(u32 **buf, int off)
+{
+ if (off & cache_line_mask())
+ return;
+
+ if (pref_bias_copy_store) {
+ uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off,
+ A0);
+ } else if (cpu_has_cache_cdex_s) {
+ uasm_i_cache(buf, Create_Dirty_Excl_SD, off, A0);
+ } else if (cpu_has_cache_cdex_p) {
+ if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) {
+ uasm_i_nop(buf);
+ uasm_i_nop(buf);
+ uasm_i_nop(buf);
+ uasm_i_nop(buf);
+ }
+
+ if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
+ uasm_i_lw(buf, ZERO, ZERO, AT);
+
+ uasm_i_cache(buf, Create_Dirty_Excl_D, off, A0);
+ }
+}
+
+void __cpuinit build_copy_page(void)
+{
+ int off;
+ u32 *buf = (u32 *)&copy_page_array;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
+ int i;
+
+ memset(labels, 0, sizeof(labels));
+ memset(relocs, 0, sizeof(relocs));
+
+ set_prefetch_parameters();
+
+ /*
+ * This algorithm makes the following assumptions:
+ * - All prefetch biases are multiples of 8 words.
+ * - The prefetch biases are less than one page.
+ * - The store prefetch bias isn't greater than the load
+ * prefetch bias.
+ */
+ BUG_ON(pref_bias_copy_load % (8 * copy_word_size));
+ BUG_ON(pref_bias_copy_store % (8 * copy_word_size));
+ BUG_ON(PAGE_SIZE < pref_bias_copy_load);
+ BUG_ON(pref_bias_copy_store > pref_bias_copy_load);
+
+ off = PAGE_SIZE - pref_bias_copy_load;
+ if (off > 0xffff || !pref_bias_copy_load)
+ pg_addiu(&buf, A2, A0, off);
+ else
+ uasm_i_ori(&buf, A2, A0, off);
+
+ if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
+ uasm_i_lui(&buf, AT, 0xa000);
+
+ off = min(8, pref_bias_copy_load / cache_line_size) * cache_line_size;
+ while (off) {
+ build_copy_load_pref(&buf, -off);
+ off -= cache_line_size;
+ }
+ off = min(8, pref_bias_copy_store / cache_line_size) * cache_line_size;
+ while (off) {
+ build_copy_store_pref(&buf, -off);
+ off -= cache_line_size;
+ }
+ uasm_l_copy_pref_both(&l, buf);
+ do {
+ build_copy_load_pref(&buf, off);
+ build_copy_load(&buf, T0, off);
+ build_copy_load_pref(&buf, off + copy_word_size);
+ build_copy_load(&buf, T1, off + copy_word_size);
+ build_copy_load_pref(&buf, off + 2 * copy_word_size);
+ build_copy_load(&buf, T2, off + 2 * copy_word_size);
+ build_copy_load_pref(&buf, off + 3 * copy_word_size);
+ build_copy_load(&buf, T3, off + 3 * copy_word_size);
+ build_copy_store_pref(&buf, off);
+ build_copy_store(&buf, T0, off);
+ build_copy_store_pref(&buf, off + copy_word_size);
+ build_copy_store(&buf, T1, off + copy_word_size);
+ build_copy_store_pref(&buf, off + 2 * copy_word_size);
+ build_copy_store(&buf, T2, off + 2 * copy_word_size);
+ build_copy_store_pref(&buf, off + 3 * copy_word_size);
+ build_copy_store(&buf, T3, off + 3 * copy_word_size);
+ off += 4 * copy_word_size;
+ } while (off < half_copy_loop_size);
+ pg_addiu(&buf, A1, A1, 2 * off);
+ pg_addiu(&buf, A0, A0, 2 * off);
+ off = -off;
+ do {
+ build_copy_load_pref(&buf, off);
+ build_copy_load(&buf, T0, off);
+ build_copy_load_pref(&buf, off + copy_word_size);
+ build_copy_load(&buf, T1, off + copy_word_size);
+ build_copy_load_pref(&buf, off + 2 * copy_word_size);
+ build_copy_load(&buf, T2, off + 2 * copy_word_size);
+ build_copy_load_pref(&buf, off + 3 * copy_word_size);
+ build_copy_load(&buf, T3, off + 3 * copy_word_size);
+ build_copy_store_pref(&buf, off);
+ build_copy_store(&buf, T0, off);
+ build_copy_store_pref(&buf, off + copy_word_size);
+ build_copy_store(&buf, T1, off + copy_word_size);
+ build_copy_store_pref(&buf, off + 2 * copy_word_size);
+ build_copy_store(&buf, T2, off + 2 * copy_word_size);
+ build_copy_store_pref(&buf, off + 3 * copy_word_size);
+ if (off == -(4 * copy_word_size))
+ uasm_il_bne(&buf, &r, A2, A0, label_copy_pref_both);
+ build_copy_store(&buf, T3, off + 3 * copy_word_size);
+ off += 4 * copy_word_size;
+ } while (off < 0);
+
+ if (pref_bias_copy_load - pref_bias_copy_store) {
+ pg_addiu(&buf, A2, A0,
+ pref_bias_copy_load - pref_bias_copy_store);
+ uasm_l_copy_pref_store(&l, buf);
+ off = 0;
+ do {
+ build_copy_load(&buf, T0, off);
+ build_copy_load(&buf, T1, off + copy_word_size);
+ build_copy_load(&buf, T2, off + 2 * copy_word_size);
+ build_copy_load(&buf, T3, off + 3 * copy_word_size);
+ build_copy_store_pref(&buf, off);
+ build_copy_store(&buf, T0, off);
+ build_copy_store_pref(&buf, off + copy_word_size);
+ build_copy_store(&buf, T1, off + copy_word_size);
+ build_copy_store_pref(&buf, off + 2 * copy_word_size);
+ build_copy_store(&buf, T2, off + 2 * copy_word_size);
+ build_copy_store_pref(&buf, off + 3 * copy_word_size);
+ build_copy_store(&buf, T3, off + 3 * copy_word_size);
+ off += 4 * copy_word_size;
+ } while (off < half_copy_loop_size);
+ pg_addiu(&buf, A1, A1, 2 * off);
+ pg_addiu(&buf, A0, A0, 2 * off);
+ off = -off;
+ do {
+ build_copy_load(&buf, T0, off);
+ build_copy_load(&buf, T1, off + copy_word_size);
+ build_copy_load(&buf, T2, off + 2 * copy_word_size);
+ build_copy_load(&buf, T3, off + 3 * copy_word_size);
+ build_copy_store_pref(&buf, off);
+ build_copy_store(&buf, T0, off);
+ build_copy_store_pref(&buf, off + copy_word_size);
+ build_copy_store(&buf, T1, off + copy_word_size);
+ build_copy_store_pref(&buf, off + 2 * copy_word_size);
+ build_copy_store(&buf, T2, off + 2 * copy_word_size);
+ build_copy_store_pref(&buf, off + 3 * copy_word_size);
+ if (off == -(4 * copy_word_size))
+ uasm_il_bne(&buf, &r, A2, A0,
+ label_copy_pref_store);
+ build_copy_store(&buf, T3, off + 3 * copy_word_size);
+ off += 4 * copy_word_size;
+ } while (off < 0);
+ }
+
+ if (pref_bias_copy_store) {
+ pg_addiu(&buf, A2, A0, pref_bias_copy_store);
+ uasm_l_copy_nopref(&l, buf);
+ off = 0;
+ do {
+ build_copy_load(&buf, T0, off);
+ build_copy_load(&buf, T1, off + copy_word_size);
+ build_copy_load(&buf, T2, off + 2 * copy_word_size);
+ build_copy_load(&buf, T3, off + 3 * copy_word_size);
+ build_copy_store(&buf, T0, off);
+ build_copy_store(&buf, T1, off + copy_word_size);
+ build_copy_store(&buf, T2, off + 2 * copy_word_size);
+ build_copy_store(&buf, T3, off + 3 * copy_word_size);
+ off += 4 * copy_word_size;
+ } while (off < half_copy_loop_size);
+ pg_addiu(&buf, A1, A1, 2 * off);
+ pg_addiu(&buf, A0, A0, 2 * off);
+ off = -off;
+ do {
+ build_copy_load(&buf, T0, off);
+ build_copy_load(&buf, T1, off + copy_word_size);
+ build_copy_load(&buf, T2, off + 2 * copy_word_size);
+ build_copy_load(&buf, T3, off + 3 * copy_word_size);
+ build_copy_store(&buf, T0, off);
+ build_copy_store(&buf, T1, off + copy_word_size);
+ build_copy_store(&buf, T2, off + 2 * copy_word_size);
+ if (off == -(4 * copy_word_size))
+ uasm_il_bne(&buf, &r, A2, A0,
+ label_copy_nopref);
+ build_copy_store(&buf, T3, off + 3 * copy_word_size);
+ off += 4 * copy_word_size;
+ } while (off < 0);
+ }
+
+ uasm_i_jr(&buf, RA);
+ uasm_i_nop(&buf);
+
+ BUG_ON(buf > copy_page_array + ARRAY_SIZE(copy_page_array));
+
+ uasm_resolve_relocs(relocs, labels);
+
+ pr_debug("Synthesized copy page handler (%u instructions).\n",
+ (u32)(buf - copy_page_array));
+
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < (buf - copy_page_array); i++)
+ pr_debug("\t.word 0x%08x\n", copy_page_array[i]);
+ pr_debug("\t.set pop\n");
+}
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+
+/*
+ * Pad descriptors to cacheline, since each is exclusively owned by a
+ * particular CPU.
+ */
+struct dmadscr {
+ u64 dscr_a;
+ u64 dscr_b;
+ u64 pad_a;
+ u64 pad_b;
+} ____cacheline_aligned_in_smp page_descr[DM_NUM_CHANNELS];
+
+void sb1_dma_init(void)
+{
+ int i;
+
+ for (i = 0; i < DM_NUM_CHANNELS; i++) {
+ const u64 base_val = CPHYSADDR((unsigned long)&page_descr[i]) |
+ V_DM_DSCR_BASE_RINGSZ(1);
+ void *base_reg = IOADDR(A_DM_REGISTER(i, R_DM_DSCR_BASE));
+
+ __raw_writeq(base_val, base_reg);
+ __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg);
+ __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg);
+ }
+}
+
+void clear_page(void *page)
+{
+ u64 to_phys = CPHYSADDR((unsigned long)page);
+ unsigned int cpu = smp_processor_id();
+
+ /* if the page is not in KSEG0, use old way */
+ if ((long)KSEGX((unsigned long)page) != (long)CKSEG0)
+ return clear_page_cpu(page);
+
+ page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM |
+ M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
+ page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
+ __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
+
+ /*
+ * Don't really want to do it this way, but there's no
+ * reliable way to delay completion detection.
+ */
+ while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
+ & M_DM_DSCR_BASE_INTERRUPT))
+ ;
+ __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
+}
+
+void copy_page(void *to, void *from)
+{
+ u64 from_phys = CPHYSADDR((unsigned long)from);
+ u64 to_phys = CPHYSADDR((unsigned long)to);
+ unsigned int cpu = smp_processor_id();
+
+ /* if any page is not in KSEG0, use old way */
+ if ((long)KSEGX((unsigned long)to) != (long)CKSEG0
+ || (long)KSEGX((unsigned long)from) != (long)CKSEG0)
+ return copy_page_cpu(to, from);
+
+ page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST |
+ M_DM_DSCRA_INTERRUPT;
+ page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
+ __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
+
+ /*
+ * Don't really want to do it this way, but there's no
+ * reliable way to delay completion detection.
+ */
+ while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
+ & M_DM_DSCR_BASE_INTERRUPT))
+ ;
+ __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
+}
+
+#endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
diff --git a/arch/mips/mm/pg-r4k.c b/arch/mips/mm/pg-r4k.c
deleted file mode 100644
index 455dedb5b39e..000000000000
--- a/arch/mips/mm/pg-r4k.c
+++ /dev/null
@@ -1,534 +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) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 2007 Maciej W. Rozycki
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-
-#include <asm/bugs.h>
-#include <asm/cacheops.h>
-#include <asm/inst.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/prefetch.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-#include <asm/mipsregs.h>
-#include <asm/mmu_context.h>
-#include <asm/cpu.h>
-#include <asm/war.h>
-
-#define half_scache_line_size() (cpu_scache_line_size() >> 1)
-#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010)
-#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020)
-
-
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache: 0x58 bytes
- * R4600 v1.7: 0x5c bytes
- * R4600 v2.0: 0x60 bytes
- * With prefetching, 16 byte strides 0xa0 bytes
- */
-
-static unsigned int clear_page_array[0x130 / 4];
-
-void clear_page(void * page) __attribute__((alias("clear_page_array")));
-
-EXPORT_SYMBOL(clear_page);
-
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache: 0x11c bytes
- * R4600 v1.7: 0x080 bytes
- * R4600 v2.0: 0x07c bytes
- * With prefetching, 16 byte strides 0x0b8 bytes
- */
-static unsigned int copy_page_array[0x148 / 4];
-
-void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
-
-EXPORT_SYMBOL(copy_page);
-
-/*
- * This is suboptimal for 32-bit kernels; we assume that R10000 is only used
- * with 64-bit kernels. The prefetch offsets have been experimentally tuned
- * an Origin 200.
- */
-static int pref_offset_clear __cpuinitdata = 512;
-static int pref_offset_copy __cpuinitdata = 256;
-
-static unsigned int pref_src_mode __cpuinitdata;
-static unsigned int pref_dst_mode __cpuinitdata;
-
-static int load_offset __cpuinitdata;
-static int store_offset __cpuinitdata;
-
-static unsigned int __cpuinitdata *dest, *epc;
-
-static unsigned int instruction_pending;
-static union mips_instruction delayed_mi;
-
-static void __cpuinit emit_instruction(union mips_instruction mi)
-{
- if (instruction_pending)
- *epc++ = delayed_mi.word;
-
- instruction_pending = 1;
- delayed_mi = mi;
-}
-
-static inline void flush_delay_slot_or_nop(void)
-{
- if (instruction_pending) {
- *epc++ = delayed_mi.word;
- instruction_pending = 0;
- return;
- }
-
- *epc++ = 0;
-}
-
-static inline unsigned int *label(void)
-{
- if (instruction_pending) {
- *epc++ = delayed_mi.word;
- instruction_pending = 0;
- }
-
- return epc;
-}
-
-static inline void build_insn_word(unsigned int word)
-{
- union mips_instruction mi;
-
- mi.word = word;
-
- emit_instruction(mi);
-}
-
-static inline void build_nop(void)
-{
- build_insn_word(0); /* nop */
-}
-
-static inline void build_src_pref(int advance)
-{
- if (!(load_offset & (cpu_dcache_line_size() - 1)) && advance) {
- union mips_instruction mi;
-
- mi.i_format.opcode = pref_op;
- mi.i_format.rs = 5; /* $a1 */
- mi.i_format.rt = pref_src_mode;
- mi.i_format.simmediate = load_offset + advance;
-
- emit_instruction(mi);
- }
-}
-
-static inline void __build_load_reg(int reg)
-{
- union mips_instruction mi;
- unsigned int width;
-
- if (cpu_has_64bit_gp_regs) {
- mi.i_format.opcode = ld_op;
- width = 8;
- } else {
- mi.i_format.opcode = lw_op;
- width = 4;
- }
- mi.i_format.rs = 5; /* $a1 */
- mi.i_format.rt = reg; /* $reg */
- mi.i_format.simmediate = load_offset;
-
- load_offset += width;
- emit_instruction(mi);
-}
-
-static inline void build_load_reg(int reg)
-{
- if (cpu_has_prefetch)
- build_src_pref(pref_offset_copy);
-
- __build_load_reg(reg);
-}
-
-static inline void build_dst_pref(int advance)
-{
- if (!(store_offset & (cpu_dcache_line_size() - 1)) && advance) {
- union mips_instruction mi;
-
- mi.i_format.opcode = pref_op;
- mi.i_format.rs = 4; /* $a0 */
- mi.i_format.rt = pref_dst_mode;
- mi.i_format.simmediate = store_offset + advance;
-
- emit_instruction(mi);
- }
-}
-
-static inline void build_cdex_s(void)
-{
- union mips_instruction mi;
-
- if ((store_offset & (cpu_scache_line_size() - 1)))
- return;
-
- mi.c_format.opcode = cache_op;
- mi.c_format.rs = 4; /* $a0 */
- mi.c_format.c_op = 3; /* Create Dirty Exclusive */
- mi.c_format.cache = 3; /* Secondary Data Cache */
- mi.c_format.simmediate = store_offset;
-
- emit_instruction(mi);
-}
-
-static inline void build_cdex_p(void)
-{
- union mips_instruction mi;
-
- if (store_offset & (cpu_dcache_line_size() - 1))
- return;
-
- if (R4600_V1_HIT_CACHEOP_WAR && cpu_is_r4600_v1_x()) {
- build_nop();
- build_nop();
- build_nop();
- build_nop();
- }
-
- if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
- build_insn_word(0x8c200000); /* lw $zero, ($at) */
-
- mi.c_format.opcode = cache_op;
- mi.c_format.rs = 4; /* $a0 */
- mi.c_format.c_op = 3; /* Create Dirty Exclusive */
- mi.c_format.cache = 1; /* Data Cache */
- mi.c_format.simmediate = store_offset;
-
- emit_instruction(mi);
-}
-
-static void __cpuinit __build_store_reg(int reg)
-{
- union mips_instruction mi;
- unsigned int width;
-
- if (cpu_has_64bit_gp_regs ||
- (cpu_has_64bit_zero_reg && reg == 0)) {
- mi.i_format.opcode = sd_op;
- width = 8;
- } else {
- mi.i_format.opcode = sw_op;
- width = 4;
- }
- mi.i_format.rs = 4; /* $a0 */
- mi.i_format.rt = reg; /* $reg */
- mi.i_format.simmediate = store_offset;
-
- store_offset += width;
- emit_instruction(mi);
-}
-
-static inline void build_store_reg(int reg)
-{
- int pref_off = cpu_has_prefetch ?
- (reg ? pref_offset_copy : pref_offset_clear) : 0;
- if (pref_off)
- build_dst_pref(pref_off);
- else if (cpu_has_cache_cdex_s)
- build_cdex_s();
- else if (cpu_has_cache_cdex_p)
- build_cdex_p();
-
- __build_store_reg(reg);
-}
-
-static inline void build_addiu_rt_rs(unsigned int rt, unsigned int rs,
- unsigned long offset)
-{
- union mips_instruction mi;
-
- BUG_ON(offset > 0x7fff);
-
- if (cpu_has_64bit_gp_regs && DADDI_WAR && r4k_daddiu_bug()) {
- mi.i_format.opcode = addiu_op;
- mi.i_format.rs = 0; /* $zero */
- mi.i_format.rt = 25; /* $t9 */
- mi.i_format.simmediate = offset;
- emit_instruction(mi);
-
- mi.r_format.opcode = spec_op;
- mi.r_format.rs = rs;
- mi.r_format.rt = 25; /* $t9 */
- mi.r_format.rd = rt;
- mi.r_format.re = 0;
- mi.r_format.func = daddu_op;
- } else {
- mi.i_format.opcode = cpu_has_64bit_gp_regs ?
- daddiu_op : addiu_op;
- mi.i_format.rs = rs;
- mi.i_format.rt = rt;
- mi.i_format.simmediate = offset;
- }
- emit_instruction(mi);
-}
-
-static inline void build_addiu_a2_a0(unsigned long offset)
-{
- build_addiu_rt_rs(6, 4, offset); /* $a2, $a0, offset */
-}
-
-static inline void build_addiu_a2(unsigned long offset)
-{
- build_addiu_rt_rs(6, 6, offset); /* $a2, $a2, offset */
-}
-
-static inline void build_addiu_a1(unsigned long offset)
-{
- build_addiu_rt_rs(5, 5, offset); /* $a1, $a1, offset */
-
- load_offset -= offset;
-}
-
-static inline void build_addiu_a0(unsigned long offset)
-{
- build_addiu_rt_rs(4, 4, offset); /* $a0, $a0, offset */
-
- store_offset -= offset;
-}
-
-static inline void build_bne(unsigned int *dest)
-{
- union mips_instruction mi;
-
- mi.i_format.opcode = bne_op;
- mi.i_format.rs = 6; /* $a2 */
- mi.i_format.rt = 4; /* $a0 */
- mi.i_format.simmediate = dest - epc - 1;
-
- *epc++ = mi.word;
- flush_delay_slot_or_nop();
-}
-
-static inline void build_jr_ra(void)
-{
- union mips_instruction mi;
-
- mi.r_format.opcode = spec_op;
- mi.r_format.rs = 31;
- mi.r_format.rt = 0;
- mi.r_format.rd = 0;
- mi.r_format.re = 0;
- mi.r_format.func = jr_op;
-
- *epc++ = mi.word;
- flush_delay_slot_or_nop();
-}
-
-void __cpuinit build_clear_page(void)
-{
- unsigned int loop_start;
- unsigned long off;
- int i;
-
- epc = (unsigned int *) &clear_page_array;
- instruction_pending = 0;
- store_offset = 0;
-
- if (cpu_has_prefetch) {
- switch (current_cpu_type()) {
- case CPU_TX49XX:
- /* TX49 supports only Pref_Load */
- pref_offset_clear = 0;
- pref_offset_copy = 0;
- break;
-
- case CPU_RM9000:
- /*
- * As a workaround for erratum G105 which make the
- * PrepareForStore hint unusable we fall back to
- * StoreRetained on the RM9000. Once it is known which
- * versions of the RM9000 we'll be able to condition-
- * alize this.
- */
-
- case CPU_R10000:
- case CPU_R12000:
- case CPU_R14000:
- pref_src_mode = Pref_LoadStreamed;
- pref_dst_mode = Pref_StoreStreamed;
- break;
-
- default:
- pref_src_mode = Pref_LoadStreamed;
- pref_dst_mode = Pref_PrepareForStore;
- break;
- }
- }
-
- off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_clear : 0);
- if (off > 0x7fff) {
- build_addiu_a2_a0(off >> 1);
- build_addiu_a2(off >> 1);
- } else
- build_addiu_a2_a0(off);
-
- if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
- build_insn_word(0x3c01a000); /* lui $at, 0xa000 */
-
-dest = label();
- do {
- build_store_reg(0);
- build_store_reg(0);
- build_store_reg(0);
- build_store_reg(0);
- } while (store_offset < half_scache_line_size());
- build_addiu_a0(2 * store_offset);
- loop_start = store_offset;
- do {
- build_store_reg(0);
- build_store_reg(0);
- build_store_reg(0);
- build_store_reg(0);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_bne(dest);
-
- if (cpu_has_prefetch && pref_offset_clear) {
- build_addiu_a2_a0(pref_offset_clear);
- dest = label();
- loop_start = store_offset;
- do {
- __build_store_reg(0);
- __build_store_reg(0);
- __build_store_reg(0);
- __build_store_reg(0);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_addiu_a0(2 * store_offset);
- loop_start = store_offset;
- do {
- __build_store_reg(0);
- __build_store_reg(0);
- __build_store_reg(0);
- __build_store_reg(0);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_bne(dest);
- }
-
- build_jr_ra();
-
- BUG_ON(epc > clear_page_array + ARRAY_SIZE(clear_page_array));
-
- pr_info("Synthesized clear page handler (%u instructions).\n",
- (unsigned int)(epc - clear_page_array));
-
- pr_debug("\t.set push\n");
- pr_debug("\t.set noreorder\n");
- for (i = 0; i < (epc - clear_page_array); i++)
- pr_debug("\t.word 0x%08x\n", clear_page_array[i]);
- pr_debug("\t.set pop\n");
-}
-
-void __cpuinit build_copy_page(void)
-{
- unsigned int loop_start;
- unsigned long off;
- int i;
-
- epc = (unsigned int *) &copy_page_array;
- store_offset = load_offset = 0;
- instruction_pending = 0;
-
- off = PAGE_SIZE - (cpu_has_prefetch ? pref_offset_copy : 0);
- if (off > 0x7fff) {
- build_addiu_a2_a0(off >> 1);
- build_addiu_a2(off >> 1);
- } else
- build_addiu_a2_a0(off);
-
- if (R4600_V2_HIT_CACHEOP_WAR && cpu_is_r4600_v2_x())
- build_insn_word(0x3c01a000); /* lui $at, 0xa000 */
-
-dest = label();
- loop_start = store_offset;
- do {
- build_load_reg( 8);
- build_load_reg( 9);
- build_load_reg(10);
- build_load_reg(11);
- build_store_reg( 8);
- build_store_reg( 9);
- build_store_reg(10);
- build_store_reg(11);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_addiu_a0(2 * store_offset);
- build_addiu_a1(2 * load_offset);
- loop_start = store_offset;
- do {
- build_load_reg( 8);
- build_load_reg( 9);
- build_load_reg(10);
- build_load_reg(11);
- build_store_reg( 8);
- build_store_reg( 9);
- build_store_reg(10);
- build_store_reg(11);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_bne(dest);
-
- if (cpu_has_prefetch && pref_offset_copy) {
- build_addiu_a2_a0(pref_offset_copy);
- dest = label();
- loop_start = store_offset;
- do {
- __build_load_reg( 8);
- __build_load_reg( 9);
- __build_load_reg(10);
- __build_load_reg(11);
- __build_store_reg( 8);
- __build_store_reg( 9);
- __build_store_reg(10);
- __build_store_reg(11);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_addiu_a0(2 * store_offset);
- build_addiu_a1(2 * load_offset);
- loop_start = store_offset;
- do {
- __build_load_reg( 8);
- __build_load_reg( 9);
- __build_load_reg(10);
- __build_load_reg(11);
- __build_store_reg( 8);
- __build_store_reg( 9);
- __build_store_reg(10);
- __build_store_reg(11);
- } while ((store_offset - loop_start) < half_scache_line_size());
- build_bne(dest);
- }
-
- build_jr_ra();
-
- BUG_ON(epc > copy_page_array + ARRAY_SIZE(copy_page_array));
-
- pr_info("Synthesized copy page handler (%u instructions).\n",
- (unsigned int)(epc - copy_page_array));
-
- pr_debug("\t.set push\n");
- pr_debug("\t.set noreorder\n");
- for (i = 0; i < (epc - copy_page_array); i++)
- pr_debug("\t.word 0x%08x\n", copy_page_array[i]);
- pr_debug("\t.set pop\n");
-}
diff --git a/arch/mips/mm/pg-sb1.c b/arch/mips/mm/pg-sb1.c
deleted file mode 100644
index 49e289d05414..000000000000
--- a/arch/mips/mm/pg-sb1.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 2000 SiByte, Inc.
- * Copyright (C) 2005 Thiemo Seufer
- *
- * Written by Justin Carlson of SiByte, Inc.
- * and Kip Walker of Broadcom Corp.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-
-#include <asm/io.h>
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_dma.h>
-
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-#define SB1_PREF_LOAD_STREAMED_HINT "0"
-#define SB1_PREF_STORE_STREAMED_HINT "1"
-#else
-#define SB1_PREF_LOAD_STREAMED_HINT "4"
-#define SB1_PREF_STORE_STREAMED_HINT "5"
-#endif
-
-static inline void clear_page_cpu(void *page)
-{
- unsigned char *addr = (unsigned char *) page;
- unsigned char *end = addr + PAGE_SIZE;
-
- /*
- * JDCXXX - This should be bottlenecked by the write buffer, but these
- * things tend to be mildly unpredictable...should check this on the
- * performance model
- *
- * We prefetch 4 lines ahead. We're also "cheating" slightly here...
- * since we know we're on an SB1, we force the assembler to take
- * 64-bit operands to speed things up
- */
- __asm__ __volatile__(
- " .set push \n"
- " .set mips4 \n"
- " .set noreorder \n"
-#ifdef CONFIG_CPU_HAS_PREFETCH
- " daddiu %0, %0, 128 \n"
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%0) \n"
- /* Prefetch the first 4 lines */
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%0) \n"
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%0) \n"
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n"
- "1: sd $0, -128(%0) \n" /* Throw out a cacheline of 0's */
- " sd $0, -120(%0) \n"
- " sd $0, -112(%0) \n"
- " sd $0, -104(%0) \n"
- " daddiu %0, %0, 32 \n"
- " bnel %0, %1, 1b \n"
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%0) \n"
- " daddiu %0, %0, -128 \n"
-#endif
- " sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */
- "1: sd $0, 8(%0) \n"
- " sd $0, 16(%0) \n"
- " sd $0, 24(%0) \n"
- " daddiu %0, %0, 32 \n"
- " bnel %0, %1, 1b \n"
- " sd $0, 0(%0) \n"
- " .set pop \n"
- : "+r" (addr)
- : "r" (end)
- : "memory");
-}
-
-static inline void copy_page_cpu(void *to, void *from)
-{
- unsigned char *src = (unsigned char *)from;
- unsigned char *dst = (unsigned char *)to;
- unsigned char *end = src + PAGE_SIZE;
-
- /*
- * The pref's used here are using "streaming" hints, which cause the
- * copied data to be kicked out of the cache sooner. A page copy often
- * ends up copying a lot more data than is commonly used, so this seems
- * to make sense in terms of reducing cache pollution, but I've no real
- * performance data to back this up
- */
- __asm__ __volatile__(
- " .set push \n"
- " .set mips4 \n"
- " .set noreorder \n"
-#ifdef CONFIG_CPU_HAS_PREFETCH
- " daddiu %0, %0, 128 \n"
- " daddiu %1, %1, 128 \n"
- " pref " SB1_PREF_LOAD_STREAMED_HINT ", -128(%0)\n"
- /* Prefetch the first 4 lines */
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -128(%1)\n"
- " pref " SB1_PREF_LOAD_STREAMED_HINT ", -96(%0)\n"
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -96(%1)\n"
- " pref " SB1_PREF_LOAD_STREAMED_HINT ", -64(%0)\n"
- " pref " SB1_PREF_STORE_STREAMED_HINT ", -64(%1)\n"
- " pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n"
- "1: pref " SB1_PREF_STORE_STREAMED_HINT ", -32(%1)\n"
-# ifdef CONFIG_64BIT
- " ld $8, -128(%0) \n" /* Block copy a cacheline */
- " ld $9, -120(%0) \n"
- " ld $10, -112(%0) \n"
- " ld $11, -104(%0) \n"
- " sd $8, -128(%1) \n"
- " sd $9, -120(%1) \n"
- " sd $10, -112(%1) \n"
- " sd $11, -104(%1) \n"
-# else
- " lw $2, -128(%0) \n" /* Block copy a cacheline */
- " lw $3, -124(%0) \n"
- " lw $6, -120(%0) \n"
- " lw $7, -116(%0) \n"
- " lw $8, -112(%0) \n"
- " lw $9, -108(%0) \n"
- " lw $10, -104(%0) \n"
- " lw $11, -100(%0) \n"
- " sw $2, -128(%1) \n"
- " sw $3, -124(%1) \n"
- " sw $6, -120(%1) \n"
- " sw $7, -116(%1) \n"
- " sw $8, -112(%1) \n"
- " sw $9, -108(%1) \n"
- " sw $10, -104(%1) \n"
- " sw $11, -100(%1) \n"
-# endif
- " daddiu %0, %0, 32 \n"
- " daddiu %1, %1, 32 \n"
- " bnel %0, %2, 1b \n"
- " pref " SB1_PREF_LOAD_STREAMED_HINT ", -32(%0)\n"
- " daddiu %0, %0, -128 \n"
- " daddiu %1, %1, -128 \n"
-#endif
-#ifdef CONFIG_64BIT
- " ld $8, 0(%0) \n" /* Block copy a cacheline */
- "1: ld $9, 8(%0) \n"
- " ld $10, 16(%0) \n"
- " ld $11, 24(%0) \n"
- " sd $8, 0(%1) \n"
- " sd $9, 8(%1) \n"
- " sd $10, 16(%1) \n"
- " sd $11, 24(%1) \n"
-#else
- " lw $2, 0(%0) \n" /* Block copy a cacheline */
- "1: lw $3, 4(%0) \n"
- " lw $6, 8(%0) \n"
- " lw $7, 12(%0) \n"
- " lw $8, 16(%0) \n"
- " lw $9, 20(%0) \n"
- " lw $10, 24(%0) \n"
- " lw $11, 28(%0) \n"
- " sw $2, 0(%1) \n"
- " sw $3, 4(%1) \n"
- " sw $6, 8(%1) \n"
- " sw $7, 12(%1) \n"
- " sw $8, 16(%1) \n"
- " sw $9, 20(%1) \n"
- " sw $10, 24(%1) \n"
- " sw $11, 28(%1) \n"
-#endif
- " daddiu %0, %0, 32 \n"
- " daddiu %1, %1, 32 \n"
- " bnel %0, %2, 1b \n"
-#ifdef CONFIG_64BIT
- " ld $8, 0(%0) \n"
-#else
- " lw $2, 0(%0) \n"
-#endif
- " .set pop \n"
- : "+r" (src), "+r" (dst)
- : "r" (end)
-#ifdef CONFIG_64BIT
- : "$8", "$9", "$10", "$11", "memory");
-#else
- : "$2", "$3", "$6", "$7", "$8", "$9", "$10", "$11", "memory");
-#endif
-}
-
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-
-/*
- * Pad descriptors to cacheline, since each is exclusively owned by a
- * particular CPU.
- */
-typedef struct dmadscr_s {
- u64 dscr_a;
- u64 dscr_b;
- u64 pad_a;
- u64 pad_b;
-} dmadscr_t;
-
-static dmadscr_t page_descr[DM_NUM_CHANNELS]
- __attribute__((aligned(SMP_CACHE_BYTES)));
-
-void sb1_dma_init(void)
-{
- int i;
-
- for (i = 0; i < DM_NUM_CHANNELS; i++) {
- const u64 base_val = CPHYSADDR((unsigned long)&page_descr[i]) |
- V_DM_DSCR_BASE_RINGSZ(1);
- void *base_reg = IOADDR(A_DM_REGISTER(i, R_DM_DSCR_BASE));
-
- __raw_writeq(base_val, base_reg);
- __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg);
- __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg);
- }
-}
-
-void clear_page(void *page)
-{
- u64 to_phys = CPHYSADDR((unsigned long)page);
- unsigned int cpu = smp_processor_id();
-
- /* if the page is not in KSEG0, use old way */
- if ((long)KSEGX((unsigned long)page) != (long)CKSEG0)
- return clear_page_cpu(page);
-
- page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM |
- M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
- page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
- __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
-
- /*
- * Don't really want to do it this way, but there's no
- * reliable way to delay completion detection.
- */
- while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
- & M_DM_DSCR_BASE_INTERRUPT))
- ;
- __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
-}
-
-void copy_page(void *to, void *from)
-{
- u64 from_phys = CPHYSADDR((unsigned long)from);
- u64 to_phys = CPHYSADDR((unsigned long)to);
- unsigned int cpu = smp_processor_id();
-
- /* if any page is not in KSEG0, use old way */
- if ((long)KSEGX((unsigned long)to) != (long)CKSEG0
- || (long)KSEGX((unsigned long)from) != (long)CKSEG0)
- return copy_page_cpu(to, from);
-
- page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST |
- M_DM_DSCRA_INTERRUPT;
- page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
- __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
-
- /*
- * Don't really want to do it this way, but there's no
- * reliable way to delay completion detection.
- */
- while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
- & M_DM_DSCR_BASE_INTERRUPT))
- ;
- __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
-}
-
-#else /* !CONFIG_SIBYTE_DMA_PAGEOPS */
-
-void clear_page(void *page)
-{
- return clear_page_cpu(page);
-}
-
-void copy_page(void *to, void *from)
-{
- return copy_page_cpu(to, from);
-}
-
-#endif /* !CONFIG_SIBYTE_DMA_PAGEOPS */
-
-EXPORT_SYMBOL(clear_page);
-EXPORT_SYMBOL(copy_page);
-
-void __cpuinit build_clear_page(void)
-{
-}
-
-void __cpuinit build_copy_page(void)
-{
-}
diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
index 57df1c38e303..7dfa579ab24c 100644
--- a/arch/mips/mm/pgtable.c
+++ b/arch/mips/mm/pgtable.c
@@ -12,7 +12,6 @@ void show_mem(void)
printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
pfn = max_mapnr;
while (pfn-- > 0) {
if (!pfn_valid(pfn))
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 63065d6e8063..5ce2fa745626 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -299,7 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
idx = read_c0_index();
ptep = pte_offset_map(pmdp, address);
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
write_c0_entrylo0(ptep->pte_high);
ptep++;
write_c0_entrylo1(ptep->pte_high);
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
index 1a6f7704cc89..1655aa69e133 100644
--- a/arch/mips/mm/uasm.c
+++ b/arch/mips/mm/uasm.c
@@ -58,13 +58,13 @@ enum opcode {
insn_invalid,
insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
- insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
- insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
- insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
- insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
- insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
- insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
- insn_tlbwr, insn_xor, insn_xori
+ insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0,
+ insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl,
+ insn_dsrl32, insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr,
+ insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0,
+ insn_mtc0, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd,
+ insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw,
+ insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori
};
struct insn {
@@ -94,6 +94,7 @@ static struct insn insn_table[] __cpuinitdata = {
{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+ { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
{ insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
@@ -116,6 +117,7 @@ static struct insn insn_table[] __cpuinitdata = {
{ insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
{ insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
+ { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
{ insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
@@ -337,6 +339,7 @@ I_u1s2(_bgezl)
I_u1s2(_bltz)
I_u1s2(_bltzl)
I_u1u2s3(_bne)
+I_u2s3u1(_cache)
I_u1u2u3(_dmfc0)
I_u1u2u3(_dmtc0)
I_u2u1s3(_daddiu)
@@ -359,6 +362,7 @@ I_u2s3u1(_lw)
I_u1u2u3(_mfc0)
I_u1u2u3(_mtc0)
I_u2u1u3(_ori)
+I_u2s3u1(_pref)
I_0(_rfe)
I_u2s3u1(_sc)
I_u2s3u1(_scd)
@@ -555,6 +559,14 @@ uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
}
void __cpuinit
+uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
+ unsigned int reg2, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bne(p, reg1, reg2, 0);
+}
+
+void __cpuinit
uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h
index fe0574f6e77d..0d6a66f32030 100644
--- a/arch/mips/mm/uasm.h
+++ b/arch/mips/mm/uasm.h
@@ -55,6 +55,7 @@ Ip_u1s2(_bgezl);
Ip_u1s2(_bltz);
Ip_u1s2(_bltzl);
Ip_u1u2s3(_bne);
+Ip_u2s3u1(_cache);
Ip_u1u2u3(_dmfc0);
Ip_u1u2u3(_dmtc0);
Ip_u2u1s3(_daddiu);
@@ -77,6 +78,7 @@ Ip_u2s3u1(_lw);
Ip_u1u2u3(_mfc0);
Ip_u1u2u3(_mtc0);
Ip_u2u1u3(_ori);
+Ip_u2s3u1(_pref);
Ip_0(_rfe);
Ip_u2s3u1(_sc);
Ip_u2s3u1(_scd);
@@ -177,6 +179,8 @@ void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid);
void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
+ unsigned int reg2, int lid);
void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
diff --git a/arch/mips/philips/pnx8550/common/Makefile b/arch/mips/nxp/pnx8550/common/Makefile
index 31cc1a5cec3b..31cc1a5cec3b 100644
--- a/arch/mips/philips/pnx8550/common/Makefile
+++ b/arch/mips/nxp/pnx8550/common/Makefile
diff --git a/arch/mips/philips/pnx8550/common/gdb_hook.c b/arch/mips/nxp/pnx8550/common/gdb_hook.c
index ad4624f6d9bc..ad4624f6d9bc 100644
--- a/arch/mips/philips/pnx8550/common/gdb_hook.c
+++ b/arch/mips/nxp/pnx8550/common/gdb_hook.c
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/nxp/pnx8550/common/int.c
index aad03429a5e3..aad03429a5e3 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/nxp/pnx8550/common/int.c
diff --git a/arch/mips/philips/pnx8550/common/pci.c b/arch/mips/nxp/pnx8550/common/pci.c
index eee4f3dfc410..eee4f3dfc410 100644
--- a/arch/mips/philips/pnx8550/common/pci.c
+++ b/arch/mips/nxp/pnx8550/common/pci.c
diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/nxp/pnx8550/common/platform.c
index c839436bd012..c7c763dbe588 100644
--- a/arch/mips/philips/pnx8550/common/platform.c
+++ b/arch/mips/nxp/pnx8550/common/platform.c
@@ -1,5 +1,5 @@
/*
- * Platform device support for Philips PNX8550 SoCs
+ * Platform device support for NXP PNX8550 SoCs
*
* Copyright 2005, Embedded Alley Solutions, Inc
*
diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/nxp/pnx8550/common/proc.c
index 18b125e3b65d..18b125e3b65d 100644
--- a/arch/mips/philips/pnx8550/common/proc.c
+++ b/arch/mips/nxp/pnx8550/common/proc.c
diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/nxp/pnx8550/common/prom.c
index 2f567452e7ac..2f567452e7ac 100644
--- a/arch/mips/philips/pnx8550/common/prom.c
+++ b/arch/mips/nxp/pnx8550/common/prom.c
diff --git a/arch/mips/philips/pnx8550/common/reset.c b/arch/mips/nxp/pnx8550/common/reset.c
index 7b2cbc5b2c7c..7b2cbc5b2c7c 100644
--- a/arch/mips/philips/pnx8550/common/reset.c
+++ b/arch/mips/nxp/pnx8550/common/reset.c
diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/nxp/pnx8550/common/setup.c
index 92d764c97701..92d764c97701 100644
--- a/arch/mips/philips/pnx8550/common/setup.c
+++ b/arch/mips/nxp/pnx8550/common/setup.c
diff --git a/arch/mips/philips/pnx8550/common/time.c b/arch/mips/nxp/pnx8550/common/time.c
index 62f495b57f93..62f495b57f93 100644
--- a/arch/mips/philips/pnx8550/common/time.c
+++ b/arch/mips/nxp/pnx8550/common/time.c
diff --git a/arch/mips/philips/pnx8550/jbs/Makefile b/arch/mips/nxp/pnx8550/jbs/Makefile
index e8228dbca8f6..ad6a8ca7d8ce 100644
--- a/arch/mips/philips/pnx8550/jbs/Makefile
+++ b/arch/mips/nxp/pnx8550/jbs/Makefile
@@ -1,4 +1,4 @@
-# Makefile for the Philips JBS Board.
+# Makefile for the NXP JBS Board.
lib-y := init.o board_setup.o irqmap.o
diff --git a/arch/mips/philips/pnx8550/jbs/board_setup.c b/arch/mips/nxp/pnx8550/jbs/board_setup.c
index f92826e0096d..f92826e0096d 100644
--- a/arch/mips/philips/pnx8550/jbs/board_setup.c
+++ b/arch/mips/nxp/pnx8550/jbs/board_setup.c
diff --git a/arch/mips/philips/pnx8550/jbs/init.c b/arch/mips/nxp/pnx8550/jbs/init.c
index 90b4d35f3ece..d59b4a4e5e8b 100644
--- a/arch/mips/philips/pnx8550/jbs/init.c
+++ b/arch/mips/nxp/pnx8550/jbs/init.c
@@ -40,7 +40,7 @@ extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
- return "Philips PNX8550/JBS";
+ return "NXP PNX8550/JBS";
}
void __init prom_init(void)
diff --git a/arch/mips/philips/pnx8550/jbs/irqmap.c b/arch/mips/nxp/pnx8550/jbs/irqmap.c
index 98c3429e6e50..7fc89842002c 100644
--- a/arch/mips/philips/pnx8550/jbs/irqmap.c
+++ b/arch/mips/nxp/pnx8550/jbs/irqmap.c
@@ -1,5 +1,5 @@
/*
- * Philips JBS board irqmap.
+ * NXP JBS board irqmap.
*
* Copyright 2005 Embedded Alley Solutions, Inc
* source@embeddealley.com
@@ -33,4 +33,3 @@ char pnx8550_irq_tab[][5] __initdata = {
[9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
[17] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
};
-
diff --git a/arch/mips/philips/pnx8550/stb810/Makefile b/arch/mips/nxp/pnx8550/stb810/Makefile
index f14b592af398..ab91d72c5664 100644
--- a/arch/mips/philips/pnx8550/stb810/Makefile
+++ b/arch/mips/nxp/pnx8550/stb810/Makefile
@@ -1,4 +1,4 @@
-# Makefile for the Philips STB810 Board.
+# Makefile for the NXP STB810 Board.
lib-y := prom_init.o board_setup.o irqmap.o
diff --git a/arch/mips/philips/pnx8550/stb810/board_setup.c b/arch/mips/nxp/pnx8550/stb810/board_setup.c
index 345d71e53cf2..1282c27cfcb7 100644
--- a/arch/mips/philips/pnx8550/stb810/board_setup.c
+++ b/arch/mips/nxp/pnx8550/stb810/board_setup.c
@@ -1,7 +1,7 @@
/*
* STB810 specific board startup routines.
*
- * Based on the arch/mips/philips/pnx8550/jbs/board_setup.c
+ * Based on the arch/mips/nxp/pnx8550/jbs/board_setup.c
*
* Author: MontaVista Software, Inc.
* source@mvista.com
diff --git a/arch/mips/philips/pnx8550/stb810/irqmap.c b/arch/mips/nxp/pnx8550/stb810/irqmap.c
index 5ee11e19975e..8c034963ddcd 100644
--- a/arch/mips/philips/pnx8550/stb810/irqmap.c
+++ b/arch/mips/nxp/pnx8550/stb810/irqmap.c
@@ -1,5 +1,5 @@
/*
- * Philips STB810 board irqmap.
+ * NXP STB810 board irqmap.
*
* Author: MontaVista Software, Inc.
* source@mvista.com
@@ -20,4 +20,3 @@ char pnx8550_irq_tab[][5] __initdata = {
[9] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
[10] = { -1, PNX8550_INT_PCI_INTA, 0xff, 0xff, 0xff},
};
-
diff --git a/arch/mips/philips/pnx8550/stb810/prom_init.c b/arch/mips/nxp/pnx8550/stb810/prom_init.c
index 832dd60b0a7a..ca7f4ada0640 100644
--- a/arch/mips/philips/pnx8550/stb810/prom_init.c
+++ b/arch/mips/nxp/pnx8550/stb810/prom_init.c
@@ -28,7 +28,7 @@ extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
- return "Philips PNX8550/STB810";
+ return "NXP PNX8950/STB810";
}
void __init prom_init(void)
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
index aa52aa146cea..b5f6f71b27bc 100644
--- a/arch/mips/oprofile/common.c
+++ b/arch/mips/oprofile/common.c
@@ -80,6 +80,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
case CPU_24K:
case CPU_25KF:
case CPU_34K:
+ case CPU_1004K:
case CPU_74K:
case CPU_SB1:
case CPU_SB1A:
diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h
index fa6b4aae7523..2bfc17c30106 100644
--- a/arch/mips/oprofile/op_impl.h
+++ b/arch/mips/oprofile/op_impl.h
@@ -10,7 +10,6 @@
#ifndef OP_IMPL_H
#define OP_IMPL_H 1
-extern int null_perf_irq(void);
extern int (*perf_irq)(void);
/* Per-counter configuration as set via oprofilefs. */
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index ccbea229a0e6..da8cbb6899dc 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -31,9 +31,14 @@
#define M_COUNTER_OVERFLOW (1UL << 31)
+static int (*save_perf_irq)(void);
+
#ifdef CONFIG_MIPS_MT_SMP
-#define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id()))
-#define vpe_id() smp_processor_id()
+static int cpu_has_mipsmt_pertccounters;
+#define WHAT (M_TC_EN_VPE | \
+ M_PERFCTL_VPEID(cpu_data[smp_processor_id()].vpe_id))
+#define vpe_id() (cpu_has_mipsmt_pertccounters ? \
+ 0 : cpu_data[smp_processor_id()].vpe_id)
/*
* The number of bits to shift to convert between counters per core and
@@ -243,11 +248,11 @@ static inline int __n_counters(void)
{
if (!(read_c0_config1() & M_CONFIG1_PC))
return 0;
- if (!(r_c0_perfctrl0() & M_PERFCTL_MORE))
+ if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
return 1;
- if (!(r_c0_perfctrl1() & M_PERFCTL_MORE))
+ if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
return 2;
- if (!(r_c0_perfctrl2() & M_PERFCTL_MORE))
+ if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
return 3;
return 4;
@@ -274,8 +279,9 @@ static inline int n_counters(void)
return counters;
}
-static inline void reset_counters(int counters)
+static void reset_counters(void *arg)
{
+ int counters = (int)arg;
switch (counters) {
case 4:
w_c0_perfctrl3(0);
@@ -302,9 +308,12 @@ static int __init mipsxx_init(void)
return -ENODEV;
}
- reset_counters(counters);
-
- counters = counters_total_to_per_cpu(counters);
+#ifdef CONFIG_MIPS_MT_SMP
+ cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
+ if (!cpu_has_mipsmt_pertccounters)
+ counters = counters_total_to_per_cpu(counters);
+#endif
+ on_each_cpu(reset_counters, (void *)counters, 0, 1);
op_model_mipsxx_ops.num_counters = counters;
switch (current_cpu_type()) {
@@ -320,6 +329,13 @@ static int __init mipsxx_init(void)
op_model_mipsxx_ops.cpu_type = "mips/25K";
break;
+ case CPU_1004K:
+#if 0
+ /* FIXME: report as 34K for now */
+ op_model_mipsxx_ops.cpu_type = "mips/1004K";
+ break;
+#endif
+
case CPU_34K:
op_model_mipsxx_ops.cpu_type = "mips/34K";
break;
@@ -355,6 +371,7 @@ static int __init mipsxx_init(void)
return -ENODEV;
}
+ save_perf_irq = perf_irq;
perf_irq = mipsxx_perfcount_handler;
return 0;
@@ -365,9 +382,9 @@ static void mipsxx_exit(void)
int counters = op_model_mipsxx_ops.num_counters;
counters = counters_per_cpu_to_total(counters);
- reset_counters(counters);
+ on_each_cpu(reset_counters, (void *)counters, 0, 1);
- perf_irq = null_perf_irq;
+ perf_irq = save_perf_irq;
}
struct op_mips_model op_model_mipsxx_ops = {
diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c
index ca0276c8070a..00c36c9dbe0e 100644
--- a/arch/mips/pci/fixup-au1000.c
+++ b/arch/mips/pci/fixup-au1000.c
@@ -26,13 +26,10 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/types.h>
+
#include <linux/pci.h>
-#include <linux/kernel.h>
#include <linux/init.h>
-#include <asm/mach-au1x00/au1000.h>
-
extern char irq_tab_alchemy[][5];
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c
index d61064652498..0e160d9f07c3 100644
--- a/arch/mips/pci/ops-pnx8550.c
+++ b/arch/mips/pci/ops-pnx8550.c
@@ -90,14 +90,14 @@ config_access(unsigned int pci_cmd, struct pci_bus *bus, unsigned int devfn, int
loops--;
if (loops == 0) {
- printk("%s : Arbiter Locked.\n", __FUNCTION__);
+ printk("%s : Arbiter Locked.\n", __func__);
}
}
clear_status();
if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) {
printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n",
- __FUNCTION__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr,
+ __func__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr,
pci_cmd);
}
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
index 624bbdbff2a8..b6cab089561e 100644
--- a/arch/mips/sgi-ip32/ip32-reset.c
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -142,7 +142,7 @@ static irqreturn_t ip32_rtc_int(int irq, void *dev_id)
reg_c = CMOS_READ(RTC_INTR_FLAGS);
if (!(reg_c & RTC_IRQF)) {
printk(KERN_WARNING
- "%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__);
+ "%s: RTC IRQ without RTC_IRQF\n", __func__);
}
/* Wait until interrupt goes away */
disable_irq(MACEISA_RTC_IRQ);
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
index 3f808b629242..6d31f2a98abf 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
@@ -173,7 +173,7 @@ static const u32 toshiba_rbtx4927_irq_debug_flag =
{ \
char tmp[100]; \
sprintf( tmp, str ); \
- printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \
+ printk( "%s(%s:%u)::%s", __func__, __FILE__, __LINE__, tmp ); \
}
#else
#define TOSHIBA_RBTX4927_IRQ_DPRINTK(flag, str...)
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index e466e5e711d8..2203c77b2ce2 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -93,7 +93,7 @@ static const u32 toshiba_rbtx4927_setup_debug_flag =
{ \
char tmp[100]; \
sprintf( tmp, str ); \
- printk( "%s(%s:%u)::%s", __FUNCTION__, __FILE__, __LINE__, tmp ); \
+ printk( "%s(%s:%u)::%s", __func__, __FILE__, __LINE__, tmp ); \
}
#else
#define TOSHIBA_RBTX4927_SETUP_DPRINTK(flag, str...)
diff --git a/arch/mips/tx4938/common/dbgio.c b/arch/mips/tx4938/common/dbgio.c
index bea59ff1842a..33b9c672a322 100644
--- a/arch/mips/tx4938/common/dbgio.c
+++ b/arch/mips/tx4938/common/dbgio.c
@@ -31,9 +31,7 @@
* Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp>
*/
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/tx4938/tx4938_mips.h>
+#include <linux/types>
extern u8 txx9_sio_kdbg_rd(void);
extern int txx9_sio_kdbg_wr( u8 ch );
diff --git a/arch/mips/tx4938/common/prom.c b/arch/mips/tx4938/common/prom.c
index 3189a65f7d7e..20baeaeba4cd 100644
--- a/arch/mips/tx4938/common/prom.c
+++ b/arch/mips/tx4938/common/prom.c
@@ -13,13 +13,8 @@
*/
#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <asm/tx4938/tx4938.h>
+#include <linux/types.h>
+#include <linux/io.h>
static unsigned int __init
tx4938_process_sdccr(u64 * addr)
@@ -35,7 +30,7 @@ tx4938_process_sdccr(u64 * addr)
unsigned int bc = 4;
unsigned int msize = 0;
- val = (*((vu64 *) (addr)));
+ val = ____raw_readq((void __iomem *)addr);
/* MVMCP -- need #defs for these bits masks */
sdccr_ce = ((val & (1 << 10)) >> 10);
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
index f00185017e80..4d6a8dc46c76 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
@@ -67,24 +67,7 @@ IRQ Device
63 RBTX4938-IOC/07 SWINT
*/
#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/timex.h>
-#include <asm/bootinfo.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/time.h>
-#include <asm/wbflush.h>
-#include <linux/bootmem.h>
#include <asm/tx4938/rbtx4938.h>
static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq);
@@ -99,21 +82,16 @@ static struct irq_chip toshiba_rbtx4938_irq_ioc_type = {
.unmask = toshiba_rbtx4938_irq_ioc_enable,
};
-#define TOSHIBA_RBTX4938_IOC_INTR_ENAB 0xb7f02000
-#define TOSHIBA_RBTX4938_IOC_INTR_STAT 0xb7f0200a
-
int
toshiba_rbtx4938_irq_nested(int sw_irq)
{
u8 level3;
- level3 = reg_rd08(TOSHIBA_RBTX4938_IOC_INTR_STAT) & 0xff;
- if (level3) {
+ level3 = readb(rbtx4938_imstat_addr);
+ if (level3)
/* must use fls so onboard ATA has priority */
sw_irq = TOSHIBA_RBTX4938_IRQ_IOC_BEG + fls(level3) - 1;
- }
- wbflush();
return sw_irq;
}
@@ -144,25 +122,23 @@ toshiba_rbtx4938_irq_ioc_init(void)
static void
toshiba_rbtx4938_irq_ioc_enable(unsigned int irq)
{
- volatile unsigned char v;
+ unsigned char v;
- v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB);
+ v = readb(rbtx4938_imask_addr);
v |= (1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG));
- TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v);
+ writeb(v, rbtx4938_imask_addr);
mmiowb();
- TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB);
}
static void
toshiba_rbtx4938_irq_ioc_disable(unsigned int irq)
{
- volatile unsigned char v;
+ unsigned char v;
- v = TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB);
+ v = readb(rbtx4938_imask_addr);
v &= ~(1 << (irq - TOSHIBA_RBTX4938_IRQ_IOC_BEG));
- TX4938_WR08(TOSHIBA_RBTX4938_IOC_INTR_ENAB, v);
+ writeb(v, rbtx4938_imask_addr);
mmiowb();
- TX4938_RD08(TOSHIBA_RBTX4938_IOC_INTR_ENAB);
}
void __init arch_init_irq(void)
@@ -174,14 +150,12 @@ void __init arch_init_irq(void)
/* all IRC interrupt mode are Low Active. */
/* mask all IOC interrupts */
- *rbtx4938_imask_ptr = 0;
+ writeb(0, rbtx4938_imask_addr);
/* clear SoftInt interrupts */
- *rbtx4938_softint_ptr = 0;
+ writeb(0, rbtx4938_softint_addr);
tx4938_irq_init();
toshiba_rbtx4938_irq_ioc_init();
/* Onboard 10M Ether: High Active */
set_irq_type(RBTX4938_IRQ_ETHER, IRQF_TRIGGER_HIGH);
-
- wbflush();
}
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
index 61249f049cd6..3a3659e8633a 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
@@ -21,8 +21,8 @@
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/gpio.h>
-#include <asm/wbflush.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <asm/txx9tmr.h>
@@ -34,7 +34,7 @@
#endif
#include <linux/spi/spi.h>
#include <asm/tx4938/spi.h>
-#include <asm/gpio.h>
+#include <asm/txx9pio.h>
extern char * __init prom_getcmdline(void);
static inline void tx4938_report_pcic_status1(struct tx4938_pcic_reg *pcicptr);
@@ -90,12 +90,11 @@ void rbtx4938_machine_restart(char *command)
local_irq_disable();
printk("Rebooting...");
- *rbtx4938_softresetlock_ptr = 1;
- *rbtx4938_sfvol_ptr = 1;
- *rbtx4938_softreset_ptr = 1;
- wbflush();
-
- while(1);
+ writeb(1, rbtx4938_softresetlock_addr);
+ writeb(1, rbtx4938_sfvol_addr);
+ writeb(1, rbtx4938_softreset_addr);
+ while(1)
+ ;
}
void __init
@@ -487,7 +486,7 @@ static int __init tx4938_pcibios_init(void)
}
/* Reset PCI Bus */
- *rbtx4938_pcireset_ptr = 0;
+ writeb(0, rbtx4938_pcireset_addr);
/* Reset PCIC */
tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST;
if (txboard_pci66_mode > 0)
@@ -495,8 +494,8 @@ static int __init tx4938_pcibios_init(void)
mdelay(10);
/* clear PCIC reset */
tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST;
- *rbtx4938_pcireset_ptr = 1;
- wbflush();
+ writeb(1, rbtx4938_pcireset_addr);
+ mmiowb();
tx4938_report_pcic_status1(tx4938_pcicptr);
tx4938_report_pciclk();
@@ -504,15 +503,15 @@ static int __init tx4938_pcibios_init(void)
if (txboard_pci66_mode == 0 &&
txboard_pci66_check(&tx4938_pci_controller[0], 0, 0)) {
/* Reset PCI Bus */
- *rbtx4938_pcireset_ptr = 0;
+ writeb(0, rbtx4938_pcireset_addr);
/* Reset PCIC */
tx4938_ccfgptr->clkctr |= TX4938_CLKCTR_PCIRST;
tx4938_pciclk66_setup();
mdelay(10);
/* clear PCIC reset */
tx4938_ccfgptr->clkctr &= ~TX4938_CLKCTR_PCIRST;
- *rbtx4938_pcireset_ptr = 1;
- wbflush();
+ writeb(1, rbtx4938_pcireset_addr);
+ mmiowb();
/* Reinitialize PCIC */
tx4938_report_pciclk();
tx4938_pcic_setup(tx4938_pcicptr, &tx4938_pci_controller[0], io_base[0], extarb);
@@ -615,9 +614,6 @@ static void __init rbtx4938_spi_setup(void)
{
/* set SPI_SEL */
tx4938_ccfgptr->pcfg |= TX4938_PCFG_SPI_SEL;
- /* chip selects for SPI devices */
- tx4938_pioptr->dout |= (1 << SEEPROM1_CS);
- tx4938_pioptr->dir |= (1 << SEEPROM1_CS);
}
static struct resource rbtx4938_fpga_resource;
@@ -776,12 +772,13 @@ void __init tx4938_board_setup(void)
txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL);
/* enable DMA */
- TX4938_WR64(0xff1fb150, TX4938_DMA_MCR_MSTEN);
- TX4938_WR64(0xff1fb950, TX4938_DMA_MCR_MSTEN);
+ for (i = 0; i < 2; i++)
+ ____raw_writeq(TX4938_DMA_MCR_MSTEN,
+ (void __iomem *)(TX4938_DMA_REG(i) + 0x50));
/* PIO */
- tx4938_pioptr->maskcpu = 0;
- tx4938_pioptr->maskext = 0;
+ __raw_writel(0, &tx4938_pioptr->maskcpu);
+ __raw_writel(0, &tx4938_pioptr->maskext);
/* TX4938 internal registers */
if (request_resource(&iomem_resource, &tx4938_reg_resource))
@@ -863,10 +860,6 @@ void __init plat_mem_setup(void)
if (txx9_master_clock == 0)
txx9_master_clock = 25000000; /* 25MHz */
tx4938_board_setup();
- /* setup serial stuff */
- TX4938_WR(0xff1ff314, 0x00000000); /* h/w flow control off */
- TX4938_WR(0xff1ff414, 0x00000000); /* h/w flow control off */
-
#ifndef CONFIG_PCI
set_io_port_base(RBTX4938_ETHER_BASE);
#endif
@@ -932,16 +925,16 @@ void __init plat_mem_setup(void)
pcfg = tx4938_ccfgptr->pcfg; /* updated */
/* fixup piosel */
if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) ==
- TX4938_PCFG_ATA_SEL) {
- *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x04;
- }
+ TX4938_PCFG_ATA_SEL)
+ writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x04,
+ rbtx4938_piosel_addr);
else if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) ==
- TX4938_PCFG_NDF_SEL) {
- *rbtx4938_piosel_ptr = (*rbtx4938_piosel_ptr & 0x03) | 0x08;
- }
- else {
- *rbtx4938_piosel_ptr &= ~(0x08 | 0x04);
- }
+ TX4938_PCFG_NDF_SEL)
+ writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x08,
+ rbtx4938_piosel_addr);
+ else
+ writeb(readb(rbtx4938_piosel_addr) & ~(0x08 | 0x04),
+ rbtx4938_piosel_addr);
rbtx4938_fpga_resource.name = "FPGA Registers";
rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR);
@@ -950,17 +943,14 @@ void __init plat_mem_setup(void)
if (request_resource(&iomem_resource, &rbtx4938_fpga_resource))
printk("request resource for fpga failed\n");
- /* disable all OnBoard I/O interrupts */
- *rbtx4938_imask_ptr = 0;
-
_machine_restart = rbtx4938_machine_restart;
_machine_halt = rbtx4938_machine_halt;
pm_power_off = rbtx4938_machine_power_off;
- *rbtx4938_led_ptr = 0xff;
- printk("RBTX4938 --- FPGA(Rev %02x)", *rbtx4938_fpga_rev_ptr);
- printk(" DIPSW:%02x,%02x\n",
- *rbtx4938_dipsw_ptr, *rbtx4938_bdipsw_ptr);
+ writeb(0xff, rbtx4938_led_addr);
+ printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n",
+ readb(rbtx4938_fpga_rev_addr),
+ readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr));
}
static int __init rbtx4938_ne_init(void)
@@ -984,106 +974,48 @@ device_initcall(rbtx4938_ne_init);
/* GPIO support */
-static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock);
-
-static void rbtx4938_spi_gpio_set(unsigned gpio, int value)
+int gpio_to_irq(unsigned gpio)
{
- u8 val;
- unsigned long flags;
- gpio -= 16;
- spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags);
- val = *rbtx4938_spics_ptr;
- if (value)
- val |= 1 << gpio;
- else
- val &= ~(1 << gpio);
- *rbtx4938_spics_ptr = val;
- mmiowb();
- spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags);
+ return -EINVAL;
}
-static int rbtx4938_spi_gpio_dir_out(unsigned gpio, int value)
+int irq_to_gpio(unsigned irq)
{
- rbtx4938_spi_gpio_set(gpio, value);
- return 0;
+ return -EINVAL;
}
-static DEFINE_SPINLOCK(tx4938_gpio_lock);
-
-static int tx4938_gpio_get(unsigned gpio)
-{
- return tx4938_pioptr->din & (1 << gpio);
-}
+static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock);
-static void tx4938_gpio_set_raw(unsigned gpio, int value)
+static void rbtx4938_spi_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
- u32 val;
- val = tx4938_pioptr->dout;
+ u8 val;
+ unsigned long flags;
+ spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags);
+ val = readb(rbtx4938_spics_addr);
if (value)
- val |= 1 << gpio;
+ val |= 1 << offset;
else
- val &= ~(1 << gpio);
- tx4938_pioptr->dout = val;
-}
-
-static void tx4938_gpio_set(unsigned gpio, int value)
-{
- unsigned long flags;
- spin_lock_irqsave(&tx4938_gpio_lock, flags);
- tx4938_gpio_set_raw(gpio, value);
- mmiowb();
- spin_unlock_irqrestore(&tx4938_gpio_lock, flags);
-}
-
-static int tx4938_gpio_dir_in(unsigned gpio)
-{
- spin_lock_irq(&tx4938_gpio_lock);
- tx4938_pioptr->dir &= ~(1 << gpio);
+ val &= ~(1 << offset);
+ writeb(val, rbtx4938_spics_addr);
mmiowb();
- spin_unlock_irq(&tx4938_gpio_lock);
- return 0;
-}
-
-static int tx4938_gpio_dir_out(unsigned int gpio, int value)
-{
- spin_lock_irq(&tx4938_gpio_lock);
- tx4938_gpio_set_raw(gpio, value);
- tx4938_pioptr->dir |= 1 << gpio;
- mmiowb();
- spin_unlock_irq(&tx4938_gpio_lock);
- return 0;
-}
-
-int gpio_direction_input(unsigned gpio)
-{
- if (gpio < 16)
- return tx4938_gpio_dir_in(gpio);
- return -EINVAL;
-}
-
-int gpio_direction_output(unsigned gpio, int value)
-{
- if (gpio < 16)
- return tx4938_gpio_dir_out(gpio, value);
- if (gpio < 16 + 3)
- return rbtx4938_spi_gpio_dir_out(gpio, value);
- return -EINVAL;
+ spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags);
}
-int gpio_get_value(unsigned gpio)
+static int rbtx4938_spi_gpio_dir_out(struct gpio_chip *chip,
+ unsigned int offset, int value)
{
- if (gpio < 16)
- return tx4938_gpio_get(gpio);
+ rbtx4938_spi_gpio_set(chip, offset, value);
return 0;
}
-void gpio_set_value(unsigned gpio, int value)
-{
- if (gpio < 16)
- tx4938_gpio_set(gpio, value);
- else
- rbtx4938_spi_gpio_set(gpio, value);
-}
+static struct gpio_chip rbtx4938_spi_gpio_chip = {
+ .set = rbtx4938_spi_gpio_set,
+ .direction_output = rbtx4938_spi_gpio_dir_out,
+ .label = "RBTX4938-SPICS",
+ .base = 16,
+ .ngpio = 3,
+};
/* SPI support */
@@ -1094,7 +1026,6 @@ static void __init txx9_spi_init(unsigned long base, int irq)
.start = base,
.end = base + 0x20 - 1,
.flags = IORESOURCE_MEM,
- .parent = &tx4938_reg_resource,
}, {
.start = irq,
.flags = IORESOURCE_IRQ,
@@ -1118,10 +1049,25 @@ static int __init rbtx4938_spi_init(void)
spi_eeprom_register(SEEPROM1_CS);
spi_eeprom_register(16 + SEEPROM2_CS);
spi_eeprom_register(16 + SEEPROM3_CS);
+ gpio_request(16 + SRTC_CS, "rtc-rs5c348");
+ gpio_direction_output(16 + SRTC_CS, 0);
+ gpio_request(SEEPROM1_CS, "seeprom1");
+ gpio_direction_output(SEEPROM1_CS, 1);
+ gpio_request(16 + SEEPROM2_CS, "seeprom2");
+ gpio_direction_output(16 + SEEPROM2_CS, 1);
+ gpio_request(16 + SEEPROM3_CS, "seeprom3");
+ gpio_direction_output(16 + SEEPROM3_CS, 1);
txx9_spi_init(TX4938_SPI_REG & 0xfffffffffULL, RBTX4938_IRQ_IRC_SPI);
return 0;
}
-arch_initcall(rbtx4938_spi_init);
+
+static int __init rbtx4938_arch_init(void)
+{
+ txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, 16);
+ gpiochip_add(&rbtx4938_spi_gpio_chip);
+ return rbtx4938_spi_init();
+}
+arch_initcall(rbtx4938_arch_init);
/* Watchdog support */
@@ -1131,7 +1077,6 @@ static int __init txx9_wdt_init(unsigned long base)
.start = base,
.end = base + 0x100 - 1,
.flags = IORESOURCE_MEM,
- .parent = &tx4938_reg_resource,
};
struct platform_device *dev =
platform_device_register_simple("txx9wdt", -1, &res, 1);
diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
index 76d4b5ed3fc0..c64995342ba8 100644
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -1,7 +1,7 @@
/*
* init.c, Common initialization routines for NEC VR4100 series.
*
- * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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
@@ -53,6 +53,8 @@ void __init plat_time_init(void)
void __init plat_mem_setup(void)
{
iomem_resource_init();
+
+ vr41xx_siu_setup();
}
void __init prom_init(void)
diff --git a/arch/mips/vr41xx/common/siu.c b/arch/mips/vr41xx/common/siu.c
index b735f45b25f0..654dee6208be 100644
--- a/arch/mips/vr41xx/common/siu.c
+++ b/arch/mips/vr41xx/common/siu.c
@@ -1,7 +1,7 @@
/*
* NEC VR4100 series SIU platform device.
*
- * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2007-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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
@@ -118,3 +118,37 @@ err_free_device:
return retval;
}
device_initcall(vr41xx_siu_add);
+
+void __init vr41xx_siu_setup(void)
+{
+ struct uart_port port;
+ struct resource *res;
+ unsigned int *type;
+ int i;
+
+ switch (current_cpu_type()) {
+ case CPU_VR4111:
+ case CPU_VR4121:
+ type = siu_type1_ports;
+ res = siu_type1_resource;
+ break;
+ case CPU_VR4122:
+ case CPU_VR4131:
+ case CPU_VR4133:
+ type = siu_type2_ports;
+ res = siu_type2_resource;
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < SIU_PORTS_MAX; i++) {
+ port.line = i;
+ port.type = type[i];
+ if (port.type == PORT_UNKNOWN)
+ break;
+ port.mapbase = res[i].start;
+ port.membase = (unsigned char __iomem *)KSEG1ADDR(res[i].start);
+ vr41xx_siu_early_setup(&port);
+ }
+}
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index eb80f5e33d7d..1f012843150f 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -603,15 +603,18 @@ void show_mem(void)
#ifdef CONFIG_DISCONTIGMEM
{
struct zonelist *zl;
- int i, j, k;
+ int i, j;
for (i = 0; i < npmem_ranges; i++) {
+ zl = node_zonelist(i);
for (j = 0; j < MAX_NR_ZONES; j++) {
- zl = NODE_DATA(i)->node_zonelists + j;
+ struct zoneref *z;
+ struct zone *zone;
printk("Zone list for zone %d on node %d: ", j, i);
- for (k = 0; zl->zones[k] != NULL; k++)
- printk("[%d/%s] ", zone_to_nid(zl->zones[k]), zl->zones[k]->name);
+ for_each_zone_zonelist(zone, z, zl, j)
+ printk("[%d/%s] ", zone_to_nid(zone),
+ zone->name);
printk("\n");
}
}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 4bb2e9310a56..4e40c122bf26 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -626,20 +626,6 @@ config ADVANCED_OPTIONS
comment "Default settings for advanced configuration options are used"
depends on !ADVANCED_OPTIONS
-config HIGHMEM_START_BOOL
- bool "Set high memory pool address"
- depends on ADVANCED_OPTIONS && HIGHMEM
- help
- This option allows you to set the base address of the kernel virtual
- area used to map high memory pages. This can be useful in
- optimizing the layout of kernel virtual memory.
-
- Say N here unless you know what you are doing.
-
-config HIGHMEM_START
- hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
- default "0xfe000000"
-
config LOWMEM_SIZE_BOOL
bool "Set maximum low memory"
depends on ADVANCED_OPTIONS
@@ -656,21 +642,76 @@ config LOWMEM_SIZE
hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
default "0x30000000"
+config RELOCATABLE
+ bool "Build a relocatable kernel (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && FSL_BOOKE
+ help
+ This builds a kernel image that is capable of running at the
+ location the kernel is loaded at (some alignment restrictions may
+ exist).
+
+ One use is for the kexec on panic case where the recovery kernel
+ must live at a different physical address than the primary
+ kernel.
+
+ Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
+ it has been loaded at and the compile time physical addresses
+ CONFIG_PHYSICAL_START is ignored. However CONFIG_PHYSICAL_START
+ setting can still be useful to bootwrappers that need to know the
+ load location of the kernel (eg. u-boot/mkimage).
+
+config PAGE_OFFSET_BOOL
+ bool "Set custom page offset address"
+ depends on ADVANCED_OPTIONS
+ help
+ This option allows you to set the kernel virtual address at which
+ the kernel will map low memory. This can be useful in optimizing
+ the virtual memory layout of the system.
+
+ Say N here unless you know what you are doing.
+
+config PAGE_OFFSET
+ hex "Virtual address of memory base" if PAGE_OFFSET_BOOL
+ default "0xc0000000"
+
config KERNEL_START_BOOL
bool "Set custom kernel base address"
depends on ADVANCED_OPTIONS
help
This option allows you to set the kernel virtual address at which
- the kernel will map low memory (the kernel image will be linked at
- this address). This can be useful in optimizing the virtual memory
- layout of the system.
+ the kernel will be loaded. Normally this should match PAGE_OFFSET
+ however there are times (like kdump) that one might not want them
+ to be the same.
Say N here unless you know what you are doing.
config KERNEL_START
hex "Virtual address of kernel base" if KERNEL_START_BOOL
+ default PAGE_OFFSET if PAGE_OFFSET_BOOL
+ default "0xc2000000" if CRASH_DUMP
default "0xc0000000"
+config PHYSICAL_START_BOOL
+ bool "Set physical address where the kernel is loaded"
+ depends on ADVANCED_OPTIONS && FLATMEM && FSL_BOOKE
+ help
+ This gives the physical address where the kernel is loaded.
+
+ Say N here unless you know what you are doing.
+
+config PHYSICAL_START
+ hex "Physical address where the kernel is loaded" if PHYSICAL_START_BOOL
+ default "0x02000000" if PPC_STD_MMU && CRASH_DUMP
+ default "0x00000000"
+
+config PHYSICAL_ALIGN
+ hex
+ default "0x10000000" if FSL_BOOKE
+ help
+ This value puts the alignment restrictions on physical address
+ where kernel is loaded and run from. Kernel is compiled for an
+ address which meets above alignment restriction.
+
config TASK_SIZE_BOOL
bool "Set custom user task size"
depends on ADVANCED_OPTIONS
@@ -717,9 +758,17 @@ config PIN_TLB
endmenu
if PPC64
+config PAGE_OFFSET
+ hex
+ default "0xc000000000000000"
config KERNEL_START
hex
+ default "0xc000000002000000" if CRASH_DUMP
default "0xc000000000000000"
+config PHYSICAL_START
+ hex
+ default "0x02000000" if CRASH_DUMP
+ default "0x00000000"
endif
source "net/Kconfig"
@@ -754,3 +803,4 @@ config PPC_CLOCK
config PPC_LIB_RHEAP
bool
+source "arch/powerpc/kvm/Kconfig"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index a86d8d853214..807a2dce6263 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -151,6 +151,9 @@ config BOOTX_TEXT
config PPC_EARLY_DEBUG
bool "Early debugging (dangerous)"
+ # PPC_EARLY_DEBUG on 440 leaves AS=1 mappings above the TLB high water
+ # mark, which doesn't work with current 440 KVM.
+ depends on !KVM
help
Say Y to enable some early debugging facilities that may be available
for your processor/board combination. Those facilities are hacks
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index e2ec4a91ccef..9dcdc036cdf7 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -145,6 +145,7 @@ core-y += arch/powerpc/kernel/ \
arch/powerpc/platforms/
core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/
core-$(CONFIG_XMON) += arch/powerpc/xmon/
+core-$(CONFIG_KVM) += arch/powerpc/kvm/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
index 5ef2bdf8d189..2347294ff35b 100644
--- a/arch/powerpc/boot/.gitignore
+++ b/arch/powerpc/boot/.gitignore
@@ -27,6 +27,7 @@ zImage.chrp
zImage.coff
zImage.coff.lds
zImage.ep*
+zImage.iseries
zImage.*lds
zImage.miboot
zImage.pmac
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 5ba50c673390..7822d25c9d31 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -40,7 +40,7 @@ $(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
-$(obj)/virtex405-head.o: BOOTCFLAGS += -mcpu=405
+$(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405
zlib := inffast.c inflate.c inftrees.c
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index 6f3d38a1554f..39634124929b 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -142,8 +142,45 @@
#address-cells = <2>;
#size-cells = <1>;
clock-frequency = <0>; /* Filled in by U-Boot */
+ /* ranges property is supplied by U-Boot */
interrupts = <6 4>;
interrupt-parent = <&UIC1>;
+
+ nor_flash@0,0 {
+ compatible = "amd,s29gl512n", "cfi-flash";
+ bank-width = <2>;
+ reg = <0 000000 4000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "kernel";
+ reg = <0 1e0000>;
+ };
+ partition@1e0000 {
+ label = "dtb";
+ reg = <1e0000 20000>;
+ };
+ partition@200000 {
+ label = "ramdisk";
+ reg = <200000 1400000>;
+ };
+ partition@1600000 {
+ label = "jffs2";
+ reg = <1600000 400000>;
+ };
+ partition@1a00000 {
+ label = "user";
+ reg = <1a00000 2560000>;
+ };
+ partition@3f60000 {
+ label = "env";
+ reg = <3f60000 40000>;
+ };
+ partition@3fa0000 {
+ label = "u-boot";
+ reg = <3fa0000 60000>;
+ };
+ };
};
UART0: serial@ef600300 {
diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts
index 958a5ca53d35..0f2fc077d8db 100644
--- a/arch/powerpc/boot/dts/glacier.dts
+++ b/arch/powerpc/boot/dts/glacier.dts
@@ -145,8 +145,45 @@
#address-cells = <2>;
#size-cells = <1>;
clock-frequency = <0>; /* Filled in by U-Boot */
+ /* ranges property is supplied by U-Boot */
interrupts = <6 4>;
interrupt-parent = <&UIC1>;
+
+ nor_flash@0,0 {
+ compatible = "amd,s29gl512n", "cfi-flash";
+ bank-width = <2>;
+ reg = <0 000000 4000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "kernel";
+ reg = <0 1e0000>;
+ };
+ partition@1e0000 {
+ label = "dtb";
+ reg = <1e0000 20000>;
+ };
+ partition@200000 {
+ label = "ramdisk";
+ reg = <200000 1400000>;
+ };
+ partition@1600000 {
+ label = "jffs2";
+ reg = <1600000 400000>;
+ };
+ partition@1a00000 {
+ label = "user";
+ reg = <1a00000 2560000>;
+ };
+ partition@3f60000 {
+ label = "env";
+ reg = <3f60000 40000>;
+ };
+ partition@3fa0000 {
+ label = "u-boot";
+ reg = <3fa0000 60000>;
+ };
+ };
};
UART0: serial@ef600300 {
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 16c947b8a721..1f2f1e0a5571 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -45,6 +45,11 @@
reg = <0x00000000 0x20000000>; // 512M at 0x0
};
+ board-control@e8000000 {
+ compatible = "fsl,fpga-pixis";
+ reg = <0xe8000000 32>; // pixis at 0xe8000000
+ };
+
soc@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -104,6 +109,13 @@
interrupt-parent = <&mpic>;
};
+ display@2c000 {
+ compatible = "fsl,diu";
+ reg = <0x2c000 100>;
+ interrupts = <72 2>;
+ interrupt-parent = <&mpic>;
+ };
+
mpic: interrupt-controller@40000 {
clock-frequency = <0>;
interrupt-controller;
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c
index aef3bdc89160..8c9ead94be06 100644
--- a/arch/powerpc/boot/ns16550.c
+++ b/arch/powerpc/boot/ns16550.c
@@ -55,10 +55,15 @@ static u8 ns16550_tstc(void)
int ns16550_console_init(void *devp, struct serial_console_data *scdp)
{
int n;
+ u32 reg_offset;
if (dt_get_virtual_reg(devp, (void **)&reg_base, 1) < 1)
return -1;
+ n = getprop(devp, "reg-offset", &reg_offset, sizeof(reg_offset));
+ if (n == sizeof(reg_offset))
+ reg_base += reg_offset;
+
n = getprop(devp, "reg-shift", &reg_shift, sizeof(reg_shift));
if (n != sizeof(reg_shift))
reg_shift = 0;
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index ce1e8d24e747..9177b21b1a95 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -106,4 +106,13 @@ PHONY += systbl_chk
systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
$(call cmd,systbl_chk)
+$(obj)/built-in.o: prom_init_check
+
+quiet_cmd_prom_init_check = CALL $<
+ cmd_prom_init_check = $(CONFIG_SHELL) $< "$(NM)" "$(obj)/prom_init.o"
+
+PHONY += prom_init_check
+prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o
+ $(call cmd,prom_init_check)
+
clean-files := vmlinux.lds
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 292c6d8db0e1..62134845af08 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -23,6 +23,9 @@
#include <linux/mm.h>
#include <linux/suspend.h>
#include <linux/hrtimer.h>
+#ifdef CONFIG_KVM
+#include <linux/kvm_host.h>
+#endif
#ifdef CONFIG_PPC64
#include <linux/time.h>
#include <linux/hardirq.h>
@@ -93,10 +96,7 @@ int main(void)
DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_TASK, offsetof(struct thread_info, task));
-#ifdef CONFIG_PPC32
- DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
-#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size));
@@ -165,13 +165,9 @@ int main(void)
/* Interrupt register frame */
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-#ifndef CONFIG_PPC64
- DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
-#else /* CONFIG_PPC64 */
+ DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE);
+#ifdef CONFIG_PPC64
DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
- /* 288 = # of volatile regs, int & fp, for leaf routines */
- /* which do not stack a frame. See the PPC64 ABI. */
- DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
@@ -331,5 +327,30 @@ int main(void)
DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
+#ifdef CONFIG_KVM
+ DEFINE(TLBE_BYTES, sizeof(struct tlbe));
+
+ DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
+ DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
+ DEFINE(VCPU_HOST_TLB, offsetof(struct kvm_vcpu, arch.host_tlb));
+ DEFINE(VCPU_SHADOW_TLB, offsetof(struct kvm_vcpu, arch.shadow_tlb));
+ DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
+ DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
+ DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
+ DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
+ DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
+ DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
+ DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
+ DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
+ DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
+ DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
+ DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
+ DEFINE(VCPU_PID, offsetof(struct kvm_vcpu, arch.pid));
+
+ DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
+ DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
+ DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
+#endif
+
return 0;
}
diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S
index 5465e8de0e61..e3623e3e3451 100644
--- a/arch/powerpc/kernel/cpu_setup_44x.S
+++ b/arch/powerpc/kernel/cpu_setup_44x.S
@@ -33,7 +33,6 @@ _GLOBAL(__setup_cpu_440grx)
mtlr r4
blr
_GLOBAL(__setup_cpu_460ex)
-_GLOBAL(__setup_cpu_460gt)
b __init_fpu_44x
_GLOBAL(__setup_cpu_440gx)
_GLOBAL(__setup_cpu_440spe)
diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
index f1ee0b3f78f2..72d1d7395254 100644
--- a/arch/powerpc/kernel/cpu_setup_6xx.S
+++ b/arch/powerpc/kernel/cpu_setup_6xx.S
@@ -17,7 +17,13 @@
#include <asm/cache.h>
_GLOBAL(__setup_cpu_603)
- b setup_common_caches
+ mflr r4
+BEGIN_FTR_SECTION
+ bl __init_fpu_registers
+END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE)
+ bl setup_common_caches
+ mtlr r4
+ blr
_GLOBAL(__setup_cpu_604)
mflr r4
bl setup_common_caches
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 26ffb44e2701..36080d4d1922 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -37,7 +37,6 @@ extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec);
-extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
@@ -1416,10 +1415,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pvr_value = 0x13020000,
.cpu_name = "460GT",
.cpu_features = CPU_FTRS_44X,
- .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+ .cpu_user_features = COMMON_USER_BOOKE,
.icache_bsize = 32,
.dcache_bsize = 32,
- .cpu_setup = __setup_cpu_460gt,
.machine_check = machine_check_440A,
.platform = "ppc440",
},
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 4ff744143566..e581524d85bc 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -371,6 +371,17 @@ skpinv: addi r6,r6,1 /* Increment */
bl early_init
+#ifdef CONFIG_RELOCATABLE
+ lis r3,kernstart_addr@ha
+ la r3,kernstart_addr@l(r3)
+#ifdef CONFIG_PHYS_64BIT
+ stw r23,0(r3)
+ stw r25,4(r3)
+#else
+ stw r25,0(r3)
+#endif
+#endif
+
mfspr r3,SPRN_TLB1CFG
andi. r3,r3,0xfff
lis r4,num_tlbcam_entries@ha
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 9d2c56621f1e..92ccc6fcc5b0 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -152,7 +152,7 @@ _GLOBAL(low_choose_750fx_pll)
mtspr SPRN_HID1,r4
/* Store new HID1 image */
- rlwinm r6,r1,0,0,18
+ rlwinm r6,r1,0,0,(31-THREAD_SHIFT)
lwz r6,TI_CPU(r6)
slwi r6,r6,2
addis r6,r6,nap_save_hid1@ha
@@ -281,7 +281,7 @@ _GLOBAL(_tlbia)
#endif /* CONFIG_SMP */
#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
#if defined(CONFIG_SMP)
- rlwinm r8,r1,0,0,18
+ rlwinm r8,r1,0,0,(31-THREAD_SHIFT)
lwz r8,TI_CPU(r8)
oris r8,r8,10
mfmsr r10
@@ -377,7 +377,7 @@ _GLOBAL(_tlbie)
#endif /* CONFIG_SMP */
#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
#if defined(CONFIG_SMP)
- rlwinm r8,r1,0,0,18
+ rlwinm r8,r1,0,0,(31-THREAD_SHIFT)
lwz r8,TI_CPU(r8)
oris r8,r8,11
mfmsr r10
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index a3c491e88a72..942951e76586 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -27,23 +27,11 @@
.text
-_GLOBAL(get_msr)
- mfmsr r3
- blr
-
-_GLOBAL(get_srr0)
- mfsrr0 r3
- blr
-
-_GLOBAL(get_srr1)
- mfsrr1 r3
- blr
-
#ifdef CONFIG_IRQSTACKS
_GLOBAL(call_do_softirq)
mflr r0
std r0,16(r1)
- stdu r1,THREAD_SIZE-112(r3)
+ stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
mr r1,r3
bl .__do_softirq
ld r1,0(r1)
@@ -56,7 +44,7 @@ _GLOBAL(call_handle_irq)
mflr r0
std r0,16(r1)
mtctr r8
- stdu r1,THREAD_SIZE-112(r5)
+ stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
mr r1,r5
bctrl
ld r1,0(r1)
@@ -599,7 +587,7 @@ _GLOBAL(kexec_sequence)
std r0,16(r1)
/* switch stacks to newstack -- &kexec_stack.stack */
- stdu r1,THREAD_SIZE-112(r3)
+ stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
mr r1,r3
li r0,0
@@ -616,7 +604,7 @@ _GLOBAL(kexec_sequence)
std r26,-48(r1)
std r25,-56(r1)
- stdu r1,-112-64(r1)
+ stdu r1,-STACK_FRAME_OVERHEAD-64(r1)
/* save args into preserved regs */
mr r31,r3 /* newstack (both) */
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index fb698d47082d..e79ad8afda07 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -275,6 +275,8 @@ static int __devinit of_pci_phb_probe(struct of_device *dev,
/* Scan the bus */
scan_phb(phb);
+ if (phb->bus == NULL)
+ return -ENXIO;
/* Claim resources. This might need some rework as well depending
* wether we are doing probe-only or not, like assigning unassigned
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index ac163bd46cfd..c9bf17eec31b 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -7,17 +7,11 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/types.h>
#include <linux/threads.h>
#include <linux/module.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/page.h>
#include <asm/lppaca.h>
#include <asm/paca.h>
-#include <asm/mmu.h>
-
/* This symbol is provided by the linker - let it fill in the paca
* field correctly */
@@ -65,60 +59,29 @@ struct slb_shadow slb_shadow[] __cacheline_aligned = {
* processors. The processor VPD array needs one entry per physical
* processor (not thread).
*/
-#define PACA_INIT(number) \
-{ \
- .lppaca_ptr = &lppaca[number], \
- .lock_token = 0x8000, \
- .paca_index = (number), /* Paca Index */ \
- .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \
- .hw_cpu_id = 0xffff, \
- .slb_shadow_ptr = &slb_shadow[number], \
- .__current = &init_task, \
-}
-
-struct paca_struct paca[] = {
- PACA_INIT(0),
-#if NR_CPUS > 1
- PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3),
-#if NR_CPUS > 4
- PACA_INIT( 4), PACA_INIT( 5), PACA_INIT( 6), PACA_INIT( 7),
-#if NR_CPUS > 8
- PACA_INIT( 8), PACA_INIT( 9), PACA_INIT( 10), PACA_INIT( 11),
- PACA_INIT( 12), PACA_INIT( 13), PACA_INIT( 14), PACA_INIT( 15),
- PACA_INIT( 16), PACA_INIT( 17), PACA_INIT( 18), PACA_INIT( 19),
- PACA_INIT( 20), PACA_INIT( 21), PACA_INIT( 22), PACA_INIT( 23),
- PACA_INIT( 24), PACA_INIT( 25), PACA_INIT( 26), PACA_INIT( 27),
- PACA_INIT( 28), PACA_INIT( 29), PACA_INIT( 30), PACA_INIT( 31),
-#if NR_CPUS > 32
- PACA_INIT( 32), PACA_INIT( 33), PACA_INIT( 34), PACA_INIT( 35),
- PACA_INIT( 36), PACA_INIT( 37), PACA_INIT( 38), PACA_INIT( 39),
- PACA_INIT( 40), PACA_INIT( 41), PACA_INIT( 42), PACA_INIT( 43),
- PACA_INIT( 44), PACA_INIT( 45), PACA_INIT( 46), PACA_INIT( 47),
- PACA_INIT( 48), PACA_INIT( 49), PACA_INIT( 50), PACA_INIT( 51),
- PACA_INIT( 52), PACA_INIT( 53), PACA_INIT( 54), PACA_INIT( 55),
- PACA_INIT( 56), PACA_INIT( 57), PACA_INIT( 58), PACA_INIT( 59),
- PACA_INIT( 60), PACA_INIT( 61), PACA_INIT( 62), PACA_INIT( 63),
-#if NR_CPUS > 64
- PACA_INIT( 64), PACA_INIT( 65), PACA_INIT( 66), PACA_INIT( 67),
- PACA_INIT( 68), PACA_INIT( 69), PACA_INIT( 70), PACA_INIT( 71),
- PACA_INIT( 72), PACA_INIT( 73), PACA_INIT( 74), PACA_INIT( 75),
- PACA_INIT( 76), PACA_INIT( 77), PACA_INIT( 78), PACA_INIT( 79),
- PACA_INIT( 80), PACA_INIT( 81), PACA_INIT( 82), PACA_INIT( 83),
- PACA_INIT( 84), PACA_INIT( 85), PACA_INIT( 86), PACA_INIT( 87),
- PACA_INIT( 88), PACA_INIT( 89), PACA_INIT( 90), PACA_INIT( 91),
- PACA_INIT( 92), PACA_INIT( 93), PACA_INIT( 94), PACA_INIT( 95),
- PACA_INIT( 96), PACA_INIT( 97), PACA_INIT( 98), PACA_INIT( 99),
- PACA_INIT(100), PACA_INIT(101), PACA_INIT(102), PACA_INIT(103),
- PACA_INIT(104), PACA_INIT(105), PACA_INIT(106), PACA_INIT(107),
- PACA_INIT(108), PACA_INIT(109), PACA_INIT(110), PACA_INIT(111),
- PACA_INIT(112), PACA_INIT(113), PACA_INIT(114), PACA_INIT(115),
- PACA_INIT(116), PACA_INIT(117), PACA_INIT(118), PACA_INIT(119),
- PACA_INIT(120), PACA_INIT(121), PACA_INIT(122), PACA_INIT(123),
- PACA_INIT(124), PACA_INIT(125), PACA_INIT(126), PACA_INIT(127),
-#endif
-#endif
-#endif
-#endif
-#endif
-};
+struct paca_struct paca[NR_CPUS];
EXPORT_SYMBOL(paca);
+
+void __init initialise_pacas(void)
+{
+ int cpu;
+
+ /* The TOC register (GPR2) points 32kB into the TOC, so that 64kB
+ * of the TOC can be addressed using a single machine instruction.
+ */
+ unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL;
+
+ /* Can't use for_each_*_cpu, as they aren't functional yet */
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ struct paca_struct *new_paca = &paca[cpu];
+
+ new_paca->lppaca_ptr = &lppaca[cpu];
+ new_paca->lock_token = 0x8000;
+ new_paca->paca_index = cpu;
+ new_paca->kernel_toc = kernel_toc;
+ new_paca->hw_cpu_id = 0xffff;
+ new_paca->slb_shadow_ptr = &slb_shadow[cpu];
+ new_paca->__current = &init_task;
+
+ }
+}
diff --git a/arch/powerpc/kernel/ppc32.h b/arch/powerpc/kernel/ppc32.h
index fda05e2211d6..90e562771791 100644
--- a/arch/powerpc/kernel/ppc32.h
+++ b/arch/powerpc/kernel/ppc32.h
@@ -135,6 +135,4 @@ struct ucontext32 {
struct mcontext32 uc_mcontext;
};
-extern int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s);
-
#endif /* _PPC64_PPC32_H */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 703100d5e458..6caad17ea72e 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1033,3 +1033,34 @@ void ppc64_runlatch_off(void)
}
}
#endif
+
+#if THREAD_SHIFT < PAGE_SHIFT
+
+static struct kmem_cache *thread_info_cache;
+
+struct thread_info *alloc_thread_info(struct task_struct *tsk)
+{
+ struct thread_info *ti;
+
+ ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL);
+ if (unlikely(ti == NULL))
+ return NULL;
+#ifdef CONFIG_DEBUG_STACK_USAGE
+ memset(ti, 0, THREAD_SIZE);
+#endif
+ return ti;
+}
+
+void free_thread_info(struct thread_info *ti)
+{
+ kmem_cache_free(thread_info_cache, ti);
+}
+
+void thread_info_cache_init(void)
+{
+ thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE,
+ THREAD_SIZE, 0, NULL);
+ BUG_ON(thread_info_cache == NULL);
+}
+
+#endif /* THREAD_SHIFT < PAGE_SHIFT */
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3bfe7837e820..2aefe2a4129a 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -53,6 +53,7 @@
#include <asm/pci-bridge.h>
#include <asm/phyp_dump.h>
#include <asm/kexec.h>
+#include <mm/mmu_decl.h>
#ifdef DEBUG
#define DBG(fmt...) printk(KERN_ERR fmt)
@@ -978,7 +979,10 @@ static int __init early_init_dt_scan_memory(unsigned long node,
}
#endif
lmb_add(base, size);
+
+ memstart_addr = min((u64)memstart_addr, base);
}
+
return 0;
}
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh
new file mode 100644
index 000000000000..8e24fc1821e8
--- /dev/null
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# Copyright © 2008 IBM Corporation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+
+# This script checks prom_init.o to see what external symbols it
+# is using, if it finds symbols not in the whitelist it returns
+# an error. The point of this is to discourage people from
+# intentionally or accidentally adding new code to prom_init.c
+# which has side effects on other parts of the kernel.
+
+# If you really need to reference something from prom_init.o add
+# it to the list below:
+
+WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush
+_end enter_prom memcpy memset reloc_offset __secondary_hold
+__secondary_hold_acknowledge __secondary_hold_spinloop __start
+strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224
+reloc_got2"
+
+NM="$1"
+OBJ="$2"
+
+ERROR=0
+
+for UNDEF in $($NM -u $OBJ | awk '{print $2}')
+do
+ # On 64-bit nm gives us the function descriptors, which have
+ # a leading . on the name, so strip it off here.
+ UNDEF="${UNDEF#.}"
+
+ if [ $KBUILD_VERBOSE ]; then
+ if [ $KBUILD_VERBOSE -ne 0 ]; then
+ echo "Checking prom_init.o symbol '$UNDEF'"
+ fi
+ fi
+
+ OK=0
+ for WHITE in $WHITELIST
+ do
+ if [ "$UNDEF" = "$WHITE" ]; then
+ OK=1
+ break
+ fi
+ done
+
+ if [ $OK -eq 0 ]; then
+ ERROR=1
+ echo "Error: External symbol '$UNDEF' referenced" \
+ "from prom_init.c" >&2
+ fi
+done
+
+exit $ERROR
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 9d30e10970ac..4c1de6af4c09 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -29,15 +29,12 @@
#include <linux/security.h>
#include <linux/signal.h>
#include <linux/compat.h>
-#include <linux/elf.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include "ppc32.h"
-
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
@@ -67,27 +64,6 @@ static long compat_ptrace_old(struct task_struct *child, long request,
return -EPERM;
}
-static int compat_ptrace_getsiginfo(struct task_struct *child, compat_siginfo_t __user *data)
-{
- siginfo_t lastinfo;
- int error = -ESRCH;
-
- read_lock(&tasklist_lock);
- if (likely(child->sighand != NULL)) {
- error = -EINVAL;
- spin_lock_irq(&child->sighand->siglock);
- if (likely(child->last_siginfo != NULL)) {
- lastinfo = *child->last_siginfo;
- error = 0;
- }
- spin_unlock_irq(&child->sighand->siglock);
- }
- read_unlock(&tasklist_lock);
- if (!error)
- return copy_siginfo_to_user32(data, &lastinfo);
- return error;
-}
-
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata)
{
@@ -306,9 +282,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
0, PT_REGS_COUNT * sizeof(compat_long_t),
compat_ptr(data));
- case PTRACE_GETSIGINFO:
- return compat_ptrace_getsiginfo(child, compat_ptr(data));
-
case PTRACE_GETFPREGS:
case PTRACE_SETFPREGS:
case PTRACE_GETVRREGS:
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 31ada9fdfc5c..dff6308d1b5e 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -170,6 +170,9 @@ void __init setup_paca(int cpu)
void __init early_setup(unsigned long dt_ptr)
{
+ /* Fill in any unititialised pacas */
+ initialise_pacas();
+
/* Identify CPU type */
identify_cpu(0, mfspr(SPRN_PVR));
@@ -435,7 +438,7 @@ void __init setup_system(void)
printk("htab_address = 0x%p\n", htab_address);
printk("htab_hash_mask = 0x%lx\n", htab_hash_mask);
#if PHYSICAL_START > 0
- printk("physical_start = 0x%x\n", PHYSICAL_START);
+ printk("physical_start = 0x%lx\n", PHYSICAL_START);
#endif
printk("-----------------------------------------------------\n");
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c
index e3638eeaaae7..962944038430 100644
--- a/arch/powerpc/kernel/stacktrace.c
+++ b/arch/powerpc/kernel/stacktrace.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/stacktrace.h>
#include <asm/ptrace.h>
-#include <asm/asm-offsets.h>
/*
* Save stack-backtrace addresses into a stack_trace buffer.
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 7aad6203e411..7d6c9bb8c77f 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -154,8 +154,8 @@ static void udbg_console_write(struct console *con, const char *s,
static struct console udbg_console = {
.name = "udbg",
.write = udbg_console_write,
- .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT,
- .index = -1,
+ .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
+ .index = 0,
};
static int early_console_initialized;
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
new file mode 100644
index 000000000000..f5d7a5eab96e
--- /dev/null
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -0,0 +1,224 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kvm_host.h>
+#include <linux/highmem.h>
+#include <asm/mmu-44x.h>
+#include <asm/kvm_ppc.h>
+
+#include "44x_tlb.h"
+
+#define PPC44x_TLB_USER_PERM_MASK (PPC44x_TLB_UX|PPC44x_TLB_UR|PPC44x_TLB_UW)
+#define PPC44x_TLB_SUPER_PERM_MASK (PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW)
+
+static unsigned int kvmppc_tlb_44x_pos;
+
+static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode)
+{
+ /* Mask off reserved bits. */
+ attrib &= PPC44x_TLB_PERM_MASK|PPC44x_TLB_ATTR_MASK;
+
+ if (!usermode) {
+ /* Guest is in supervisor mode, so we need to translate guest
+ * supervisor permissions into user permissions. */
+ attrib &= ~PPC44x_TLB_USER_PERM_MASK;
+ attrib |= (attrib & PPC44x_TLB_SUPER_PERM_MASK) << 3;
+ }
+
+ /* Make sure host can always access this memory. */
+ attrib |= PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW;
+
+ return attrib;
+}
+
+/* Search the guest TLB for a matching entry. */
+int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
+ unsigned int as)
+{
+ int i;
+
+ /* XXX Replace loop with fancy data structures. */
+ for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+ struct tlbe *tlbe = &vcpu->arch.guest_tlb[i];
+ unsigned int tid;
+
+ if (eaddr < get_tlb_eaddr(tlbe))
+ continue;
+
+ if (eaddr > get_tlb_end(tlbe))
+ continue;
+
+ tid = get_tlb_tid(tlbe);
+ if (tid && (tid != pid))
+ continue;
+
+ if (!get_tlb_v(tlbe))
+ continue;
+
+ if (get_tlb_ts(tlbe) != as)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
+{
+ unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+ unsigned int index;
+
+ index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
+ if (index == -1)
+ return NULL;
+ return &vcpu->arch.guest_tlb[index];
+}
+
+struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
+{
+ unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+ unsigned int index;
+
+ index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
+ if (index == -1)
+ return NULL;
+ return &vcpu->arch.guest_tlb[index];
+}
+
+static int kvmppc_44x_tlbe_is_writable(struct tlbe *tlbe)
+{
+ return tlbe->word2 & (PPC44x_TLB_SW|PPC44x_TLB_UW);
+}
+
+/* Must be called with mmap_sem locked for writing. */
+static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu,
+ unsigned int index)
+{
+ struct tlbe *stlbe = &vcpu->arch.shadow_tlb[index];
+ struct page *page = vcpu->arch.shadow_pages[index];
+
+ kunmap(vcpu->arch.shadow_pages[index]);
+
+ if (get_tlb_v(stlbe)) {
+ if (kvmppc_44x_tlbe_is_writable(stlbe))
+ kvm_release_page_dirty(page);
+ else
+ kvm_release_page_clean(page);
+ }
+}
+
+/* Caller must ensure that the specified guest TLB entry is safe to insert into
+ * the shadow TLB. */
+void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
+ u32 flags)
+{
+ struct page *new_page;
+ struct tlbe *stlbe;
+ hpa_t hpaddr;
+ unsigned int victim;
+
+ /* Future optimization: don't overwrite the TLB entry containing the
+ * current PC (or stack?). */
+ victim = kvmppc_tlb_44x_pos++;
+ if (kvmppc_tlb_44x_pos > tlb_44x_hwater)
+ kvmppc_tlb_44x_pos = 0;
+ stlbe = &vcpu->arch.shadow_tlb[victim];
+
+ /* Get reference to new page. */
+ down_write(&current->mm->mmap_sem);
+ new_page = gfn_to_page(vcpu->kvm, gfn);
+ if (is_error_page(new_page)) {
+ printk(KERN_ERR "Couldn't get guest page!\n");
+ kvm_release_page_clean(new_page);
+ return;
+ }
+ hpaddr = page_to_phys(new_page);
+
+ /* Drop reference to old page. */
+ kvmppc_44x_shadow_release(vcpu, victim);
+ up_write(&current->mm->mmap_sem);
+
+ vcpu->arch.shadow_pages[victim] = new_page;
+
+ /* XXX Make sure (va, size) doesn't overlap any other
+ * entries. 440x6 user manual says the result would be
+ * "undefined." */
+
+ /* XXX what about AS? */
+
+ stlbe->tid = asid & 0xff;
+
+ /* Force TS=1 for all guest mappings. */
+ /* For now we hardcode 4KB mappings, but it will be important to
+ * use host large pages in the future. */
+ stlbe->word0 = (gvaddr & PAGE_MASK) | PPC44x_TLB_VALID | PPC44x_TLB_TS
+ | PPC44x_TLB_4K;
+
+ stlbe->word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
+ stlbe->word2 = kvmppc_44x_tlb_shadow_attrib(flags,
+ vcpu->arch.msr & MSR_PR);
+}
+
+void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
+{
+ unsigned int pid = asid & 0xff;
+ int i;
+
+ /* XXX Replace loop with fancy data structures. */
+ down_write(&current->mm->mmap_sem);
+ for (i = 0; i <= tlb_44x_hwater; i++) {
+ struct tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
+ unsigned int tid;
+
+ if (!get_tlb_v(stlbe))
+ continue;
+
+ if (eaddr < get_tlb_eaddr(stlbe))
+ continue;
+
+ if (eaddr > get_tlb_end(stlbe))
+ continue;
+
+ tid = get_tlb_tid(stlbe);
+ if (tid && (tid != pid))
+ continue;
+
+ kvmppc_44x_shadow_release(vcpu, i);
+ stlbe->word0 = 0;
+ }
+ up_write(&current->mm->mmap_sem);
+}
+
+/* Invalidate all mappings, so that when they fault back in they will get the
+ * proper permission bits. */
+void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode)
+{
+ int i;
+
+ /* XXX Replace loop with fancy data structures. */
+ down_write(&current->mm->mmap_sem);
+ for (i = 0; i <= tlb_44x_hwater; i++) {
+ kvmppc_44x_shadow_release(vcpu, i);
+ vcpu->arch.shadow_tlb[i].word0 = 0;
+ }
+ up_write(&current->mm->mmap_sem);
+}
diff --git a/arch/powerpc/kvm/44x_tlb.h b/arch/powerpc/kvm/44x_tlb.h
new file mode 100644
index 000000000000..2ccd46b6f6b7
--- /dev/null
+++ b/arch/powerpc/kvm/44x_tlb.h
@@ -0,0 +1,91 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __KVM_POWERPC_TLB_H__
+#define __KVM_POWERPC_TLB_H__
+
+#include <linux/kvm_host.h>
+#include <asm/mmu-44x.h>
+
+extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr,
+ unsigned int pid, unsigned int as);
+extern struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr);
+extern struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr);
+
+/* TLB helper functions */
+static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
+{
+ return (tlbe->word0 >> 4) & 0xf;
+}
+
+static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
+{
+ return tlbe->word0 & 0xfffffc00;
+}
+
+static inline gva_t get_tlb_bytes(const struct tlbe *tlbe)
+{
+ unsigned int pgsize = get_tlb_size(tlbe);
+ return 1 << 10 << (pgsize << 1);
+}
+
+static inline gva_t get_tlb_end(const struct tlbe *tlbe)
+{
+ return get_tlb_eaddr(tlbe) + get_tlb_bytes(tlbe) - 1;
+}
+
+static inline u64 get_tlb_raddr(const struct tlbe *tlbe)
+{
+ u64 word1 = tlbe->word1;
+ return ((word1 & 0xf) << 32) | (word1 & 0xfffffc00);
+}
+
+static inline unsigned int get_tlb_tid(const struct tlbe *tlbe)
+{
+ return tlbe->tid & 0xff;
+}
+
+static inline unsigned int get_tlb_ts(const struct tlbe *tlbe)
+{
+ return (tlbe->word0 >> 8) & 0x1;
+}
+
+static inline unsigned int get_tlb_v(const struct tlbe *tlbe)
+{
+ return (tlbe->word0 >> 9) & 0x1;
+}
+
+static inline unsigned int get_mmucr_stid(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.mmucr & 0xff;
+}
+
+static inline unsigned int get_mmucr_sts(const struct kvm_vcpu *vcpu)
+{
+ return (vcpu->arch.mmucr >> 16) & 0x1;
+}
+
+static inline gpa_t tlb_xlate(struct tlbe *tlbe, gva_t eaddr)
+{
+ unsigned int pgmask = get_tlb_bytes(tlbe) - 1;
+
+ return get_tlb_raddr(tlbe) | (eaddr & pgmask);
+}
+
+#endif /* __KVM_POWERPC_TLB_H__ */
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
new file mode 100644
index 000000000000..6b076010213b
--- /dev/null
+++ b/arch/powerpc/kvm/Kconfig
@@ -0,0 +1,42 @@
+#
+# KVM configuration
+#
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ ---help---
+ Say Y here to get to see options for using your Linux host to run
+ other operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ bool "Kernel-based Virtual Machine (KVM) support"
+ depends on 44x && EXPERIMENTAL
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ # We can only run on Book E hosts so far
+ select KVM_BOOKE_HOST
+ ---help---
+ Support hosting virtualized guest machines. You will also
+ need to select one or more of the processor modules below.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ If unsure, say N.
+
+config KVM_BOOKE_HOST
+ bool "KVM host support for Book E PowerPC processors"
+ depends on KVM && 44x
+ ---help---
+ Provides host support for KVM on Book E PowerPC processors. Currently
+ this works on 440 processors only.
+
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
new file mode 100644
index 000000000000..d0d358d367ec
--- /dev/null
+++ b/arch/powerpc/kvm/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
+
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
+
+kvm-objs := $(common-objs) powerpc.o emulate.o booke_guest.o
+obj-$(CONFIG_KVM) += kvm.o
+
+AFLAGS_booke_interrupts.o := -I$(obj)
+
+kvm-booke-host-objs := booke_host.o booke_interrupts.o 44x_tlb.o
+obj-$(CONFIG_KVM_BOOKE_HOST) += kvm-booke-host.o
diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c
new file mode 100644
index 000000000000..6d9884a6884a
--- /dev/null
+++ b/arch/powerpc/kvm/booke_guest.c
@@ -0,0 +1,615 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <asm/cputable.h>
+#include <asm/uaccess.h>
+#include <asm/kvm_ppc.h>
+
+#include "44x_tlb.h"
+
+#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
+#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+ { "exits", VCPU_STAT(sum_exits) },
+ { "mmio", VCPU_STAT(mmio_exits) },
+ { "dcr", VCPU_STAT(dcr_exits) },
+ { "sig", VCPU_STAT(signal_exits) },
+ { "light", VCPU_STAT(light_exits) },
+ { "itlb_r", VCPU_STAT(itlb_real_miss_exits) },
+ { "itlb_v", VCPU_STAT(itlb_virt_miss_exits) },
+ { "dtlb_r", VCPU_STAT(dtlb_real_miss_exits) },
+ { "dtlb_v", VCPU_STAT(dtlb_virt_miss_exits) },
+ { "sysc", VCPU_STAT(syscall_exits) },
+ { "isi", VCPU_STAT(isi_exits) },
+ { "dsi", VCPU_STAT(dsi_exits) },
+ { "inst_emu", VCPU_STAT(emulated_inst_exits) },
+ { "dec", VCPU_STAT(dec_exits) },
+ { "ext_intr", VCPU_STAT(ext_intr_exits) },
+ { NULL }
+};
+
+static const u32 interrupt_msr_mask[16] = {
+ [BOOKE_INTERRUPT_CRITICAL] = MSR_ME,
+ [BOOKE_INTERRUPT_MACHINE_CHECK] = 0,
+ [BOOKE_INTERRUPT_DATA_STORAGE] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_INST_STORAGE] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_EXTERNAL] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_ALIGNMENT] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_PROGRAM] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_FP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_SYSCALL] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_AP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_DECREMENTER] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_FIT] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_WATCHDOG] = MSR_ME,
+ [BOOKE_INTERRUPT_DTLB_MISS] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_ITLB_MISS] = MSR_CE|MSR_ME|MSR_DE,
+ [BOOKE_INTERRUPT_DEBUG] = MSR_ME,
+};
+
+const unsigned char exception_priority[] = {
+ [BOOKE_INTERRUPT_DATA_STORAGE] = 0,
+ [BOOKE_INTERRUPT_INST_STORAGE] = 1,
+ [BOOKE_INTERRUPT_ALIGNMENT] = 2,
+ [BOOKE_INTERRUPT_PROGRAM] = 3,
+ [BOOKE_INTERRUPT_FP_UNAVAIL] = 4,
+ [BOOKE_INTERRUPT_SYSCALL] = 5,
+ [BOOKE_INTERRUPT_AP_UNAVAIL] = 6,
+ [BOOKE_INTERRUPT_DTLB_MISS] = 7,
+ [BOOKE_INTERRUPT_ITLB_MISS] = 8,
+ [BOOKE_INTERRUPT_MACHINE_CHECK] = 9,
+ [BOOKE_INTERRUPT_DEBUG] = 10,
+ [BOOKE_INTERRUPT_CRITICAL] = 11,
+ [BOOKE_INTERRUPT_WATCHDOG] = 12,
+ [BOOKE_INTERRUPT_EXTERNAL] = 13,
+ [BOOKE_INTERRUPT_FIT] = 14,
+ [BOOKE_INTERRUPT_DECREMENTER] = 15,
+};
+
+const unsigned char priority_exception[] = {
+ BOOKE_INTERRUPT_DATA_STORAGE,
+ BOOKE_INTERRUPT_INST_STORAGE,
+ BOOKE_INTERRUPT_ALIGNMENT,
+ BOOKE_INTERRUPT_PROGRAM,
+ BOOKE_INTERRUPT_FP_UNAVAIL,
+ BOOKE_INTERRUPT_SYSCALL,
+ BOOKE_INTERRUPT_AP_UNAVAIL,
+ BOOKE_INTERRUPT_DTLB_MISS,
+ BOOKE_INTERRUPT_ITLB_MISS,
+ BOOKE_INTERRUPT_MACHINE_CHECK,
+ BOOKE_INTERRUPT_DEBUG,
+ BOOKE_INTERRUPT_CRITICAL,
+ BOOKE_INTERRUPT_WATCHDOG,
+ BOOKE_INTERRUPT_EXTERNAL,
+ BOOKE_INTERRUPT_FIT,
+ BOOKE_INTERRUPT_DECREMENTER,
+};
+
+
+void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
+{
+ struct tlbe *tlbe;
+ int i;
+
+ printk("vcpu %d TLB dump:\n", vcpu->vcpu_id);
+ printk("| %2s | %3s | %8s | %8s | %8s |\n",
+ "nr", "tid", "word0", "word1", "word2");
+
+ for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+ tlbe = &vcpu->arch.guest_tlb[i];
+ if (tlbe->word0 & PPC44x_TLB_VALID)
+ printk(" G%2d | %02X | %08X | %08X | %08X |\n",
+ i, tlbe->tid, tlbe->word0, tlbe->word1,
+ tlbe->word2);
+ }
+
+ for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+ tlbe = &vcpu->arch.shadow_tlb[i];
+ if (tlbe->word0 & PPC44x_TLB_VALID)
+ printk(" S%2d | %02X | %08X | %08X | %08X |\n",
+ i, tlbe->tid, tlbe->word0, tlbe->word1,
+ tlbe->word2);
+ }
+}
+
+/* TODO: use vcpu_printf() */
+void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ printk("pc: %08x msr: %08x\n", vcpu->arch.pc, vcpu->arch.msr);
+ printk("lr: %08x ctr: %08x\n", vcpu->arch.lr, vcpu->arch.ctr);
+ printk("srr0: %08x srr1: %08x\n", vcpu->arch.srr0, vcpu->arch.srr1);
+
+ printk("exceptions: %08lx\n", vcpu->arch.pending_exceptions);
+
+ for (i = 0; i < 32; i += 4) {
+ printk("gpr%02d: %08x %08x %08x %08x\n", i,
+ vcpu->arch.gpr[i],
+ vcpu->arch.gpr[i+1],
+ vcpu->arch.gpr[i+2],
+ vcpu->arch.gpr[i+3]);
+ }
+}
+
+/* Check if we are ready to deliver the interrupt */
+static int kvmppc_can_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt)
+{
+ int r;
+
+ switch (interrupt) {
+ case BOOKE_INTERRUPT_CRITICAL:
+ r = vcpu->arch.msr & MSR_CE;
+ break;
+ case BOOKE_INTERRUPT_MACHINE_CHECK:
+ r = vcpu->arch.msr & MSR_ME;
+ break;
+ case BOOKE_INTERRUPT_EXTERNAL:
+ r = vcpu->arch.msr & MSR_EE;
+ break;
+ case BOOKE_INTERRUPT_DECREMENTER:
+ r = vcpu->arch.msr & MSR_EE;
+ break;
+ case BOOKE_INTERRUPT_FIT:
+ r = vcpu->arch.msr & MSR_EE;
+ break;
+ case BOOKE_INTERRUPT_WATCHDOG:
+ r = vcpu->arch.msr & MSR_CE;
+ break;
+ case BOOKE_INTERRUPT_DEBUG:
+ r = vcpu->arch.msr & MSR_DE;
+ break;
+ default:
+ r = 1;
+ }
+
+ return r;
+}
+
+static void kvmppc_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt)
+{
+ switch (interrupt) {
+ case BOOKE_INTERRUPT_DECREMENTER:
+ vcpu->arch.tsr |= TSR_DIS;
+ break;
+ }
+
+ vcpu->arch.srr0 = vcpu->arch.pc;
+ vcpu->arch.srr1 = vcpu->arch.msr;
+ vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[interrupt];
+ kvmppc_set_msr(vcpu, vcpu->arch.msr & interrupt_msr_mask[interrupt]);
+}
+
+/* Check pending exceptions and deliver one, if possible. */
+void kvmppc_check_and_deliver_interrupts(struct kvm_vcpu *vcpu)
+{
+ unsigned long *pending = &vcpu->arch.pending_exceptions;
+ unsigned int exception;
+ unsigned int priority;
+
+ priority = find_first_bit(pending, BITS_PER_BYTE * sizeof(*pending));
+ while (priority <= BOOKE_MAX_INTERRUPT) {
+ exception = priority_exception[priority];
+ if (kvmppc_can_deliver_interrupt(vcpu, exception)) {
+ kvmppc_clear_exception(vcpu, exception);
+ kvmppc_deliver_interrupt(vcpu, exception);
+ break;
+ }
+
+ priority = find_next_bit(pending,
+ BITS_PER_BYTE * sizeof(*pending),
+ priority + 1);
+ }
+}
+
+static int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+ enum emulation_result er;
+ int r;
+
+ er = kvmppc_emulate_instruction(run, vcpu);
+ switch (er) {
+ case EMULATE_DONE:
+ /* Future optimization: only reload non-volatiles if they were
+ * actually modified. */
+ r = RESUME_GUEST_NV;
+ break;
+ case EMULATE_DO_MMIO:
+ run->exit_reason = KVM_EXIT_MMIO;
+ /* We must reload nonvolatiles because "update" load/store
+ * instructions modify register state. */
+ /* Future optimization: only reload non-volatiles if they were
+ * actually modified. */
+ r = RESUME_HOST_NV;
+ break;
+ case EMULATE_FAIL:
+ /* XXX Deliver Program interrupt to guest. */
+ printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
+ vcpu->arch.last_inst);
+ r = RESUME_HOST;
+ break;
+ default:
+ BUG();
+ }
+
+ return r;
+}
+
+/**
+ * kvmppc_handle_exit
+ *
+ * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
+ */
+int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ unsigned int exit_nr)
+{
+ enum emulation_result er;
+ int r = RESUME_HOST;
+
+ local_irq_enable();
+
+ run->exit_reason = KVM_EXIT_UNKNOWN;
+ run->ready_for_interrupt_injection = 1;
+
+ switch (exit_nr) {
+ case BOOKE_INTERRUPT_MACHINE_CHECK:
+ printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR));
+ kvmppc_dump_vcpu(vcpu);
+ r = RESUME_HOST;
+ break;
+
+ case BOOKE_INTERRUPT_EXTERNAL:
+ case BOOKE_INTERRUPT_DECREMENTER:
+ /* Since we switched IVPR back to the host's value, the host
+ * handled this interrupt the moment we enabled interrupts.
+ * Now we just offer it a chance to reschedule the guest. */
+
+ /* XXX At this point the TLB still holds our shadow TLB, so if
+ * we do reschedule the host will fault over it. Perhaps we
+ * should politely restore the host's entries to minimize
+ * misses before ceding control. */
+ if (need_resched())
+ cond_resched();
+ if (exit_nr == BOOKE_INTERRUPT_DECREMENTER)
+ vcpu->stat.dec_exits++;
+ else
+ vcpu->stat.ext_intr_exits++;
+ r = RESUME_GUEST;
+ break;
+
+ case BOOKE_INTERRUPT_PROGRAM:
+ if (vcpu->arch.msr & MSR_PR) {
+ /* Program traps generated by user-level software must be handled
+ * by the guest kernel. */
+ vcpu->arch.esr = vcpu->arch.fault_esr;
+ kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM);
+ r = RESUME_GUEST;
+ break;
+ }
+
+ er = kvmppc_emulate_instruction(run, vcpu);
+ switch (er) {
+ case EMULATE_DONE:
+ /* Future optimization: only reload non-volatiles if
+ * they were actually modified by emulation. */
+ vcpu->stat.emulated_inst_exits++;
+ r = RESUME_GUEST_NV;
+ break;
+ case EMULATE_DO_DCR:
+ run->exit_reason = KVM_EXIT_DCR;
+ r = RESUME_HOST;
+ break;
+ case EMULATE_FAIL:
+ /* XXX Deliver Program interrupt to guest. */
+ printk(KERN_CRIT "%s: emulation at %x failed (%08x)\n",
+ __func__, vcpu->arch.pc, vcpu->arch.last_inst);
+ /* For debugging, encode the failing instruction and
+ * report it to userspace. */
+ run->hw.hardware_exit_reason = ~0ULL << 32;
+ run->hw.hardware_exit_reason |= vcpu->arch.last_inst;
+ r = RESUME_HOST;
+ break;
+ default:
+ BUG();
+ }
+ break;
+
+ case BOOKE_INTERRUPT_DATA_STORAGE:
+ vcpu->arch.dear = vcpu->arch.fault_dear;
+ vcpu->arch.esr = vcpu->arch.fault_esr;
+ kvmppc_queue_exception(vcpu, exit_nr);
+ vcpu->stat.dsi_exits++;
+ r = RESUME_GUEST;
+ break;
+
+ case BOOKE_INTERRUPT_INST_STORAGE:
+ vcpu->arch.esr = vcpu->arch.fault_esr;
+ kvmppc_queue_exception(vcpu, exit_nr);
+ vcpu->stat.isi_exits++;
+ r = RESUME_GUEST;
+ break;
+
+ case BOOKE_INTERRUPT_SYSCALL:
+ kvmppc_queue_exception(vcpu, exit_nr);
+ vcpu->stat.syscall_exits++;
+ r = RESUME_GUEST;
+ break;
+
+ case BOOKE_INTERRUPT_DTLB_MISS: {
+ struct tlbe *gtlbe;
+ unsigned long eaddr = vcpu->arch.fault_dear;
+ gfn_t gfn;
+
+ /* Check the guest TLB. */
+ gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr);
+ if (!gtlbe) {
+ /* The guest didn't have a mapping for it. */
+ kvmppc_queue_exception(vcpu, exit_nr);
+ vcpu->arch.dear = vcpu->arch.fault_dear;
+ vcpu->arch.esr = vcpu->arch.fault_esr;
+ vcpu->stat.dtlb_real_miss_exits++;
+ r = RESUME_GUEST;
+ break;
+ }
+
+ vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr);
+ gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT;
+
+ if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
+ /* The guest TLB had a mapping, but the shadow TLB
+ * didn't, and it is RAM. This could be because:
+ * a) the entry is mapping the host kernel, or
+ * b) the guest used a large mapping which we're faking
+ * Either way, we need to satisfy the fault without
+ * invoking the guest. */
+ kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
+ gtlbe->word2);
+ vcpu->stat.dtlb_virt_miss_exits++;
+ r = RESUME_GUEST;
+ } else {
+ /* Guest has mapped and accessed a page which is not
+ * actually RAM. */
+ r = kvmppc_emulate_mmio(run, vcpu);
+ }
+
+ break;
+ }
+
+ case BOOKE_INTERRUPT_ITLB_MISS: {
+ struct tlbe *gtlbe;
+ unsigned long eaddr = vcpu->arch.pc;
+ gfn_t gfn;
+
+ r = RESUME_GUEST;
+
+ /* Check the guest TLB. */
+ gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr);
+ if (!gtlbe) {
+ /* The guest didn't have a mapping for it. */
+ kvmppc_queue_exception(vcpu, exit_nr);
+ vcpu->stat.itlb_real_miss_exits++;
+ break;
+ }
+
+ vcpu->stat.itlb_virt_miss_exits++;
+
+ gfn = tlb_xlate(gtlbe, eaddr) >> PAGE_SHIFT;
+
+ if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
+ /* The guest TLB had a mapping, but the shadow TLB
+ * didn't. This could be because:
+ * a) the entry is mapping the host kernel, or
+ * b) the guest used a large mapping which we're faking
+ * Either way, we need to satisfy the fault without
+ * invoking the guest. */
+ kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
+ gtlbe->word2);
+ } else {
+ /* Guest mapped and leaped at non-RAM! */
+ kvmppc_queue_exception(vcpu,
+ BOOKE_INTERRUPT_MACHINE_CHECK);
+ }
+
+ break;
+ }
+
+ default:
+ printk(KERN_EMERG "exit_nr %d\n", exit_nr);
+ BUG();
+ }
+
+ local_irq_disable();
+
+ kvmppc_check_and_deliver_interrupts(vcpu);
+
+ /* Do some exit accounting. */
+ vcpu->stat.sum_exits++;
+ if (!(r & RESUME_HOST)) {
+ /* To avoid clobbering exit_reason, only check for signals if
+ * we aren't already exiting to userspace for some other
+ * reason. */
+ if (signal_pending(current)) {
+ run->exit_reason = KVM_EXIT_INTR;
+ r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
+
+ vcpu->stat.signal_exits++;
+ } else {
+ vcpu->stat.light_exits++;
+ }
+ } else {
+ switch (run->exit_reason) {
+ case KVM_EXIT_MMIO:
+ vcpu->stat.mmio_exits++;
+ break;
+ case KVM_EXIT_DCR:
+ vcpu->stat.dcr_exits++;
+ break;
+ case KVM_EXIT_INTR:
+ vcpu->stat.signal_exits++;
+ break;
+ }
+ }
+
+ return r;
+}
+
+/* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ struct tlbe *tlbe = &vcpu->arch.guest_tlb[0];
+
+ tlbe->tid = 0;
+ tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID;
+ tlbe->word1 = 0;
+ tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR;
+
+ tlbe++;
+ tlbe->tid = 0;
+ tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID;
+ tlbe->word1 = 0xef600000;
+ tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR
+ | PPC44x_TLB_I | PPC44x_TLB_G;
+
+ vcpu->arch.pc = 0;
+ vcpu->arch.msr = 0;
+ vcpu->arch.gpr[1] = (16<<20) - 8; /* -8 for the callee-save LR slot */
+
+ /* Eye-catching number so we know if the guest takes an interrupt
+ * before it's programmed its own IVPR. */
+ vcpu->arch.ivpr = 0x55550000;
+
+ /* Since the guest can directly access the timebase, it must know the
+ * real timebase frequency. Accordingly, it must see the state of
+ * CCR1[TCS]. */
+ vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ int i;
+
+ regs->pc = vcpu->arch.pc;
+ regs->cr = vcpu->arch.cr;
+ regs->ctr = vcpu->arch.ctr;
+ regs->lr = vcpu->arch.lr;
+ regs->xer = vcpu->arch.xer;
+ regs->msr = vcpu->arch.msr;
+ regs->srr0 = vcpu->arch.srr0;
+ regs->srr1 = vcpu->arch.srr1;
+ regs->pid = vcpu->arch.pid;
+ regs->sprg0 = vcpu->arch.sprg0;
+ regs->sprg1 = vcpu->arch.sprg1;
+ regs->sprg2 = vcpu->arch.sprg2;
+ regs->sprg3 = vcpu->arch.sprg3;
+ regs->sprg5 = vcpu->arch.sprg4;
+ regs->sprg6 = vcpu->arch.sprg5;
+ regs->sprg7 = vcpu->arch.sprg6;
+
+ for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
+ regs->gpr[i] = vcpu->arch.gpr[i];
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ int i;
+
+ vcpu->arch.pc = regs->pc;
+ vcpu->arch.cr = regs->cr;
+ vcpu->arch.ctr = regs->ctr;
+ vcpu->arch.lr = regs->lr;
+ vcpu->arch.xer = regs->xer;
+ vcpu->arch.msr = regs->msr;
+ vcpu->arch.srr0 = regs->srr0;
+ vcpu->arch.srr1 = regs->srr1;
+ vcpu->arch.sprg0 = regs->sprg0;
+ vcpu->arch.sprg1 = regs->sprg1;
+ vcpu->arch.sprg2 = regs->sprg2;
+ vcpu->arch.sprg3 = regs->sprg3;
+ vcpu->arch.sprg5 = regs->sprg4;
+ vcpu->arch.sprg6 = regs->sprg5;
+ vcpu->arch.sprg7 = regs->sprg6;
+
+ for (i = 0; i < ARRAY_SIZE(vcpu->arch.gpr); i++)
+ vcpu->arch.gpr[i] = regs->gpr[i];
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -ENOTSUPP;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -ENOTSUPP;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -ENOTSUPP;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -ENOTSUPP;
+}
+
+/* 'linear_address' is actually an encoding of AS|PID|EADDR . */
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ struct tlbe *gtlbe;
+ int index;
+ gva_t eaddr;
+ u8 pid;
+ u8 as;
+
+ eaddr = tr->linear_address;
+ pid = (tr->linear_address >> 32) & 0xff;
+ as = (tr->linear_address >> 40) & 0x1;
+
+ index = kvmppc_44x_tlb_index(vcpu, eaddr, pid, as);
+ if (index == -1) {
+ tr->valid = 0;
+ return 0;
+ }
+
+ gtlbe = &vcpu->arch.guest_tlb[index];
+
+ tr->physical_address = tlb_xlate(gtlbe, eaddr);
+ /* XXX what does "writeable" and "usermode" even mean? */
+ tr->valid = 1;
+
+ return 0;
+}
diff --git a/arch/powerpc/kvm/booke_host.c b/arch/powerpc/kvm/booke_host.c
new file mode 100644
index 000000000000..b480341bc31e
--- /dev/null
+++ b/arch/powerpc/kvm/booke_host.c
@@ -0,0 +1,83 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <asm/kvm_ppc.h>
+
+unsigned long kvmppc_booke_handlers;
+
+static int kvmppc_booke_init(void)
+{
+ unsigned long ivor[16];
+ unsigned long max_ivor = 0;
+ int i;
+
+ /* We install our own exception handlers by hijacking IVPR. IVPR must
+ * be 16-bit aligned, so we need a 64KB allocation. */
+ kvmppc_booke_handlers = __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ VCPU_SIZE_ORDER);
+ if (!kvmppc_booke_handlers)
+ return -ENOMEM;
+
+ /* XXX make sure our handlers are smaller than Linux's */
+
+ /* Copy our interrupt handlers to match host IVORs. That way we don't
+ * have to swap the IVORs on every guest/host transition. */
+ ivor[0] = mfspr(SPRN_IVOR0);
+ ivor[1] = mfspr(SPRN_IVOR1);
+ ivor[2] = mfspr(SPRN_IVOR2);
+ ivor[3] = mfspr(SPRN_IVOR3);
+ ivor[4] = mfspr(SPRN_IVOR4);
+ ivor[5] = mfspr(SPRN_IVOR5);
+ ivor[6] = mfspr(SPRN_IVOR6);
+ ivor[7] = mfspr(SPRN_IVOR7);
+ ivor[8] = mfspr(SPRN_IVOR8);
+ ivor[9] = mfspr(SPRN_IVOR9);
+ ivor[10] = mfspr(SPRN_IVOR10);
+ ivor[11] = mfspr(SPRN_IVOR11);
+ ivor[12] = mfspr(SPRN_IVOR12);
+ ivor[13] = mfspr(SPRN_IVOR13);
+ ivor[14] = mfspr(SPRN_IVOR14);
+ ivor[15] = mfspr(SPRN_IVOR15);
+
+ for (i = 0; i < 16; i++) {
+ if (ivor[i] > max_ivor)
+ max_ivor = ivor[i];
+
+ memcpy((void *)kvmppc_booke_handlers + ivor[i],
+ kvmppc_handlers_start + i * kvmppc_handler_len,
+ kvmppc_handler_len);
+ }
+ flush_icache_range(kvmppc_booke_handlers,
+ kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
+
+ return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+}
+
+static void __exit kvmppc_booke_exit(void)
+{
+ free_pages(kvmppc_booke_handlers, VCPU_SIZE_ORDER);
+ kvm_exit();
+}
+
+module_init(kvmppc_booke_init)
+module_exit(kvmppc_booke_exit)
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
new file mode 100644
index 000000000000..3b653b5309b8
--- /dev/null
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -0,0 +1,436 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/kvm_asm.h>
+#include <asm/reg.h>
+#include <asm/mmu-44x.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+
+#define KVMPPC_MSR_MASK (MSR_CE|MSR_EE|MSR_PR|MSR_DE|MSR_ME|MSR_IS|MSR_DS)
+
+#define VCPU_GPR(n) (VCPU_GPRS + (n * 4))
+
+/* The host stack layout: */
+#define HOST_R1 0 /* Implied by stwu. */
+#define HOST_CALLEE_LR 4
+#define HOST_RUN 8
+/* r2 is special: it holds 'current', and it made nonvolatile in the
+ * kernel with the -ffixed-r2 gcc option. */
+#define HOST_R2 12
+#define HOST_NV_GPRS 16
+#define HOST_NV_GPR(n) (HOST_NV_GPRS + ((n - 14) * 4))
+#define HOST_MIN_STACK_SIZE (HOST_NV_GPR(31) + 4)
+#define HOST_STACK_SIZE (((HOST_MIN_STACK_SIZE + 15) / 16) * 16) /* Align. */
+#define HOST_STACK_LR (HOST_STACK_SIZE + 4) /* In caller stack frame. */
+
+#define NEED_INST_MASK ((1<<BOOKE_INTERRUPT_PROGRAM) | \
+ (1<<BOOKE_INTERRUPT_DTLB_MISS))
+
+#define NEED_DEAR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \
+ (1<<BOOKE_INTERRUPT_DTLB_MISS))
+
+#define NEED_ESR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \
+ (1<<BOOKE_INTERRUPT_INST_STORAGE) | \
+ (1<<BOOKE_INTERRUPT_PROGRAM) | \
+ (1<<BOOKE_INTERRUPT_DTLB_MISS))
+
+.macro KVM_HANDLER ivor_nr
+_GLOBAL(kvmppc_handler_\ivor_nr)
+ /* Get pointer to vcpu and record exit number. */
+ mtspr SPRN_SPRG0, r4
+ mfspr r4, SPRN_SPRG1
+ stw r5, VCPU_GPR(r5)(r4)
+ stw r6, VCPU_GPR(r6)(r4)
+ mfctr r5
+ lis r6, kvmppc_resume_host@h
+ stw r5, VCPU_CTR(r4)
+ li r5, \ivor_nr
+ ori r6, r6, kvmppc_resume_host@l
+ mtctr r6
+ bctr
+.endm
+
+_GLOBAL(kvmppc_handlers_start)
+KVM_HANDLER BOOKE_INTERRUPT_CRITICAL
+KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK
+KVM_HANDLER BOOKE_INTERRUPT_DATA_STORAGE
+KVM_HANDLER BOOKE_INTERRUPT_INST_STORAGE
+KVM_HANDLER BOOKE_INTERRUPT_EXTERNAL
+KVM_HANDLER BOOKE_INTERRUPT_ALIGNMENT
+KVM_HANDLER BOOKE_INTERRUPT_PROGRAM
+KVM_HANDLER BOOKE_INTERRUPT_FP_UNAVAIL
+KVM_HANDLER BOOKE_INTERRUPT_SYSCALL
+KVM_HANDLER BOOKE_INTERRUPT_AP_UNAVAIL
+KVM_HANDLER BOOKE_INTERRUPT_DECREMENTER
+KVM_HANDLER BOOKE_INTERRUPT_FIT
+KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG
+KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS
+KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS
+KVM_HANDLER BOOKE_INTERRUPT_DEBUG
+
+_GLOBAL(kvmppc_handler_len)
+ .long kvmppc_handler_1 - kvmppc_handler_0
+
+
+/* Registers:
+ * SPRG0: guest r4
+ * r4: vcpu pointer
+ * r5: KVM exit number
+ */
+_GLOBAL(kvmppc_resume_host)
+ stw r3, VCPU_GPR(r3)(r4)
+ mfcr r3
+ stw r3, VCPU_CR(r4)
+ stw r7, VCPU_GPR(r7)(r4)
+ stw r8, VCPU_GPR(r8)(r4)
+ stw r9, VCPU_GPR(r9)(r4)
+
+ li r6, 1
+ slw r6, r6, r5
+
+ /* Save the faulting instruction and all GPRs for emulation. */
+ andi. r7, r6, NEED_INST_MASK
+ beq ..skip_inst_copy
+ mfspr r9, SPRN_SRR0
+ mfmsr r8
+ ori r7, r8, MSR_DS
+ mtmsr r7
+ isync
+ lwz r9, 0(r9)
+ mtmsr r8
+ isync
+ stw r9, VCPU_LAST_INST(r4)
+
+ stw r15, VCPU_GPR(r15)(r4)
+ stw r16, VCPU_GPR(r16)(r4)
+ stw r17, VCPU_GPR(r17)(r4)
+ stw r18, VCPU_GPR(r18)(r4)
+ stw r19, VCPU_GPR(r19)(r4)
+ stw r20, VCPU_GPR(r20)(r4)
+ stw r21, VCPU_GPR(r21)(r4)
+ stw r22, VCPU_GPR(r22)(r4)
+ stw r23, VCPU_GPR(r23)(r4)
+ stw r24, VCPU_GPR(r24)(r4)
+ stw r25, VCPU_GPR(r25)(r4)
+ stw r26, VCPU_GPR(r26)(r4)
+ stw r27, VCPU_GPR(r27)(r4)
+ stw r28, VCPU_GPR(r28)(r4)
+ stw r29, VCPU_GPR(r29)(r4)
+ stw r30, VCPU_GPR(r30)(r4)
+ stw r31, VCPU_GPR(r31)(r4)
+..skip_inst_copy:
+
+ /* Also grab DEAR and ESR before the host can clobber them. */
+
+ andi. r7, r6, NEED_DEAR_MASK
+ beq ..skip_dear
+ mfspr r9, SPRN_DEAR
+ stw r9, VCPU_FAULT_DEAR(r4)
+..skip_dear:
+
+ andi. r7, r6, NEED_ESR_MASK
+ beq ..skip_esr
+ mfspr r9, SPRN_ESR
+ stw r9, VCPU_FAULT_ESR(r4)
+..skip_esr:
+
+ /* Save remaining volatile guest register state to vcpu. */
+ stw r0, VCPU_GPR(r0)(r4)
+ stw r1, VCPU_GPR(r1)(r4)
+ stw r2, VCPU_GPR(r2)(r4)
+ stw r10, VCPU_GPR(r10)(r4)
+ stw r11, VCPU_GPR(r11)(r4)
+ stw r12, VCPU_GPR(r12)(r4)
+ stw r13, VCPU_GPR(r13)(r4)
+ stw r14, VCPU_GPR(r14)(r4) /* We need a NV GPR below. */
+ mflr r3
+ stw r3, VCPU_LR(r4)
+ mfxer r3
+ stw r3, VCPU_XER(r4)
+ mfspr r3, SPRN_SPRG0
+ stw r3, VCPU_GPR(r4)(r4)
+ mfspr r3, SPRN_SRR0
+ stw r3, VCPU_PC(r4)
+
+ /* Restore host stack pointer and PID before IVPR, since the host
+ * exception handlers use them. */
+ lwz r1, VCPU_HOST_STACK(r4)
+ lwz r3, VCPU_HOST_PID(r4)
+ mtspr SPRN_PID, r3
+
+ /* Restore host IVPR before re-enabling interrupts. We cheat and know
+ * that Linux IVPR is always 0xc0000000. */
+ lis r3, 0xc000
+ mtspr SPRN_IVPR, r3
+
+ /* Switch to kernel stack and jump to handler. */
+ LOAD_REG_ADDR(r3, kvmppc_handle_exit)
+ mtctr r3
+ lwz r3, HOST_RUN(r1)
+ lwz r2, HOST_R2(r1)
+ mr r14, r4 /* Save vcpu pointer. */
+
+ bctrl /* kvmppc_handle_exit() */
+
+ /* Restore vcpu pointer and the nonvolatiles we used. */
+ mr r4, r14
+ lwz r14, VCPU_GPR(r14)(r4)
+
+ /* Sometimes instruction emulation must restore complete GPR state. */
+ andi. r5, r3, RESUME_FLAG_NV
+ beq ..skip_nv_load
+ lwz r15, VCPU_GPR(r15)(r4)
+ lwz r16, VCPU_GPR(r16)(r4)
+ lwz r17, VCPU_GPR(r17)(r4)
+ lwz r18, VCPU_GPR(r18)(r4)
+ lwz r19, VCPU_GPR(r19)(r4)
+ lwz r20, VCPU_GPR(r20)(r4)
+ lwz r21, VCPU_GPR(r21)(r4)
+ lwz r22, VCPU_GPR(r22)(r4)
+ lwz r23, VCPU_GPR(r23)(r4)
+ lwz r24, VCPU_GPR(r24)(r4)
+ lwz r25, VCPU_GPR(r25)(r4)
+ lwz r26, VCPU_GPR(r26)(r4)
+ lwz r27, VCPU_GPR(r27)(r4)
+ lwz r28, VCPU_GPR(r28)(r4)
+ lwz r29, VCPU_GPR(r29)(r4)
+ lwz r30, VCPU_GPR(r30)(r4)
+ lwz r31, VCPU_GPR(r31)(r4)
+..skip_nv_load:
+
+ /* Should we return to the guest? */
+ andi. r5, r3, RESUME_FLAG_HOST
+ beq lightweight_exit
+
+ srawi r3, r3, 2 /* Shift -ERR back down. */
+
+heavyweight_exit:
+ /* Not returning to guest. */
+
+ /* We already saved guest volatile register state; now save the
+ * non-volatiles. */
+ stw r15, VCPU_GPR(r15)(r4)
+ stw r16, VCPU_GPR(r16)(r4)
+ stw r17, VCPU_GPR(r17)(r4)
+ stw r18, VCPU_GPR(r18)(r4)
+ stw r19, VCPU_GPR(r19)(r4)
+ stw r20, VCPU_GPR(r20)(r4)
+ stw r21, VCPU_GPR(r21)(r4)
+ stw r22, VCPU_GPR(r22)(r4)
+ stw r23, VCPU_GPR(r23)(r4)
+ stw r24, VCPU_GPR(r24)(r4)
+ stw r25, VCPU_GPR(r25)(r4)
+ stw r26, VCPU_GPR(r26)(r4)
+ stw r27, VCPU_GPR(r27)(r4)
+ stw r28, VCPU_GPR(r28)(r4)
+ stw r29, VCPU_GPR(r29)(r4)
+ stw r30, VCPU_GPR(r30)(r4)
+ stw r31, VCPU_GPR(r31)(r4)
+
+ /* Load host non-volatile register state from host stack. */
+ lwz r14, HOST_NV_GPR(r14)(r1)
+ lwz r15, HOST_NV_GPR(r15)(r1)
+ lwz r16, HOST_NV_GPR(r16)(r1)
+ lwz r17, HOST_NV_GPR(r17)(r1)
+ lwz r18, HOST_NV_GPR(r18)(r1)
+ lwz r19, HOST_NV_GPR(r19)(r1)
+ lwz r20, HOST_NV_GPR(r20)(r1)
+ lwz r21, HOST_NV_GPR(r21)(r1)
+ lwz r22, HOST_NV_GPR(r22)(r1)
+ lwz r23, HOST_NV_GPR(r23)(r1)
+ lwz r24, HOST_NV_GPR(r24)(r1)
+ lwz r25, HOST_NV_GPR(r25)(r1)
+ lwz r26, HOST_NV_GPR(r26)(r1)
+ lwz r27, HOST_NV_GPR(r27)(r1)
+ lwz r28, HOST_NV_GPR(r28)(r1)
+ lwz r29, HOST_NV_GPR(r29)(r1)
+ lwz r30, HOST_NV_GPR(r30)(r1)
+ lwz r31, HOST_NV_GPR(r31)(r1)
+
+ /* Return to kvm_vcpu_run(). */
+ lwz r4, HOST_STACK_LR(r1)
+ addi r1, r1, HOST_STACK_SIZE
+ mtlr r4
+ /* r3 still contains the return code from kvmppc_handle_exit(). */
+ blr
+
+
+/* Registers:
+ * r3: kvm_run pointer
+ * r4: vcpu pointer
+ */
+_GLOBAL(__kvmppc_vcpu_run)
+ stwu r1, -HOST_STACK_SIZE(r1)
+ stw r1, VCPU_HOST_STACK(r4) /* Save stack pointer to vcpu. */
+
+ /* Save host state to stack. */
+ stw r3, HOST_RUN(r1)
+ mflr r3
+ stw r3, HOST_STACK_LR(r1)
+
+ /* Save host non-volatile register state to stack. */
+ stw r14, HOST_NV_GPR(r14)(r1)
+ stw r15, HOST_NV_GPR(r15)(r1)
+ stw r16, HOST_NV_GPR(r16)(r1)
+ stw r17, HOST_NV_GPR(r17)(r1)
+ stw r18, HOST_NV_GPR(r18)(r1)
+ stw r19, HOST_NV_GPR(r19)(r1)
+ stw r20, HOST_NV_GPR(r20)(r1)
+ stw r21, HOST_NV_GPR(r21)(r1)
+ stw r22, HOST_NV_GPR(r22)(r1)
+ stw r23, HOST_NV_GPR(r23)(r1)
+ stw r24, HOST_NV_GPR(r24)(r1)
+ stw r25, HOST_NV_GPR(r25)(r1)
+ stw r26, HOST_NV_GPR(r26)(r1)
+ stw r27, HOST_NV_GPR(r27)(r1)
+ stw r28, HOST_NV_GPR(r28)(r1)
+ stw r29, HOST_NV_GPR(r29)(r1)
+ stw r30, HOST_NV_GPR(r30)(r1)
+ stw r31, HOST_NV_GPR(r31)(r1)
+
+ /* Load guest non-volatiles. */
+ lwz r14, VCPU_GPR(r14)(r4)
+ lwz r15, VCPU_GPR(r15)(r4)
+ lwz r16, VCPU_GPR(r16)(r4)
+ lwz r17, VCPU_GPR(r17)(r4)
+ lwz r18, VCPU_GPR(r18)(r4)
+ lwz r19, VCPU_GPR(r19)(r4)
+ lwz r20, VCPU_GPR(r20)(r4)
+ lwz r21, VCPU_GPR(r21)(r4)
+ lwz r22, VCPU_GPR(r22)(r4)
+ lwz r23, VCPU_GPR(r23)(r4)
+ lwz r24, VCPU_GPR(r24)(r4)
+ lwz r25, VCPU_GPR(r25)(r4)
+ lwz r26, VCPU_GPR(r26)(r4)
+ lwz r27, VCPU_GPR(r27)(r4)
+ lwz r28, VCPU_GPR(r28)(r4)
+ lwz r29, VCPU_GPR(r29)(r4)
+ lwz r30, VCPU_GPR(r30)(r4)
+ lwz r31, VCPU_GPR(r31)(r4)
+
+lightweight_exit:
+ stw r2, HOST_R2(r1)
+
+ mfspr r3, SPRN_PID
+ stw r3, VCPU_HOST_PID(r4)
+ lwz r3, VCPU_PID(r4)
+ mtspr SPRN_PID, r3
+
+ /* Prevent all TLB updates. */
+ mfmsr r5
+ lis r6, (MSR_EE|MSR_CE|MSR_ME|MSR_DE)@h
+ ori r6, r6, (MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l
+ andc r6, r5, r6
+ mtmsr r6
+
+ /* Save the host's non-pinned TLB mappings, and load the guest mappings
+ * over them. Leave the host's "pinned" kernel mappings in place. */
+ /* XXX optimization: use generation count to avoid swapping unmodified
+ * entries. */
+ mfspr r10, SPRN_MMUCR /* Save host MMUCR. */
+ lis r8, tlb_44x_hwater@ha
+ lwz r8, tlb_44x_hwater@l(r8)
+ addi r3, r4, VCPU_HOST_TLB - 4
+ addi r9, r4, VCPU_SHADOW_TLB - 4
+ li r6, 0
+1:
+ /* Save host entry. */
+ tlbre r7, r6, PPC44x_TLB_PAGEID
+ mfspr r5, SPRN_MMUCR
+ stwu r5, 4(r3)
+ stwu r7, 4(r3)
+ tlbre r7, r6, PPC44x_TLB_XLAT
+ stwu r7, 4(r3)
+ tlbre r7, r6, PPC44x_TLB_ATTRIB
+ stwu r7, 4(r3)
+ /* Load guest entry. */
+ lwzu r7, 4(r9)
+ mtspr SPRN_MMUCR, r7
+ lwzu r7, 4(r9)
+ tlbwe r7, r6, PPC44x_TLB_PAGEID
+ lwzu r7, 4(r9)
+ tlbwe r7, r6, PPC44x_TLB_XLAT
+ lwzu r7, 4(r9)
+ tlbwe r7, r6, PPC44x_TLB_ATTRIB
+ /* Increment index. */
+ addi r6, r6, 1
+ cmpw r6, r8
+ blt 1b
+ mtspr SPRN_MMUCR, r10 /* Restore host MMUCR. */
+
+ iccci 0, 0 /* XXX hack */
+
+ /* Load some guest volatiles. */
+ lwz r0, VCPU_GPR(r0)(r4)
+ lwz r2, VCPU_GPR(r2)(r4)
+ lwz r9, VCPU_GPR(r9)(r4)
+ lwz r10, VCPU_GPR(r10)(r4)
+ lwz r11, VCPU_GPR(r11)(r4)
+ lwz r12, VCPU_GPR(r12)(r4)
+ lwz r13, VCPU_GPR(r13)(r4)
+ lwz r3, VCPU_LR(r4)
+ mtlr r3
+ lwz r3, VCPU_XER(r4)
+ mtxer r3
+
+ /* Switch the IVPR. XXX If we take a TLB miss after this we're screwed,
+ * so how do we make sure vcpu won't fault? */
+ lis r8, kvmppc_booke_handlers@ha
+ lwz r8, kvmppc_booke_handlers@l(r8)
+ mtspr SPRN_IVPR, r8
+
+ /* Save vcpu pointer for the exception handlers. */
+ mtspr SPRN_SPRG1, r4
+
+ /* Can't switch the stack pointer until after IVPR is switched,
+ * because host interrupt handlers would get confused. */
+ lwz r1, VCPU_GPR(r1)(r4)
+
+ /* XXX handle USPRG0 */
+ /* Host interrupt handlers may have clobbered these guest-readable
+ * SPRGs, so we need to reload them here with the guest's values. */
+ lwz r3, VCPU_SPRG4(r4)
+ mtspr SPRN_SPRG4, r3
+ lwz r3, VCPU_SPRG5(r4)
+ mtspr SPRN_SPRG5, r3
+ lwz r3, VCPU_SPRG6(r4)
+ mtspr SPRN_SPRG6, r3
+ lwz r3, VCPU_SPRG7(r4)
+ mtspr SPRN_SPRG7, r3
+
+ /* Finish loading guest volatiles and jump to guest. */
+ lwz r3, VCPU_CTR(r4)
+ mtctr r3
+ lwz r3, VCPU_CR(r4)
+ mtcr r3
+ lwz r5, VCPU_GPR(r5)(r4)
+ lwz r6, VCPU_GPR(r6)(r4)
+ lwz r7, VCPU_GPR(r7)(r4)
+ lwz r8, VCPU_GPR(r8)(r4)
+ lwz r3, VCPU_PC(r4)
+ mtsrr0 r3
+ lwz r3, VCPU_MSR(r4)
+ oris r3, r3, KVMPPC_MSR_MASK@h
+ ori r3, r3, KVMPPC_MSR_MASK@l
+ mtsrr1 r3
+ lwz r3, VCPU_GPR(r3)(r4)
+ lwz r4, VCPU_GPR(r4)(r4)
+ rfi
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
new file mode 100644
index 000000000000..a03fe0c80698
--- /dev/null
+++ b/arch/powerpc/kvm/emulate.c
@@ -0,0 +1,760 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kvm_host.h>
+
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+#include <asm/time.h>
+#include <asm/byteorder.h>
+#include <asm/kvm_ppc.h>
+
+#include "44x_tlb.h"
+
+/* Instruction decoding */
+static inline unsigned int get_op(u32 inst)
+{
+ return inst >> 26;
+}
+
+static inline unsigned int get_xop(u32 inst)
+{
+ return (inst >> 1) & 0x3ff;
+}
+
+static inline unsigned int get_sprn(u32 inst)
+{
+ return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
+}
+
+static inline unsigned int get_dcrn(u32 inst)
+{
+ return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
+}
+
+static inline unsigned int get_rt(u32 inst)
+{
+ return (inst >> 21) & 0x1f;
+}
+
+static inline unsigned int get_rs(u32 inst)
+{
+ return (inst >> 21) & 0x1f;
+}
+
+static inline unsigned int get_ra(u32 inst)
+{
+ return (inst >> 16) & 0x1f;
+}
+
+static inline unsigned int get_rb(u32 inst)
+{
+ return (inst >> 11) & 0x1f;
+}
+
+static inline unsigned int get_rc(u32 inst)
+{
+ return inst & 0x1;
+}
+
+static inline unsigned int get_ws(u32 inst)
+{
+ return (inst >> 11) & 0x1f;
+}
+
+static inline unsigned int get_d(u32 inst)
+{
+ return inst & 0xffff;
+}
+
+static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
+ const struct tlbe *tlbe)
+{
+ gpa_t gpa;
+
+ if (!get_tlb_v(tlbe))
+ return 0;
+
+ /* Does it match current guest AS? */
+ /* XXX what about IS != DS? */
+ if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+ return 0;
+
+ gpa = get_tlb_raddr(tlbe);
+ if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
+ /* Mapping is not for RAM. */
+ return 0;
+
+ return 1;
+}
+
+static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst)
+{
+ u64 eaddr;
+ u64 raddr;
+ u64 asid;
+ u32 flags;
+ struct tlbe *tlbe;
+ unsigned int ra;
+ unsigned int rs;
+ unsigned int ws;
+ unsigned int index;
+
+ ra = get_ra(inst);
+ rs = get_rs(inst);
+ ws = get_ws(inst);
+
+ index = vcpu->arch.gpr[ra];
+ if (index > PPC44x_TLB_SIZE) {
+ printk("%s: index %d\n", __func__, index);
+ kvmppc_dump_vcpu(vcpu);
+ return EMULATE_FAIL;
+ }
+
+ tlbe = &vcpu->arch.guest_tlb[index];
+
+ /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
+ if (tlbe->word0 & PPC44x_TLB_VALID) {
+ eaddr = get_tlb_eaddr(tlbe);
+ asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
+ kvmppc_mmu_invalidate(vcpu, eaddr, asid);
+ }
+
+ switch (ws) {
+ case PPC44x_TLB_PAGEID:
+ tlbe->tid = vcpu->arch.mmucr & 0xff;
+ tlbe->word0 = vcpu->arch.gpr[rs];
+ break;
+
+ case PPC44x_TLB_XLAT:
+ tlbe->word1 = vcpu->arch.gpr[rs];
+ break;
+
+ case PPC44x_TLB_ATTRIB:
+ tlbe->word2 = vcpu->arch.gpr[rs];
+ break;
+
+ default:
+ return EMULATE_FAIL;
+ }
+
+ if (tlbe_is_host_safe(vcpu, tlbe)) {
+ eaddr = get_tlb_eaddr(tlbe);
+ raddr = get_tlb_raddr(tlbe);
+ asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
+ flags = tlbe->word2 & 0xffff;
+
+ /* Create a 4KB mapping on the host. If the guest wanted a
+ * large page, only the first 4KB is mapped here and the rest
+ * are mapped on the fly. */
+ kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags);
+ }
+
+ return EMULATE_DONE;
+}
+
+static void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.tcr & TCR_DIE) {
+ /* The decrementer ticks at the same rate as the timebase, so
+ * that's how we convert the guest DEC value to the number of
+ * host ticks. */
+ unsigned long nr_jiffies;
+
+ nr_jiffies = vcpu->arch.dec / tb_ticks_per_jiffy;
+ mod_timer(&vcpu->arch.dec_timer,
+ get_jiffies_64() + nr_jiffies);
+ } else {
+ del_timer(&vcpu->arch.dec_timer);
+ }
+}
+
+static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.pc = vcpu->arch.srr0;
+ kvmppc_set_msr(vcpu, vcpu->arch.srr1);
+}
+
+/* XXX to do:
+ * lhax
+ * lhaux
+ * lswx
+ * lswi
+ * stswx
+ * stswi
+ * lha
+ * lhau
+ * lmw
+ * stmw
+ *
+ * XXX is_bigendian should depend on MMU mapping or MSR[LE]
+ */
+int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+ u32 inst = vcpu->arch.last_inst;
+ u32 ea;
+ int ra;
+ int rb;
+ int rc;
+ int rs;
+ int rt;
+ int sprn;
+ int dcrn;
+ enum emulation_result emulated = EMULATE_DONE;
+ int advance = 1;
+
+ switch (get_op(inst)) {
+ case 3: /* trap */
+ printk("trap!\n");
+ kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM);
+ advance = 0;
+ break;
+
+ case 19:
+ switch (get_xop(inst)) {
+ case 50: /* rfi */
+ kvmppc_emul_rfi(vcpu);
+ advance = 0;
+ break;
+
+ default:
+ emulated = EMULATE_FAIL;
+ break;
+ }
+ break;
+
+ case 31:
+ switch (get_xop(inst)) {
+
+ case 83: /* mfmsr */
+ rt = get_rt(inst);
+ vcpu->arch.gpr[rt] = vcpu->arch.msr;
+ break;
+
+ case 87: /* lbzx */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+ break;
+
+ case 131: /* wrtee */
+ rs = get_rs(inst);
+ vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+ | (vcpu->arch.gpr[rs] & MSR_EE);
+ break;
+
+ case 146: /* mtmsr */
+ rs = get_rs(inst);
+ kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]);
+ break;
+
+ case 163: /* wrteei */
+ vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+ | (inst & MSR_EE);
+ break;
+
+ case 215: /* stbx */
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu,
+ vcpu->arch.gpr[rs],
+ 1, 1);
+ break;
+
+ case 247: /* stbux */
+ rs = get_rs(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+
+ ea = vcpu->arch.gpr[rb];
+ if (ra)
+ ea += vcpu->arch.gpr[ra];
+
+ emulated = kvmppc_handle_store(run, vcpu,
+ vcpu->arch.gpr[rs],
+ 1, 1);
+ vcpu->arch.gpr[rs] = ea;
+ break;
+
+ case 279: /* lhzx */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+ break;
+
+ case 311: /* lhzux */
+ rt = get_rt(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+
+ ea = vcpu->arch.gpr[rb];
+ if (ra)
+ ea += vcpu->arch.gpr[ra];
+
+ emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+ vcpu->arch.gpr[ra] = ea;
+ break;
+
+ case 323: /* mfdcr */
+ dcrn = get_dcrn(inst);
+ rt = get_rt(inst);
+
+ /* The guest may access CPR0 registers to determine the timebase
+ * frequency, and it must know the real host frequency because it
+ * can directly access the timebase registers.
+ *
+ * It would be possible to emulate those accesses in userspace,
+ * but userspace can really only figure out the end frequency.
+ * We could decompose that into the factors that compute it, but
+ * that's tricky math, and it's easier to just report the real
+ * CPR0 values.
+ */
+ switch (dcrn) {
+ case DCRN_CPR0_CONFIG_ADDR:
+ vcpu->arch.gpr[rt] = vcpu->arch.cpr0_cfgaddr;
+ break;
+ case DCRN_CPR0_CONFIG_DATA:
+ local_irq_disable();
+ mtdcr(DCRN_CPR0_CONFIG_ADDR,
+ vcpu->arch.cpr0_cfgaddr);
+ vcpu->arch.gpr[rt] = mfdcr(DCRN_CPR0_CONFIG_DATA);
+ local_irq_enable();
+ break;
+ default:
+ run->dcr.dcrn = dcrn;
+ run->dcr.data = 0;
+ run->dcr.is_write = 0;
+ vcpu->arch.io_gpr = rt;
+ vcpu->arch.dcr_needed = 1;
+ emulated = EMULATE_DO_DCR;
+ }
+
+ break;
+
+ case 339: /* mfspr */
+ sprn = get_sprn(inst);
+ rt = get_rt(inst);
+
+ switch (sprn) {
+ case SPRN_SRR0:
+ vcpu->arch.gpr[rt] = vcpu->arch.srr0; break;
+ case SPRN_SRR1:
+ vcpu->arch.gpr[rt] = vcpu->arch.srr1; break;
+ case SPRN_MMUCR:
+ vcpu->arch.gpr[rt] = vcpu->arch.mmucr; break;
+ case SPRN_PID:
+ vcpu->arch.gpr[rt] = vcpu->arch.pid; break;
+ case SPRN_IVPR:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivpr; break;
+ case SPRN_CCR0:
+ vcpu->arch.gpr[rt] = vcpu->arch.ccr0; break;
+ case SPRN_CCR1:
+ vcpu->arch.gpr[rt] = vcpu->arch.ccr1; break;
+ case SPRN_PVR:
+ vcpu->arch.gpr[rt] = vcpu->arch.pvr; break;
+ case SPRN_DEAR:
+ vcpu->arch.gpr[rt] = vcpu->arch.dear; break;
+ case SPRN_ESR:
+ vcpu->arch.gpr[rt] = vcpu->arch.esr; break;
+ case SPRN_DBCR0:
+ vcpu->arch.gpr[rt] = vcpu->arch.dbcr0; break;
+ case SPRN_DBCR1:
+ vcpu->arch.gpr[rt] = vcpu->arch.dbcr1; break;
+
+ /* Note: mftb and TBRL/TBWL are user-accessible, so
+ * the guest can always access the real TB anyways.
+ * In fact, we probably will never see these traps. */
+ case SPRN_TBWL:
+ vcpu->arch.gpr[rt] = mftbl(); break;
+ case SPRN_TBWU:
+ vcpu->arch.gpr[rt] = mftbu(); break;
+
+ case SPRN_SPRG0:
+ vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break;
+ case SPRN_SPRG1:
+ vcpu->arch.gpr[rt] = vcpu->arch.sprg1; break;
+ case SPRN_SPRG2:
+ vcpu->arch.gpr[rt] = vcpu->arch.sprg2; break;
+ case SPRN_SPRG3:
+ vcpu->arch.gpr[rt] = vcpu->arch.sprg3; break;
+ /* Note: SPRG4-7 are user-readable, so we don't get
+ * a trap. */
+
+ case SPRN_IVOR0:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[0]; break;
+ case SPRN_IVOR1:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[1]; break;
+ case SPRN_IVOR2:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[2]; break;
+ case SPRN_IVOR3:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[3]; break;
+ case SPRN_IVOR4:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[4]; break;
+ case SPRN_IVOR5:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[5]; break;
+ case SPRN_IVOR6:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[6]; break;
+ case SPRN_IVOR7:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[7]; break;
+ case SPRN_IVOR8:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[8]; break;
+ case SPRN_IVOR9:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[9]; break;
+ case SPRN_IVOR10:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[10]; break;
+ case SPRN_IVOR11:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[11]; break;
+ case SPRN_IVOR12:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[12]; break;
+ case SPRN_IVOR13:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[13]; break;
+ case SPRN_IVOR14:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[14]; break;
+ case SPRN_IVOR15:
+ vcpu->arch.gpr[rt] = vcpu->arch.ivor[15]; break;
+
+ default:
+ printk("mfspr: unknown spr %x\n", sprn);
+ vcpu->arch.gpr[rt] = 0;
+ break;
+ }
+ break;
+
+ case 407: /* sthx */
+ rs = get_rs(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+
+ emulated = kvmppc_handle_store(run, vcpu,
+ vcpu->arch.gpr[rs],
+ 2, 1);
+ break;
+
+ case 439: /* sthux */
+ rs = get_rs(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+
+ ea = vcpu->arch.gpr[rb];
+ if (ra)
+ ea += vcpu->arch.gpr[ra];
+
+ emulated = kvmppc_handle_store(run, vcpu,
+ vcpu->arch.gpr[rs],
+ 2, 1);
+ vcpu->arch.gpr[ra] = ea;
+ break;
+
+ case 451: /* mtdcr */
+ dcrn = get_dcrn(inst);
+ rs = get_rs(inst);
+
+ /* emulate some access in kernel */
+ switch (dcrn) {
+ case DCRN_CPR0_CONFIG_ADDR:
+ vcpu->arch.cpr0_cfgaddr = vcpu->arch.gpr[rs];
+ break;
+ default:
+ run->dcr.dcrn = dcrn;
+ run->dcr.data = vcpu->arch.gpr[rs];
+ run->dcr.is_write = 1;
+ vcpu->arch.dcr_needed = 1;
+ emulated = EMULATE_DO_DCR;
+ }
+
+ break;
+
+ case 467: /* mtspr */
+ sprn = get_sprn(inst);
+ rs = get_rs(inst);
+ switch (sprn) {
+ case SPRN_SRR0:
+ vcpu->arch.srr0 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SRR1:
+ vcpu->arch.srr1 = vcpu->arch.gpr[rs]; break;
+ case SPRN_MMUCR:
+ vcpu->arch.mmucr = vcpu->arch.gpr[rs]; break;
+ case SPRN_PID:
+ vcpu->arch.pid = vcpu->arch.gpr[rs]; break;
+ case SPRN_CCR0:
+ vcpu->arch.ccr0 = vcpu->arch.gpr[rs]; break;
+ case SPRN_CCR1:
+ vcpu->arch.ccr1 = vcpu->arch.gpr[rs]; break;
+ case SPRN_DEAR:
+ vcpu->arch.dear = vcpu->arch.gpr[rs]; break;
+ case SPRN_ESR:
+ vcpu->arch.esr = vcpu->arch.gpr[rs]; break;
+ case SPRN_DBCR0:
+ vcpu->arch.dbcr0 = vcpu->arch.gpr[rs]; break;
+ case SPRN_DBCR1:
+ vcpu->arch.dbcr1 = vcpu->arch.gpr[rs]; break;
+
+ /* XXX We need to context-switch the timebase for
+ * watchdog and FIT. */
+ case SPRN_TBWL: break;
+ case SPRN_TBWU: break;
+
+ case SPRN_DEC:
+ vcpu->arch.dec = vcpu->arch.gpr[rs];
+ kvmppc_emulate_dec(vcpu);
+ break;
+
+ case SPRN_TSR:
+ vcpu->arch.tsr &= ~vcpu->arch.gpr[rs]; break;
+
+ case SPRN_TCR:
+ vcpu->arch.tcr = vcpu->arch.gpr[rs];
+ kvmppc_emulate_dec(vcpu);
+ break;
+
+ case SPRN_SPRG0:
+ vcpu->arch.sprg0 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SPRG1:
+ vcpu->arch.sprg1 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SPRG2:
+ vcpu->arch.sprg2 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SPRG3:
+ vcpu->arch.sprg3 = vcpu->arch.gpr[rs]; break;
+
+ /* Note: SPRG4-7 are user-readable. These values are
+ * loaded into the real SPRGs when resuming the
+ * guest. */
+ case SPRN_SPRG4:
+ vcpu->arch.sprg4 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SPRG5:
+ vcpu->arch.sprg5 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SPRG6:
+ vcpu->arch.sprg6 = vcpu->arch.gpr[rs]; break;
+ case SPRN_SPRG7:
+ vcpu->arch.sprg7 = vcpu->arch.gpr[rs]; break;
+
+ case SPRN_IVPR:
+ vcpu->arch.ivpr = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR0:
+ vcpu->arch.ivor[0] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR1:
+ vcpu->arch.ivor[1] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR2:
+ vcpu->arch.ivor[2] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR3:
+ vcpu->arch.ivor[3] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR4:
+ vcpu->arch.ivor[4] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR5:
+ vcpu->arch.ivor[5] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR6:
+ vcpu->arch.ivor[6] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR7:
+ vcpu->arch.ivor[7] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR8:
+ vcpu->arch.ivor[8] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR9:
+ vcpu->arch.ivor[9] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR10:
+ vcpu->arch.ivor[10] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR11:
+ vcpu->arch.ivor[11] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR12:
+ vcpu->arch.ivor[12] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR13:
+ vcpu->arch.ivor[13] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR14:
+ vcpu->arch.ivor[14] = vcpu->arch.gpr[rs]; break;
+ case SPRN_IVOR15:
+ vcpu->arch.ivor[15] = vcpu->arch.gpr[rs]; break;
+
+ default:
+ printk("mtspr: unknown spr %x\n", sprn);
+ emulated = EMULATE_FAIL;
+ break;
+ }
+ break;
+
+ case 470: /* dcbi */
+ /* Do nothing. The guest is performing dcbi because
+ * hardware DMA is not snooped by the dcache, but
+ * emulated DMA either goes through the dcache as
+ * normal writes, or the host kernel has handled dcache
+ * coherence. */
+ break;
+
+ case 534: /* lwbrx */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
+ break;
+
+ case 566: /* tlbsync */
+ break;
+
+ case 662: /* stwbrx */
+ rs = get_rs(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+
+ emulated = kvmppc_handle_store(run, vcpu,
+ vcpu->arch.gpr[rs],
+ 4, 0);
+ break;
+
+ case 978: /* tlbwe */
+ emulated = kvmppc_emul_tlbwe(vcpu, inst);
+ break;
+
+ case 914: { /* tlbsx */
+ int index;
+ unsigned int as = get_mmucr_sts(vcpu);
+ unsigned int pid = get_mmucr_stid(vcpu);
+
+ rt = get_rt(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+ rc = get_rc(inst);
+
+ ea = vcpu->arch.gpr[rb];
+ if (ra)
+ ea += vcpu->arch.gpr[ra];
+
+ index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
+ if (rc) {
+ if (index < 0)
+ vcpu->arch.cr &= ~0x20000000;
+ else
+ vcpu->arch.cr |= 0x20000000;
+ }
+ vcpu->arch.gpr[rt] = index;
+
+ }
+ break;
+
+ case 790: /* lhbrx */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
+ break;
+
+ case 918: /* sthbrx */
+ rs = get_rs(inst);
+ ra = get_ra(inst);
+ rb = get_rb(inst);
+
+ emulated = kvmppc_handle_store(run, vcpu,
+ vcpu->arch.gpr[rs],
+ 2, 0);
+ break;
+
+ case 966: /* iccci */
+ break;
+
+ default:
+ printk("unknown: op %d xop %d\n", get_op(inst),
+ get_xop(inst));
+ emulated = EMULATE_FAIL;
+ break;
+ }
+ break;
+
+ case 32: /* lwz */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
+ break;
+
+ case 33: /* lwzu */
+ ra = get_ra(inst);
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
+ vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+ break;
+
+ case 34: /* lbz */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+ break;
+
+ case 35: /* lbzu */
+ ra = get_ra(inst);
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
+ vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+ break;
+
+ case 36: /* stw */
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+ 4, 1);
+ break;
+
+ case 37: /* stwu */
+ ra = get_ra(inst);
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+ 4, 1);
+ vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+ break;
+
+ case 38: /* stb */
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+ 1, 1);
+ break;
+
+ case 39: /* stbu */
+ ra = get_ra(inst);
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+ 1, 1);
+ vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+ break;
+
+ case 40: /* lhz */
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+ break;
+
+ case 41: /* lhzu */
+ ra = get_ra(inst);
+ rt = get_rt(inst);
+ emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
+ vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+ break;
+
+ case 44: /* sth */
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+ 2, 1);
+ break;
+
+ case 45: /* sthu */
+ ra = get_ra(inst);
+ rs = get_rs(inst);
+ emulated = kvmppc_handle_store(run, vcpu, vcpu->arch.gpr[rs],
+ 2, 1);
+ vcpu->arch.gpr[ra] = vcpu->arch.paddr_accessed;
+ break;
+
+ default:
+ printk("unknown op %d\n", get_op(inst));
+ emulated = EMULATE_FAIL;
+ break;
+ }
+
+ if (advance)
+ vcpu->arch.pc += 4; /* Advance past emulated instruction. */
+
+ return emulated;
+}
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
new file mode 100644
index 000000000000..bad40bd2d3ac
--- /dev/null
+++ b/arch/powerpc/kvm/powerpc.c
@@ -0,0 +1,436 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <asm/cputable.h>
+#include <asm/uaccess.h>
+#include <asm/kvm_ppc.h>
+
+
+gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
+{
+ return gfn;
+}
+
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
+{
+ /* XXX implement me */
+ return 0;
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
+{
+ return 1;
+}
+
+
+int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+ enum emulation_result er;
+ int r;
+
+ er = kvmppc_emulate_instruction(run, vcpu);
+ switch (er) {
+ case EMULATE_DONE:
+ /* Future optimization: only reload non-volatiles if they were
+ * actually modified. */
+ r = RESUME_GUEST_NV;
+ break;
+ case EMULATE_DO_MMIO:
+ run->exit_reason = KVM_EXIT_MMIO;
+ /* We must reload nonvolatiles because "update" load/store
+ * instructions modify register state. */
+ /* Future optimization: only reload non-volatiles if they were
+ * actually modified. */
+ r = RESUME_HOST_NV;
+ break;
+ case EMULATE_FAIL:
+ /* XXX Deliver Program interrupt to guest. */
+ printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
+ vcpu->arch.last_inst);
+ r = RESUME_HOST;
+ break;
+ default:
+ BUG();
+ }
+
+ return r;
+}
+
+void kvm_arch_hardware_enable(void *garbage)
+{
+}
+
+void kvm_arch_hardware_disable(void *garbage)
+{
+}
+
+int kvm_arch_hardware_setup(void)
+{
+ return 0;
+}
+
+void kvm_arch_hardware_unsetup(void)
+{
+}
+
+void kvm_arch_check_processor_compat(void *rtn)
+{
+ int r;
+
+ if (strcmp(cur_cpu_spec->platform, "ppc440") == 0)
+ r = 0;
+ else
+ r = -ENOTSUPP;
+
+ *(int *)rtn = r;
+}
+
+struct kvm *kvm_arch_create_vm(void)
+{
+ struct kvm *kvm;
+
+ kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+ if (!kvm)
+ return ERR_PTR(-ENOMEM);
+
+ return kvm;
+}
+
+static void kvmppc_free_vcpus(struct kvm *kvm)
+{
+ unsigned int i;
+
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ if (kvm->vcpus[i]) {
+ kvm_arch_vcpu_free(kvm->vcpus[i]);
+ kvm->vcpus[i] = NULL;
+ }
+ }
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ kvmppc_free_vcpus(kvm);
+ kvm_free_physmem(kvm);
+ kfree(kvm);
+}
+
+int kvm_dev_ioctl_check_extension(long ext)
+{
+ int r;
+
+ switch (ext) {
+ case KVM_CAP_USER_MEMORY:
+ r = 1;
+ break;
+ default:
+ r = 0;
+ break;
+ }
+ return r;
+
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_set_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+ return 0;
+}
+
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
+{
+ struct kvm_vcpu *vcpu;
+ int err;
+
+ vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ if (!vcpu) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = kvm_vcpu_init(vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
+
+ return vcpu;
+
+free_vcpu:
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
+out:
+ return ERR_PTR(err);
+}
+
+void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
+{
+ kvm_vcpu_uninit(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ kvm_arch_vcpu_free(vcpu);
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ unsigned int priority = exception_priority[BOOKE_INTERRUPT_DECREMENTER];
+
+ return test_bit(priority, &vcpu->arch.pending_exceptions);
+}
+
+static void kvmppc_decrementer_func(unsigned long data)
+{
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+
+ kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_DECREMENTER);
+}
+
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ setup_timer(&vcpu->arch.dec_timer, kvmppc_decrementer_func,
+ (unsigned long)vcpu);
+
+ return 0;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+}
+
+void decache_vcpus_on_cpu(int cpu)
+{
+}
+
+int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
+ struct kvm_debug_guest *dbg)
+{
+ return -ENOTSUPP;
+}
+
+static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
+ struct kvm_run *run)
+{
+ u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr];
+ *gpr = run->dcr.data;
+}
+
+static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
+ struct kvm_run *run)
+{
+ u32 *gpr = &vcpu->arch.gpr[vcpu->arch.io_gpr];
+
+ if (run->mmio.len > sizeof(*gpr)) {
+ printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
+ return;
+ }
+
+ if (vcpu->arch.mmio_is_bigendian) {
+ switch (run->mmio.len) {
+ case 4: *gpr = *(u32 *)run->mmio.data; break;
+ case 2: *gpr = *(u16 *)run->mmio.data; break;
+ case 1: *gpr = *(u8 *)run->mmio.data; break;
+ }
+ } else {
+ /* Convert BE data from userland back to LE. */
+ switch (run->mmio.len) {
+ case 4: *gpr = ld_le32((u32 *)run->mmio.data); break;
+ case 2: *gpr = ld_le16((u16 *)run->mmio.data); break;
+ case 1: *gpr = *(u8 *)run->mmio.data; break;
+ }
+ }
+}
+
+int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ unsigned int rt, unsigned int bytes, int is_bigendian)
+{
+ if (bytes > sizeof(run->mmio.data)) {
+ printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
+ run->mmio.len);
+ }
+
+ run->mmio.phys_addr = vcpu->arch.paddr_accessed;
+ run->mmio.len = bytes;
+ run->mmio.is_write = 0;
+
+ vcpu->arch.io_gpr = rt;
+ vcpu->arch.mmio_is_bigendian = is_bigendian;
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_is_write = 0;
+
+ return EMULATE_DO_MMIO;
+}
+
+int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ u32 val, unsigned int bytes, int is_bigendian)
+{
+ void *data = run->mmio.data;
+
+ if (bytes > sizeof(run->mmio.data)) {
+ printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
+ run->mmio.len);
+ }
+
+ run->mmio.phys_addr = vcpu->arch.paddr_accessed;
+ run->mmio.len = bytes;
+ run->mmio.is_write = 1;
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_is_write = 1;
+
+ /* Store the value at the lowest bytes in 'data'. */
+ if (is_bigendian) {
+ switch (bytes) {
+ case 4: *(u32 *)data = val; break;
+ case 2: *(u16 *)data = val; break;
+ case 1: *(u8 *)data = val; break;
+ }
+ } else {
+ /* Store LE value into 'data'. */
+ switch (bytes) {
+ case 4: st_le32(data, val); break;
+ case 2: st_le16(data, val); break;
+ case 1: *(u8 *)data = val; break;
+ }
+ }
+
+ return EMULATE_DO_MMIO;
+}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ int r;
+ sigset_t sigsaved;
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
+ if (vcpu->mmio_needed) {
+ if (!vcpu->mmio_is_write)
+ kvmppc_complete_mmio_load(vcpu, run);
+ vcpu->mmio_needed = 0;
+ } else if (vcpu->arch.dcr_needed) {
+ if (!vcpu->arch.dcr_is_write)
+ kvmppc_complete_dcr_load(vcpu, run);
+ vcpu->arch.dcr_needed = 0;
+ }
+
+ kvmppc_check_and_deliver_interrupts(vcpu);
+
+ local_irq_disable();
+ kvm_guest_enter();
+ r = __kvmppc_vcpu_run(run, vcpu);
+ kvm_guest_exit();
+ local_irq_enable();
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+ return r;
+}
+
+int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
+{
+ kvmppc_queue_exception(vcpu, BOOKE_INTERRUPT_EXTERNAL);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ long r;
+
+ switch (ioctl) {
+ case KVM_INTERRUPT: {
+ struct kvm_interrupt irq;
+ r = -EFAULT;
+ if (copy_from_user(&irq, argp, sizeof(irq)))
+ goto out;
+ r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
+ break;
+ }
+ default:
+ r = -EINVAL;
+ }
+
+out:
+ return r;
+}
+
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+ return -ENOTSUPP;
+}
+
+long kvm_arch_vm_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ long r;
+
+ switch (ioctl) {
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+int kvm_arch_init(void *opaque)
+{
+ return 0;
+}
+
+void kvm_arch_exit(void)
+{
+}
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index ada249bf9779..ce10e2b1b902 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -202,7 +202,7 @@ adjust_total_lowmem(void)
cam_max_size = max_lowmem_size;
/* adjust lowmem size to max_lowmem_size */
- ram = min(max_lowmem_size, total_lowmem);
+ ram = min(max_lowmem_size, (phys_addr_t)total_lowmem);
/* Calculate CAM values */
__cam0 = 1UL << 2 * (__ilog2(ram) / 2);
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index e10d76a860d3..ddeaf9e38ad5 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -191,7 +191,7 @@ _GLOBAL(add_hash_page)
add r3,r3,r0 /* note create_hpte trims to 24 bits */
#ifdef CONFIG_SMP
- rlwinm r8,r1,0,0,18 /* use cpu number to make tag */
+ rlwinm r8,r1,0,0,(31-THREAD_SHIFT) /* use cpu number to make tag */
lwz r8,TI_CPU(r8) /* to go in mmu_hash_lock */
oris r8,r8,12
#endif /* CONFIG_SMP */
@@ -526,7 +526,7 @@ _GLOBAL(flush_hash_pages)
#ifdef CONFIG_SMP
addis r9,r7,mmu_hash_lock@ha
addi r9,r9,mmu_hash_lock@l
- rlwinm r8,r1,0,0,18
+ rlwinm r8,r1,0,0,(31-THREAD_SHIFT)
add r8,r8,r7
lwz r8,TI_CPU(r8)
oris r8,r8,9
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 47325f23c51f..1952b4d3fa7f 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -59,7 +59,10 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
unsigned long total_memory;
unsigned long total_lowmem;
-phys_addr_t memstart_addr;
+phys_addr_t memstart_addr = (phys_addr_t)~0ull;
+EXPORT_SYMBOL(memstart_addr);
+phys_addr_t kernstart_addr;
+EXPORT_SYMBOL(kernstart_addr);
phys_addr_t lowmem_end_addr;
int boot_mapsize;
@@ -68,14 +71,6 @@ unsigned long agp_special_page;
EXPORT_SYMBOL(agp_special_page);
#endif
-#ifdef CONFIG_HIGHMEM
-pte_t *kmap_pte;
-pgprot_t kmap_prot;
-
-EXPORT_SYMBOL(kmap_prot);
-EXPORT_SYMBOL(kmap_pte);
-#endif
-
void MMU_init(void);
/* XXX should be in current.h -- paulus */
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 698bd000f98b..c5ac532a0161 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -72,7 +72,8 @@
#warning TASK_SIZE is smaller than it needs to be.
#endif
-phys_addr_t memstart_addr;
+phys_addr_t memstart_addr = ~0;
+phys_addr_t kernstart_addr;
void free_initmem(void)
{
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 16def4dcff6d..d9e37f365b54 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -45,6 +45,7 @@
#include <asm/tlb.h>
#include <asm/sections.h>
#include <asm/vdso.h>
+#include <asm/fixmap.h>
#include "mmu_decl.h"
@@ -57,6 +58,20 @@ int init_bootmem_done;
int mem_init_done;
unsigned long memory_limit;
+#ifdef CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+EXPORT_SYMBOL(kmap_prot);
+EXPORT_SYMBOL(kmap_pte);
+
+static inline pte_t *virt_to_kpte(unsigned long vaddr)
+{
+ return pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr),
+ vaddr), vaddr), vaddr);
+}
+#endif
+
int page_is_ram(unsigned long pfn)
{
unsigned long paddr = (pfn << PAGE_SHIFT);
@@ -95,15 +110,6 @@ EXPORT_SYMBOL(phys_mem_access_prot);
#ifdef CONFIG_MEMORY_HOTPLUG
-void online_page(struct page *page)
-{
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalram_pages++;
- num_physpages++;
-}
-
#ifdef CONFIG_NUMA
int memory_add_physaddr_to_nid(u64 start)
{
@@ -216,7 +222,7 @@ void __init do_init_bootmem(void)
unsigned long total_pages;
int boot_mapsize;
- max_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
+ max_low_pfn = max_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
total_pages = (lmb_end_of_DRAM() - memstart_addr) >> PAGE_SHIFT;
#ifdef CONFIG_HIGHMEM
total_pages = total_lowmem >> PAGE_SHIFT;
@@ -232,7 +238,8 @@ void __init do_init_bootmem(void)
start = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
- boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
+ min_low_pfn = MEMORY_START >> PAGE_SHIFT;
+ boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn);
/* Add active regions with valid PFNs */
for (i = 0; i < lmb.memory.cnt; i++) {
@@ -310,14 +317,19 @@ void __init paging_init(void)
unsigned long top_of_ram = lmb_end_of_DRAM();
unsigned long max_zone_pfns[MAX_NR_ZONES];
+#ifdef CONFIG_PPC32
+ unsigned long v = __fix_to_virt(__end_of_fixed_addresses - 1);
+ unsigned long end = __fix_to_virt(FIX_HOLE);
+
+ for (; v < end; v += PAGE_SIZE)
+ map_page(v, 0, 0); /* XXX gross */
+#endif
+
#ifdef CONFIG_HIGHMEM
map_page(PKMAP_BASE, 0, 0); /* XXX gross */
- pkmap_page_table = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k
- (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE), PKMAP_BASE);
- map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */
- kmap_pte = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k
- (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN),
- KMAP_FIX_BEGIN);
+ pkmap_page_table = virt_to_kpte(PKMAP_BASE);
+
+ kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
kmap_prot = PAGE_KERNEL;
#endif /* CONFIG_HIGHMEM */
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 1efd631211ef..dc704da363eb 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -18,6 +18,7 @@
#include <linux/cpu.h>
#include <linux/notifier.h>
#include <linux/lmb.h>
+#include <linux/of.h>
#include <asm/sparsemem.h>
#include <asm/prom.h>
#include <asm/system.h>
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 64c44bcc68de..80d1babb230d 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -29,6 +29,7 @@
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/fixmap.h>
#include <asm/io.h>
#include "mmu_decl.h"
@@ -387,3 +388,25 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0));
}
#endif /* CONFIG_DEBUG_PAGEALLOC */
+
+static int fixmaps;
+unsigned long FIXADDR_TOP = 0xfffff000;
+EXPORT_SYMBOL(FIXADDR_TOP);
+
+void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
+{
+ unsigned long address = __fix_to_virt(idx);
+
+ if (idx >= __end_of_fixed_addresses) {
+ BUG();
+ return;
+ }
+
+ map_page(address, phys, flags);
+ fixmaps++;
+}
+
+void __this_fixmap_does_not_exist(void)
+{
+ WARN_ON(1);
+}
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 18b8ebe930d5..5e1e8cf14e75 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -3,11 +3,12 @@
*
* Initial author: Xianghua Xiao <x.xiao@freescale.com>
* Recode: Jason Jin <jason.jin@freescale.com>
+ * York Sun <yorksun@freescale.com>
*
* Rewrite the interrupt routing. remove the 8259PIC support,
* All the integrated device in ULI use sideband interrupt.
*
- * Copyright 2007 Freescale Semiconductor Inc.
+ * Copyright 2008 Freescale Semiconductor Inc.
*
* 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
@@ -38,6 +39,8 @@
#include <sysdev/fsl_pci.h>
#include <sysdev/fsl_soc.h>
+static unsigned char *pixis_bdcfg0, *pixis_arch;
+
static struct of_device_id __initdata mpc8610_ids[] = {
{ .compatible = "fsl,mpc8610-immr", },
{}
@@ -52,8 +55,7 @@ static int __init mpc8610_declare_of_platform_devices(void)
}
machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
-static void __init
-mpc86xx_hpcd_init_irq(void)
+static void __init mpc86xx_hpcd_init_irq(void)
{
struct mpic *mpic1;
struct device_node *np;
@@ -161,12 +163,159 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288);
#endif /* CONFIG_PCI */
-static void __init
-mpc86xx_hpcd_setup_arch(void)
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+static u32 get_busfreq(void)
{
-#ifdef CONFIG_PCI
- struct device_node *np;
+ struct device_node *node;
+
+ u32 fs_busfreq = 0;
+ node = of_find_node_by_type(NULL, "cpu");
+ if (node) {
+ unsigned int size;
+ const unsigned int *prop =
+ of_get_property(node, "bus-frequency", &size);
+ if (prop)
+ fs_busfreq = *prop;
+ of_node_put(node);
+ };
+ return fs_busfreq;
+}
+
+unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
+ int monitor_port)
+{
+ static const unsigned long pixelformat[][3] = {
+ {0x88882317, 0x88083218, 0x65052119},
+ {0x88883316, 0x88082219, 0x65053118},
+ };
+ unsigned int pix_fmt, arch_monitor;
+
+ arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1;
+ /* DVI port for board version 0x01 */
+
+ if (bits_per_pixel == 32)
+ pix_fmt = pixelformat[arch_monitor][0];
+ else if (bits_per_pixel == 24)
+ pix_fmt = pixelformat[arch_monitor][1];
+ else if (bits_per_pixel == 16)
+ pix_fmt = pixelformat[arch_monitor][2];
+ else
+ pix_fmt = pixelformat[1][0];
+
+ return pix_fmt;
+}
+
+void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+ int i;
+ if (monitor_port == 2) { /* dual link LVDS */
+ for (i = 0; i < 256*3; i++)
+ gamma_table_base[i] = (gamma_table_base[i] << 2) |
+ ((gamma_table_base[i] >> 6) & 0x03);
+ }
+}
+
+void mpc8610hpcd_set_monitor_port(int monitor_port)
+{
+ static const u8 bdcfg[] = {0xBD, 0xB5, 0xA5};
+ if (monitor_port < 3)
+ *pixis_bdcfg0 = bdcfg[monitor_port];
+}
+
+void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
+{
+ u32 __iomem *clkdvdr;
+ u32 temp;
+ /* variables for pixel clock calcs */
+ ulong bestval, bestfreq, speed_ccb, minpixclock, maxpixclock;
+ ulong pixval;
+ long err;
+ int i;
+
+ clkdvdr = ioremap(get_immrbase() + 0xe0800, sizeof(u32));
+ if (!clkdvdr) {
+ printk(KERN_ERR "Err: can't map clock divider register!\n");
+ return;
+ }
+
+ /* Pixel Clock configuration */
+ pr_debug("DIU: Bus Frequency = %d\n", get_busfreq());
+ speed_ccb = get_busfreq();
+
+ /* Calculate the pixel clock with the smallest error */
+ /* calculate the following in steps to avoid overflow */
+ pr_debug("DIU pixclock in ps - %d\n", pixclock);
+ temp = 1000000000/pixclock;
+ temp *= 1000;
+ pixclock = temp;
+ pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+ temp = pixclock * 5 / 100;
+ pr_debug("deviation = %d\n", temp);
+ minpixclock = pixclock - temp;
+ maxpixclock = pixclock + temp;
+ pr_debug("DIU minpixclock - %lu\n", minpixclock);
+ pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
+ pixval = speed_ccb/pixclock;
+ pr_debug("DIU pixval = %lu\n", pixval);
+
+ err = 100000000;
+ bestval = pixval;
+ pr_debug("DIU bestval = %lu\n", bestval);
+
+ bestfreq = 0;
+ for (i = -1; i <= 1; i++) {
+ temp = speed_ccb / ((pixval+i) + 1);
+ pr_debug("DIU test pixval i= %d, pixval=%lu, temp freq. = %u\n",
+ i, pixval, temp);
+ if ((temp < minpixclock) || (temp > maxpixclock))
+ pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
+ minpixclock, maxpixclock);
+ else if (abs(temp - pixclock) < err) {
+ pr_debug("Entered the else if block %d\n", i);
+ err = abs(temp - pixclock);
+ bestval = pixval+i;
+ bestfreq = temp;
+ }
+ }
+
+ pr_debug("DIU chose = %lx\n", bestval);
+ pr_debug("DIU error = %ld\n NomPixClk ", err);
+ pr_debug("DIU: Best Freq = %lx\n", bestfreq);
+ /* Modify PXCLK in GUTS CLKDVDR */
+ pr_debug("DIU: Current value of CLKDVDR = 0x%08x\n", (*clkdvdr));
+ temp = (*clkdvdr) & 0x2000FFFF;
+ *clkdvdr = temp; /* turn off clock */
+ *clkdvdr = temp | 0x80000000 | (((bestval) & 0x1F) << 16);
+ pr_debug("DIU: Modified value of CLKDVDR = 0x%08x\n", (*clkdvdr));
+ iounmap(clkdvdr);
+}
+
+ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE,
+ "%c0 - DVI\n"
+ "%c1 - Single link LVDS\n"
+ "%c2 - Dual link LVDS\n",
+ monitor_port == 0 ? '*' : ' ',
+ monitor_port == 1 ? '*' : ' ',
+ monitor_port == 2 ? '*' : ' ');
+}
+
+int mpc8610hpcd_set_sysfs_monitor_port(int val)
+{
+ return val < 3 ? val : 0;
+}
+
#endif
+
+static void __init mpc86xx_hpcd_setup_arch(void)
+{
+ struct resource r;
+ struct device_node *np;
+ unsigned char *pixis;
+
if (ppc_md.progress)
ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0);
@@ -183,6 +332,30 @@ mpc86xx_hpcd_setup_arch(void)
}
}
#endif
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+ preallocate_diu_videomemory();
+ diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format;
+ diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table;
+ diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port;
+ diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock;
+ diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port;
+ diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port;
+#endif
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");
+ if (np) {
+ of_address_to_resource(np, 0, &r);
+ of_node_put(np);
+ pixis = ioremap(r.start, 32);
+ if (!pixis) {
+ printk(KERN_ERR "Err: can't map FPGA cfg register!\n");
+ return;
+ }
+ pixis_bdcfg0 = pixis + 8;
+ pixis_arch = pixis + 1;
+ } else
+ printk(KERN_ERR "Err: "
+ "can't find device node 'fsl,fpga-pixis'\n");
printk("MPC86xx HPCD board from Freescale Semiconductor\n");
}
@@ -200,8 +373,7 @@ static int __init mpc86xx_hpcd_probe(void)
return 0;
}
-static long __init
-mpc86xx_time_init(void)
+static long __init mpc86xx_time_init(void)
{
unsigned int temp;
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f38c50b4ce56..87454c526973 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -45,7 +45,6 @@ source "arch/powerpc/platforms/powermac/Kconfig"
source "arch/powerpc/platforms/prep/Kconfig"
source "arch/powerpc/platforms/maple/Kconfig"
source "arch/powerpc/platforms/pasemi/Kconfig"
-source "arch/powerpc/platforms/celleb/Kconfig"
source "arch/powerpc/platforms/ps3/Kconfig"
source "arch/powerpc/platforms/cell/Kconfig"
source "arch/powerpc/platforms/8xx/Kconfig"
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 5fc7fac10e93..f7efaa925a13 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -220,8 +220,8 @@ config SMP
If you don't know what to do here, say N.
config NR_CPUS
- int "Maximum number of CPUs (2-128)"
- range 2 128
+ int "Maximum number of CPUs (2-1024)"
+ range 2 1024
depends on SMP
default "32" if PPC64
default "4"
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index a984894466d9..423a0234dc31 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -24,5 +24,4 @@ obj-$(CONFIG_PPC_MAPLE) += maple/
obj-$(CONFIG_PPC_PASEMI) += pasemi/
obj-$(CONFIG_PPC_CELL) += cell/
obj-$(CONFIG_PPC_PS3) += ps3/
-obj-$(CONFIG_PPC_CELLEB) += celleb/
obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 2f169991896d..3959fcfe731c 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -25,6 +25,19 @@ config PPC_IBM_CELL_BLADE
select PPC_UDBG_16550
select UDBG_RTAS_CONSOLE
+config PPC_CELLEB
+ bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL
+ select PPC_CELL_NATIVE
+ select PPC_RTAS
+ select PPC_INDIRECT_IO
+ select PPC_OF_PLATFORM_PCI
+ select HAS_TXX9_SERIAL
+ select PPC_UDBG_BEAT
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_MMIO
+
menu "Cell Broadband Engine options"
depends on PPC_CELL
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index c89964c6fb1f..c2a7e4e5ddf9 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
cbe_regs.o spider-pic.o \
- pervasive.o pmu.o io-workarounds.o
+ pervasive.o pmu.o io-workarounds.o \
+ spider-pci.o
obj-$(CONFIG_CBE_RAS) += ras.o
obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
@@ -26,3 +27,20 @@ obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
spufs/
obj-$(CONFIG_PCI_MSI) += axon_msi.o
+
+
+# celleb stuff
+ifeq ($(CONFIG_PPC_CELLEB),y)
+obj-y += celleb_setup.o \
+ celleb_pci.o celleb_scc_epci.o \
+ celleb_scc_pciex.o \
+ celleb_scc_uhc.o \
+ io-workarounds.o spider-pci.o \
+ beat.o beat_htab.o beat_hvCall.o \
+ beat_interrupt.o beat_iommu.o
+
+obj-$(CONFIG_SMP) += beat_smp.o
+obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o
+obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o
+obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o
+endif
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index d95e71dee91f..c39f5c225f2e 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -123,7 +123,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
return NULL;
}
- for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+ for (; dn; dn = of_get_next_parent(dn)) {
ph = of_get_property(dn, "msi-translator", NULL);
if (ph)
break;
@@ -169,7 +169,7 @@ static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
{
- struct device_node *dn, *tmp;
+ struct device_node *dn;
struct msi_desc *entry;
int len;
const u32 *prop;
@@ -182,7 +182,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
- for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+ for (; dn; dn = of_get_next_parent(dn)) {
if (entry->msi_attrib.is_64) {
prop = of_get_property(dn, "msi-address-64", &len);
if (prop)
diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/cell/beat.c
index b64b171f245b..48c690ea65da 100644
--- a/arch/powerpc/platforms/celleb/beat.c
+++ b/arch/powerpc/platforms/cell/beat.c
@@ -33,7 +33,7 @@
#include "beat_wrapper.h"
#include "beat.h"
-#include "interrupt.h"
+#include "beat_interrupt.h"
static int beat_pm_poweroff_flag;
diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/cell/beat.h
index 32c8efcedc80..32c8efcedc80 100644
--- a/arch/powerpc/platforms/celleb/beat.h
+++ b/arch/powerpc/platforms/cell/beat.h
diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/cell/beat_htab.c
index 81467ff055c8..81467ff055c8 100644
--- a/arch/powerpc/platforms/celleb/htab.c
+++ b/arch/powerpc/platforms/cell/beat_htab.c
diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/cell/beat_hvCall.S
index 74c817448948..74c817448948 100644
--- a/arch/powerpc/platforms/celleb/hvCall.S
+++ b/arch/powerpc/platforms/cell/beat_hvCall.S
diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 69562a867876..192a93509372 100644
--- a/arch/powerpc/platforms/celleb/interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -26,7 +26,7 @@
#include <asm/machdep.h>
-#include "interrupt.h"
+#include "beat_interrupt.h"
#include "beat_wrapper.h"
#define MAX_IRQS NR_IRQS
diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h
index b470fd0051f1..b470fd0051f1 100644
--- a/arch/powerpc/platforms/celleb/interrupt.h
+++ b/arch/powerpc/platforms/cell/beat_interrupt.h
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/cell/beat_iommu.c
index 93b0efddd658..93b0efddd658 100644
--- a/arch/powerpc/platforms/celleb/iommu.c
+++ b/arch/powerpc/platforms/cell/beat_iommu.c
diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/cell/beat_smp.c
index a7631250aeb4..26efc204c47f 100644
--- a/arch/powerpc/platforms/celleb/smp.c
+++ b/arch/powerpc/platforms/cell/beat_smp.c
@@ -37,7 +37,7 @@
#include <asm/machdep.h>
#include <asm/udbg.h>
-#include "interrupt.h"
+#include "beat_interrupt.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/cell/beat_spu_priv1.c
index bcc17f7fe8ad..bcc17f7fe8ad 100644
--- a/arch/powerpc/platforms/celleb/spu_priv1.c
+++ b/arch/powerpc/platforms/cell/beat_spu_priv1.c
diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/cell/beat_syscall.h
index 8580dc7e1798..8580dc7e1798 100644
--- a/arch/powerpc/platforms/celleb/beat_syscall.h
+++ b/arch/powerpc/platforms/cell/beat_syscall.h
diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/cell/beat_udbg.c
index 6b418f6b6175..6b418f6b6175 100644
--- a/arch/powerpc/platforms/celleb/udbg_beat.c
+++ b/arch/powerpc/platforms/cell/beat_udbg.c
diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/cell/beat_wrapper.h
index b47dfda48d06..b47dfda48d06 100644
--- a/arch/powerpc/platforms/celleb/beat_wrapper.h
+++ b/arch/powerpc/platforms/cell/beat_wrapper.h
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/cell/celleb_pci.c
index 51b390d34e4d..f39a3b2a1667 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/cell/celleb_pci.c
@@ -37,12 +37,11 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
-#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
-#include "pci.h"
-#include "interrupt.h"
+#include "io-workarounds.h"
+#include "celleb_pci.h"
#define MAX_PCI_DEVICES 32
#define MAX_PCI_FUNCTIONS 8
@@ -190,7 +189,7 @@ static int celleb_fake_pci_read_config(struct pci_bus *bus,
static int celleb_fake_pci_write_config(struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 val)
+ unsigned int devfn, int where, int size, u32 val)
{
char *config;
struct device_node *node;
@@ -457,33 +456,42 @@ static int __init celleb_setup_fake_pci(struct device_node *dev,
return 0;
}
-void __init fake_pci_workaround_init(struct pci_controller *phb)
-{
- /**
- * We will add fake pci bus to scc_pci_bus for the purpose to improve
- * I/O Macro performance. But device-tree and device drivers
- * are not ready to use address with a token.
- */
-
- /* celleb_pci_add_one(phb, NULL); */
-}
+static struct celleb_phb_spec celleb_fake_pci_spec __initdata = {
+ .setup = celleb_setup_fake_pci,
+};
static struct of_device_id celleb_phb_match[] __initdata = {
{
.name = "pci-pseudo",
- .data = celleb_setup_fake_pci,
+ .data = &celleb_fake_pci_spec,
}, {
.name = "epci",
- .data = celleb_setup_epci,
+ .data = &celleb_epci_spec,
+ }, {
+ .name = "pcie",
+ .data = &celleb_pciex_spec,
}, {
},
};
+static int __init celleb_io_workaround_init(struct pci_controller *phb,
+ struct celleb_phb_spec *phb_spec)
+{
+ if (phb_spec->ops) {
+ iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init,
+ phb_spec->iowa_data);
+ io_workaround_init();
+ }
+
+ return 0;
+}
+
int __init celleb_setup_phb(struct pci_controller *phb)
{
struct device_node *dev = phb->dn;
const struct of_device_id *match;
- int (*setup_func)(struct device_node *, struct pci_controller *);
+ struct celleb_phb_spec *phb_spec;
+ int rc;
match = of_match_node(celleb_phb_match, dev);
if (!match)
@@ -492,8 +500,12 @@ int __init celleb_setup_phb(struct pci_controller *phb)
phb_set_bus_ranges(dev, phb);
phb->buid = 1;
- setup_func = match->data;
- return (*setup_func)(dev, phb);
+ phb_spec = match->data;
+ rc = (*phb_spec->setup)(dev, phb);
+ if (rc)
+ return 1;
+
+ return celleb_io_workaround_init(phb, phb_spec);
}
int celleb_pci_probe_mode(struct pci_bus *bus)
diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/cell/celleb_pci.h
index 5d5544ffeddb..4cba1523ec50 100644
--- a/arch/powerpc/platforms/celleb/pci.h
+++ b/arch/powerpc/platforms/cell/celleb_pci.h
@@ -27,16 +27,19 @@
#include <asm/prom.h>
#include <asm/ppc-pci.h>
+#include "io-workarounds.h"
+
+struct celleb_phb_spec {
+ int (*setup)(struct device_node *, struct pci_controller *);
+ struct ppc_pci_io *ops;
+ int (*iowa_init)(struct iowa_bus *, void *);
+ void *iowa_data;
+};
+
extern int celleb_setup_phb(struct pci_controller *);
extern int celleb_pci_probe_mode(struct pci_bus *);
-extern int celleb_setup_epci(struct device_node *, struct pci_controller *);
-
-extern void *celleb_dummy_page_va;
-extern int __init celleb_pci_workaround_init(void);
-extern void __init celleb_pci_add_one(struct pci_controller *,
- void (*)(struct pci_controller *));
-extern void fake_pci_workaround_init(struct pci_controller *);
-extern void epci_workaround_init(struct pci_controller *);
+extern struct celleb_phb_spec celleb_epci_spec;
+extern struct celleb_phb_spec celleb_pciex_spec;
#endif /* _CELLEB_PCI_H */
diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/cell/celleb_scc.h
index 6be1542a6e66..b596a711c348 100644
--- a/arch/powerpc/platforms/celleb/scc.h
+++ b/arch/powerpc/platforms/cell/celleb_scc.h
@@ -125,6 +125,93 @@
/* bits for SCC_EPCI_CNTOPT */
#define SCC_EPCI_CNTOPT_O2PMB 0x00000002
+/* SCC PCIEXC SMMIO registers */
+#define PEXCADRS 0x000
+#define PEXCWDATA 0x004
+#define PEXCRDATA 0x008
+#define PEXDADRS 0x010
+#define PEXDCMND 0x014
+#define PEXDWDATA 0x018
+#define PEXDRDATA 0x01c
+#define PEXREQID 0x020
+#define PEXTIDMAP 0x024
+#define PEXINTMASK 0x028
+#define PEXINTSTS 0x02c
+#define PEXAERRMASK 0x030
+#define PEXAERRSTS 0x034
+#define PEXPRERRMASK 0x040
+#define PEXPRERRSTS 0x044
+#define PEXPRERRID01 0x048
+#define PEXPRERRID23 0x04c
+#define PEXVDMASK 0x050
+#define PEXVDSTS 0x054
+#define PEXRCVCPLIDA 0x060
+#define PEXLENERRIDA 0x068
+#define PEXPHYPLLST 0x070
+#define PEXDMRDEN0 0x100
+#define PEXDMRDADR0 0x104
+#define PEXDMRDENX 0x110
+#define PEXDMRDADRX 0x114
+#define PEXECMODE 0xf00
+#define PEXMAEA(n) (0xf50 + (8 * n))
+#define PEXMAEC(n) (0xf54 + (8 * n))
+#define PEXCCRCTRL 0xff0
+
+/* SCC PCIEXC bits and shifts for PEXCADRS */
+#define PEXCADRS_BYTE_EN_SHIFT 20
+#define PEXCADRS_CMD_SHIFT 16
+#define PEXCADRS_CMD_READ (0xa << PEXCADRS_CMD_SHIFT)
+#define PEXCADRS_CMD_WRITE (0xb << PEXCADRS_CMD_SHIFT)
+
+/* SCC PCIEXC shifts for PEXDADRS */
+#define PEXDADRS_BUSNO_SHIFT 20
+#define PEXDADRS_DEVNO_SHIFT 15
+#define PEXDADRS_FUNCNO_SHIFT 12
+
+/* SCC PCIEXC bits and shifts for PEXDCMND */
+#define PEXDCMND_BYTE_EN_SHIFT 4
+#define PEXDCMND_IO_READ 0x2
+#define PEXDCMND_IO_WRITE 0x3
+#define PEXDCMND_CONFIG_READ 0xa
+#define PEXDCMND_CONFIG_WRITE 0xb
+
+/* SCC PCIEXC bits for PEXPHYPLLST */
+#define PEXPHYPLLST_PEXPHYAPLLST 0x00000001
+
+/* SCC PCIEXC bits for PEXECMODE */
+#define PEXECMODE_ALL_THROUGH 0x00000000
+#define PEXECMODE_ALL_8BIT 0x00550155
+#define PEXECMODE_ALL_16BIT 0x00aa02aa
+
+/* SCC PCIEXC bits for PEXCCRCTRL */
+#define PEXCCRCTRL_PEXIPCOREEN 0x00040000
+#define PEXCCRCTRL_PEXIPCONTEN 0x00020000
+#define PEXCCRCTRL_PEXPHYPLLEN 0x00010000
+#define PEXCCRCTRL_PCIEXCAOCKEN 0x00000100
+
+/* SCC PCIEXC port configuration registers */
+#define PEXTCERRCHK 0x21c
+#define PEXTAMAPB0 0x220
+#define PEXTAMAPL0 0x224
+#define PEXTAMAPB(n) (PEXTAMAPB0 + 8 * (n))
+#define PEXTAMAPL(n) (PEXTAMAPL0 + 8 * (n))
+#define PEXCHVC0P 0x500
+#define PEXCHVC0NP 0x504
+#define PEXCHVC0C 0x508
+#define PEXCDVC0P 0x50c
+#define PEXCDVC0NP 0x510
+#define PEXCDVC0C 0x514
+#define PEXCHVCXP 0x518
+#define PEXCHVCXNP 0x51c
+#define PEXCHVCXC 0x520
+#define PEXCDVCXP 0x524
+#define PEXCDVCXNP 0x528
+#define PEXCDVCXC 0x52c
+#define PEXCTTRG 0x530
+#define PEXTSCTRL 0x700
+#define PEXTSSTS 0x704
+#define PEXSKPCTRL 0x708
+
/* UHC registers */
#define SCC_UHC_CKRCTRL 0xff0
#define SCC_UHC_ECMODE 0xf00
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/cell/celleb_scc_epci.c
index a999b393f6f6..08c285b10e30 100644
--- a/arch/powerpc/platforms/celleb/scc_epci.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_epci.c
@@ -30,23 +30,17 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
-#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
-#include "scc.h"
-#include "pci.h"
-#include "interrupt.h"
+#include "celleb_scc.h"
+#include "celleb_pci.h"
#define MAX_PCI_DEVICES 32
#define MAX_PCI_FUNCTIONS 8
#define iob() __asm__ __volatile__("eieio; sync":::"memory")
-struct epci_private {
- dma_addr_t dummy_page_da;
-};
-
static inline PCI_IO_ADDR celleb_epci_get_epci_base(
struct pci_controller *hose)
{
@@ -71,42 +65,6 @@ static inline PCI_IO_ADDR celleb_epci_get_epci_cfg(
return hose->cfg_data;
}
-static void scc_epci_dummy_read(struct pci_controller *hose)
-{
- PCI_IO_ADDR epci_base;
- u32 val;
-
- epci_base = celleb_epci_get_epci_base(hose);
-
- val = in_be32(epci_base + SCC_EPCI_WATRP);
- iosync();
-
- return;
-}
-
-void __init epci_workaround_init(struct pci_controller *hose)
-{
- PCI_IO_ADDR epci_base;
- PCI_IO_ADDR reg;
- struct epci_private *private = hose->private_data;
-
- BUG_ON(!private);
-
- private->dummy_page_da = dma_map_single(hose->parent,
- celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE);
- if (private->dummy_page_da == DMA_ERROR_CODE) {
- printk(KERN_ERR "EPCI: dummy read disabled. "
- "Map dummy page failed.\n");
- return;
- }
-
- celleb_pci_add_one(hose, scc_epci_dummy_read);
- epci_base = celleb_epci_get_epci_base(hose);
-
- reg = epci_base + SCC_EPCI_DUMYRADR;
- out_be32(reg, private->dummy_page_da);
-}
-
static inline void clear_and_disable_master_abort_interrupt(
struct pci_controller *hose)
{
@@ -151,10 +109,8 @@ static int celleb_epci_check_abort(struct pci_controller *hose,
return PCIBIOS_SUCCESSFUL;
}
-static PCI_IO_ADDR celleb_epci_make_config_addr(
- struct pci_bus *bus,
- struct pci_controller *hose,
- unsigned int devfn, int where)
+static PCI_IO_ADDR celleb_epci_make_config_addr(struct pci_bus *bus,
+ struct pci_controller *hose, unsigned int devfn, int where)
{
PCI_IO_ADDR addr;
@@ -425,8 +381,8 @@ static int __init celleb_epci_init(struct pci_controller *hose)
return 0;
}
-int __init celleb_setup_epci(struct device_node *node,
- struct pci_controller *hose)
+static int __init celleb_setup_epci(struct device_node *node,
+ struct pci_controller *hose)
{
struct resource r;
@@ -450,8 +406,7 @@ int __init celleb_setup_epci(struct device_node *node,
if (!hose->cfg_addr)
goto error;
pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n",
- r.start, (unsigned long)hose->cfg_addr,
- (r.end - r.start + 1));
+ r.start, (unsigned long)hose->cfg_addr, (r.end - r.start + 1));
if (of_address_to_resource(node, 2, &r))
goto error;
@@ -459,14 +414,7 @@ int __init celleb_setup_epci(struct device_node *node,
if (!hose->cfg_data)
goto error;
pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n",
- r.start, (unsigned long)hose->cfg_data,
- (r.end - r.start + 1));
-
- hose->private_data = kzalloc(sizeof(struct epci_private), GFP_KERNEL);
- if (hose->private_data == NULL) {
- printk(KERN_ERR "EPCI: no memory for private data.\n");
- goto error;
- }
+ r.start, (unsigned long)hose->cfg_data, (r.end - r.start + 1));
hose->ops = &celleb_epci_ops;
celleb_epci_init(hose);
@@ -474,8 +422,6 @@ int __init celleb_setup_epci(struct device_node *node,
return 0;
error:
- kfree(hose->private_data);
-
if (hose->cfg_addr)
iounmap(hose->cfg_addr);
@@ -483,3 +429,10 @@ error:
iounmap(hose->cfg_data);
return 1;
}
+
+struct celleb_phb_spec celleb_epci_spec __initdata = {
+ .setup = celleb_setup_epci,
+ .ops = &spiderpci_ops,
+ .iowa_init = &spiderpci_iowa_init,
+ .iowa_data = (void *)0,
+};
diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
new file mode 100644
index 000000000000..31da84c458d2
--- /dev/null
+++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c
@@ -0,0 +1,547 @@
+/*
+ * Support for Celleb PCI-Express.
+ *
+ * (C) Copyright 2007-2008 TOSHIBA CORPORATION
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/iommu.h>
+#include <asm/byteorder.h>
+
+#include "celleb_scc.h"
+#include "celleb_pci.h"
+
+#define PEX_IN(base, off) in_be32((void __iomem *)(base) + (off))
+#define PEX_OUT(base, off, data) out_be32((void __iomem *)(base) + (off), (data))
+
+static void scc_pciex_io_flush(struct iowa_bus *bus)
+{
+ (void)PEX_IN(bus->phb->cfg_addr, PEXDMRDEN0);
+}
+
+/*
+ * Memory space access to device on PCIEX
+ */
+#define PCIEX_MMIO_READ(name, ret) \
+static ret scc_pciex_##name(const PCI_IO_ADDR addr) \
+{ \
+ ret val = __do_##name(addr); \
+ scc_pciex_io_flush(iowa_mem_find_bus(addr)); \
+ return val; \
+}
+
+#define PCIEX_MMIO_READ_STR(name) \
+static void scc_pciex_##name(const PCI_IO_ADDR addr, void *buf, \
+ unsigned long count) \
+{ \
+ __do_##name(addr, buf, count); \
+ scc_pciex_io_flush(iowa_mem_find_bus(addr)); \
+}
+
+PCIEX_MMIO_READ(readb, u8)
+PCIEX_MMIO_READ(readw, u16)
+PCIEX_MMIO_READ(readl, u32)
+PCIEX_MMIO_READ(readq, u64)
+PCIEX_MMIO_READ(readw_be, u16)
+PCIEX_MMIO_READ(readl_be, u32)
+PCIEX_MMIO_READ(readq_be, u64)
+PCIEX_MMIO_READ_STR(readsb)
+PCIEX_MMIO_READ_STR(readsw)
+PCIEX_MMIO_READ_STR(readsl)
+
+static void scc_pciex_memcpy_fromio(void *dest, const PCI_IO_ADDR src,
+ unsigned long n)
+{
+ __do_memcpy_fromio(dest, src, n);
+ scc_pciex_io_flush(iowa_mem_find_bus(src));
+}
+
+/*
+ * I/O port access to devices on PCIEX.
+ */
+
+static inline unsigned long get_bus_address(struct pci_controller *phb,
+ unsigned long port)
+{
+ return port - ((unsigned long)(phb->io_base_virt) - _IO_BASE);
+}
+
+static u32 scc_pciex_read_port(struct pci_controller *phb,
+ unsigned long port, int size)
+{
+ unsigned int byte_enable;
+ unsigned int cmd, shift;
+ unsigned long addr;
+ u32 data, ret;
+
+ BUG_ON(((port & 0x3ul) + size) > 4);
+
+ addr = get_bus_address(phb, port);
+ shift = addr & 0x3ul;
+ byte_enable = ((1 << size) - 1) << shift;
+ cmd = PEXDCMND_IO_READ | (byte_enable << PEXDCMND_BYTE_EN_SHIFT);
+ PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul));
+ PEX_OUT(phb->cfg_addr, PEXDCMND, cmd);
+ data = PEX_IN(phb->cfg_addr, PEXDRDATA);
+ ret = (data >> (shift * 8)) & (0xFFFFFFFF >> ((4 - size) * 8));
+
+ pr_debug("PCIEX:PIO READ:port=0x%lx, addr=0x%lx, size=%d, be=%x,"
+ " cmd=%x, data=%x, ret=%x\n", port, addr, size, byte_enable,
+ cmd, data, ret);
+
+ return ret;
+}
+
+static void scc_pciex_write_port(struct pci_controller *phb,
+ unsigned long port, int size, u32 val)
+{
+ unsigned int byte_enable;
+ unsigned int cmd, shift;
+ unsigned long addr;
+ u32 data;
+
+ BUG_ON(((port & 0x3ul) + size) > 4);
+
+ addr = get_bus_address(phb, port);
+ shift = addr & 0x3ul;
+ byte_enable = ((1 << size) - 1) << shift;
+ cmd = PEXDCMND_IO_WRITE | (byte_enable << PEXDCMND_BYTE_EN_SHIFT);
+ data = (val & (0xFFFFFFFF >> (4 - size) * 8)) << (shift * 8);
+ PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul));
+ PEX_OUT(phb->cfg_addr, PEXDCMND, cmd);
+ PEX_OUT(phb->cfg_addr, PEXDWDATA, data);
+
+ pr_debug("PCIEX:PIO WRITE:port=0x%lx, addr=%lx, size=%d, val=%x,"
+ " be=%x, cmd=%x, data=%x\n", port, addr, size, val,
+ byte_enable, cmd, data);
+}
+
+static u8 __scc_pciex_inb(struct pci_controller *phb, unsigned long port)
+{
+ return (u8)scc_pciex_read_port(phb, port, 1);
+}
+
+static u16 __scc_pciex_inw(struct pci_controller *phb, unsigned long port)
+{
+ u32 data;
+ if ((port & 0x3ul) < 3)
+ data = scc_pciex_read_port(phb, port, 2);
+ else {
+ u32 d1 = scc_pciex_read_port(phb, port, 1);
+ u32 d2 = scc_pciex_read_port(phb, port + 1, 1);
+ data = d1 | (d2 << 8);
+ }
+ return (u16)data;
+}
+
+static u32 __scc_pciex_inl(struct pci_controller *phb, unsigned long port)
+{
+ unsigned int mod = port & 0x3ul;
+ u32 data;
+ if (mod == 0)
+ data = scc_pciex_read_port(phb, port, 4);
+ else {
+ u32 d1 = scc_pciex_read_port(phb, port, 4 - mod);
+ u32 d2 = scc_pciex_read_port(phb, port + 1, mod);
+ data = d1 | (d2 << (mod * 8));
+ }
+ return data;
+}
+
+static void __scc_pciex_outb(struct pci_controller *phb,
+ u8 val, unsigned long port)
+{
+ scc_pciex_write_port(phb, port, 1, (u32)val);
+}
+
+static void __scc_pciex_outw(struct pci_controller *phb,
+ u16 val, unsigned long port)
+{
+ if ((port & 0x3ul) < 3)
+ scc_pciex_write_port(phb, port, 2, (u32)val);
+ else {
+ u32 d1 = val & 0x000000FF;
+ u32 d2 = (val & 0x0000FF00) >> 8;
+ scc_pciex_write_port(phb, port, 1, d1);
+ scc_pciex_write_port(phb, port + 1, 1, d2);
+ }
+}
+
+static void __scc_pciex_outl(struct pci_controller *phb,
+ u32 val, unsigned long port)
+{
+ unsigned int mod = port & 0x3ul;
+ if (mod == 0)
+ scc_pciex_write_port(phb, port, 4, val);
+ else {
+ u32 d1 = val & (0xFFFFFFFFul >> (mod * 8));
+ u32 d2 = val >> ((4 - mod) * 8);
+ scc_pciex_write_port(phb, port, 4 - mod, d1);
+ scc_pciex_write_port(phb, port + 1, mod, d2);
+ }
+}
+
+#define PCIEX_PIO_FUNC(size, name) \
+static u##size scc_pciex_in##name(unsigned long port) \
+{ \
+ struct iowa_bus *bus = iowa_pio_find_bus(port); \
+ u##size data = __scc_pciex_in##name(bus->phb, port); \
+ scc_pciex_io_flush(bus); \
+ return data; \
+} \
+static void scc_pciex_ins##name(unsigned long p, void *b, unsigned long c) \
+{ \
+ struct iowa_bus *bus = iowa_pio_find_bus(p); \
+ u##size *dst = b; \
+ for (; c != 0; c--, dst++) \
+ *dst = cpu_to_le##size(__scc_pciex_in##name(bus->phb, p)); \
+ scc_pciex_io_flush(bus); \
+} \
+static void scc_pciex_out##name(u##size val, unsigned long port) \
+{ \
+ struct iowa_bus *bus = iowa_pio_find_bus(port); \
+ __scc_pciex_out##name(bus->phb, val, port); \
+} \
+static void scc_pciex_outs##name(unsigned long p, const void *b, \
+ unsigned long c) \
+{ \
+ struct iowa_bus *bus = iowa_pio_find_bus(p); \
+ const u##size *src = b; \
+ for (; c != 0; c--, src++) \
+ __scc_pciex_out##name(bus->phb, le##size##_to_cpu(*src), p); \
+}
+#define cpu_to_le8(x) (x)
+#define le8_to_cpu(x) (x)
+PCIEX_PIO_FUNC(8, b)
+PCIEX_PIO_FUNC(16, w)
+PCIEX_PIO_FUNC(32, l)
+
+static struct ppc_pci_io scc_pciex_ops = {
+ .readb = scc_pciex_readb,
+ .readw = scc_pciex_readw,
+ .readl = scc_pciex_readl,
+ .readq = scc_pciex_readq,
+ .readw_be = scc_pciex_readw_be,
+ .readl_be = scc_pciex_readl_be,
+ .readq_be = scc_pciex_readq_be,
+ .readsb = scc_pciex_readsb,
+ .readsw = scc_pciex_readsw,
+ .readsl = scc_pciex_readsl,
+ .memcpy_fromio = scc_pciex_memcpy_fromio,
+ .inb = scc_pciex_inb,
+ .inw = scc_pciex_inw,
+ .inl = scc_pciex_inl,
+ .outb = scc_pciex_outb,
+ .outw = scc_pciex_outw,
+ .outl = scc_pciex_outl,
+ .insb = scc_pciex_insb,
+ .insw = scc_pciex_insw,
+ .insl = scc_pciex_insl,
+ .outsb = scc_pciex_outsb,
+ .outsw = scc_pciex_outsw,
+ .outsl = scc_pciex_outsl,
+};
+
+static int __init scc_pciex_iowa_init(struct iowa_bus *bus, void *data)
+{
+ dma_addr_t dummy_page_da;
+ void *dummy_page_va;
+
+ dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!dummy_page_va) {
+ pr_err("PCIEX:Alloc dummy_page_va failed\n");
+ return -1;
+ }
+
+ dummy_page_da = dma_map_single(bus->phb->parent, dummy_page_va,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dummy_page_da)) {
+ pr_err("PCIEX:Map dummy page failed.\n");
+ kfree(dummy_page_va);
+ return -1;
+ }
+
+ PEX_OUT(bus->phb->cfg_addr, PEXDMRDADR0, dummy_page_da);
+
+ return 0;
+}
+
+/*
+ * config space access
+ */
+#define MK_PEXDADRS(bus_no, dev_no, func_no, addr) \
+ ((uint32_t)(((addr) & ~0x3UL) | \
+ ((bus_no) << PEXDADRS_BUSNO_SHIFT) | \
+ ((dev_no) << PEXDADRS_DEVNO_SHIFT) | \
+ ((func_no) << PEXDADRS_FUNCNO_SHIFT)))
+
+#define MK_PEXDCMND_BYTE_EN(addr, size) \
+ ((((0x1 << (size))-1) << ((addr) & 0x3)) << PEXDCMND_BYTE_EN_SHIFT)
+#define MK_PEXDCMND(cmd, addr, size) ((cmd) | MK_PEXDCMND_BYTE_EN(addr, size))
+
+static uint32_t config_read_pciex_dev(unsigned int __iomem *base,
+ uint64_t bus_no, uint64_t dev_no, uint64_t func_no,
+ uint64_t off, uint64_t size)
+{
+ uint32_t ret;
+ uint32_t addr, cmd;
+
+ addr = MK_PEXDADRS(bus_no, dev_no, func_no, off);
+ cmd = MK_PEXDCMND(PEXDCMND_CONFIG_READ, off, size);
+ PEX_OUT(base, PEXDADRS, addr);
+ PEX_OUT(base, PEXDCMND, cmd);
+ ret = (PEX_IN(base, PEXDRDATA)
+ >> ((off & (4-size)) * 8)) & ((0x1 << (size * 8)) - 1);
+ return ret;
+}
+
+static void config_write_pciex_dev(unsigned int __iomem *base, uint64_t bus_no,
+ uint64_t dev_no, uint64_t func_no, uint64_t off, uint64_t size,
+ uint32_t data)
+{
+ uint32_t addr, cmd;
+
+ addr = MK_PEXDADRS(bus_no, dev_no, func_no, off);
+ cmd = MK_PEXDCMND(PEXDCMND_CONFIG_WRITE, off, size);
+ PEX_OUT(base, PEXDADRS, addr);
+ PEX_OUT(base, PEXDCMND, cmd);
+ PEX_OUT(base, PEXDWDATA,
+ (data & ((0x1 << (size * 8)) - 1)) << ((off & (4-size)) * 8));
+}
+
+#define MK_PEXCADRS_BYTE_EN(off, len) \
+ ((((0x1 << (len)) - 1) << ((off) & 0x3)) << PEXCADRS_BYTE_EN_SHIFT)
+#define MK_PEXCADRS(cmd, addr, size) \
+ ((cmd) | MK_PEXCADRS_BYTE_EN(addr, size) | ((addr) & ~0x3))
+static uint32_t config_read_pciex_rc(unsigned int __iomem *base,
+ uint32_t where, uint32_t size)
+{
+ PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_READ, where, size));
+ return (PEX_IN(base, PEXCRDATA)
+ >> ((where & (4 - size)) * 8)) & ((0x1 << (size * 8)) - 1);
+}
+
+static void config_write_pciex_rc(unsigned int __iomem *base, uint32_t where,
+ uint32_t size, uint32_t val)
+{
+ uint32_t data;
+
+ data = (val & ((0x1 << (size * 8)) - 1)) << ((where & (4 - size)) * 8);
+ PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_WRITE, where, size));
+ PEX_OUT(base, PEXCWDATA, data);
+}
+
+/* Interfaces */
+/* Note: Work-around
+ * On SCC PCIEXC, one device is seen on all 32 dev_no.
+ * As SCC PCIEXC can have only one device on the bus, we look only one dev_no.
+ * (dev_no = 1)
+ */
+static int scc_pciex_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, unsigned int *val)
+{
+ struct device_node *dn;
+ struct pci_controller *phb;
+
+ dn = bus->sysdata;
+ phb = pci_find_hose_for_OF_device(dn);
+
+ if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (bus->number == 0 && PCI_SLOT(devfn) == 0)
+ *val = config_read_pciex_rc(phb->cfg_addr, where, size);
+ else
+ *val = config_read_pciex_dev(phb->cfg_addr, bus->number,
+ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int scc_pciex_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, unsigned int val)
+{
+ struct device_node *dn;
+ struct pci_controller *phb;
+
+ dn = bus->sysdata;
+ phb = pci_find_hose_for_OF_device(dn);
+
+ if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (bus->number == 0 && PCI_SLOT(devfn) == 0)
+ config_write_pciex_rc(phb->cfg_addr, where, size, val);
+ else
+ config_write_pciex_dev(phb->cfg_addr, bus->number,
+ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops scc_pciex_pci_ops = {
+ scc_pciex_read_config,
+ scc_pciex_write_config,
+};
+
+static void pciex_clear_intr_all(unsigned int __iomem *base)
+{
+ PEX_OUT(base, PEXAERRSTS, 0xffffffff);
+ PEX_OUT(base, PEXPRERRSTS, 0xffffffff);
+ PEX_OUT(base, PEXINTSTS, 0xffffffff);
+}
+
+#if 0
+static void pciex_disable_intr_all(unsigned int *base)
+{
+ PEX_OUT(base, PEXINTMASK, 0x0);
+ PEX_OUT(base, PEXAERRMASK, 0x0);
+ PEX_OUT(base, PEXPRERRMASK, 0x0);
+ PEX_OUT(base, PEXVDMASK, 0x0);
+}
+#endif
+
+static void pciex_enable_intr_all(unsigned int __iomem *base)
+{
+ PEX_OUT(base, PEXINTMASK, 0x0000e7f1);
+ PEX_OUT(base, PEXAERRMASK, 0x03ff01ff);
+ PEX_OUT(base, PEXPRERRMASK, 0x0001010f);
+ PEX_OUT(base, PEXVDMASK, 0x00000001);
+}
+
+static void pciex_check_status(unsigned int __iomem *base)
+{
+ uint32_t err = 0;
+ uint32_t intsts, aerr, prerr, rcvcp, lenerr;
+ uint32_t maea, maec;
+
+ intsts = PEX_IN(base, PEXINTSTS);
+ aerr = PEX_IN(base, PEXAERRSTS);
+ prerr = PEX_IN(base, PEXPRERRSTS);
+ rcvcp = PEX_IN(base, PEXRCVCPLIDA);
+ lenerr = PEX_IN(base, PEXLENERRIDA);
+
+ if (intsts || aerr || prerr || rcvcp || lenerr)
+ err = 1;
+
+ pr_info("PCEXC interrupt!!\n");
+ pr_info("PEXINTSTS :0x%08x\n", intsts);
+ pr_info("PEXAERRSTS :0x%08x\n", aerr);
+ pr_info("PEXPRERRSTS :0x%08x\n", prerr);
+ pr_info("PEXRCVCPLIDA :0x%08x\n", rcvcp);
+ pr_info("PEXLENERRIDA :0x%08x\n", lenerr);
+
+ /* print detail of Protection Error */
+ if (intsts & 0x00004000) {
+ uint32_t i, n;
+ for (i = 0; i < 4; i++) {
+ n = 1 << i;
+ if (prerr & n) {
+ maea = PEX_IN(base, PEXMAEA(i));
+ maec = PEX_IN(base, PEXMAEC(i));
+ pr_info("PEXMAEC%d :0x%08x\n", i, maec);
+ pr_info("PEXMAEA%d :0x%08x\n", i, maea);
+ }
+ }
+ }
+
+ if (err)
+ pciex_clear_intr_all(base);
+}
+
+static irqreturn_t pciex_handle_internal_irq(int irq, void *dev_id)
+{
+ struct pci_controller *phb = dev_id;
+
+ pr_debug("PCIEX:pciex_handle_internal_irq(irq=%d)\n", irq);
+
+ BUG_ON(phb->cfg_addr == NULL);
+
+ pciex_check_status(phb->cfg_addr);
+
+ return IRQ_HANDLED;
+}
+
+static __init int celleb_setup_pciex(struct device_node *node,
+ struct pci_controller *phb)
+{
+ struct resource r;
+ struct of_irq oirq;
+ int virq;
+
+ /* SMMIO registers; used inside this file */
+ if (of_address_to_resource(node, 0, &r)) {
+ pr_err("PCIEXC:Failed to get config resource.\n");
+ return 1;
+ }
+ phb->cfg_addr = ioremap(r.start, r.end - r.start + 1);
+ if (!phb->cfg_addr) {
+ pr_err("PCIEXC:Failed to remap SMMIO region.\n");
+ return 1;
+ }
+
+ /* Not use cfg_data, cmd and data regs are near address reg */
+ phb->cfg_data = NULL;
+
+ /* set pci_ops */
+ phb->ops = &scc_pciex_pci_ops;
+
+ /* internal interrupt handler */
+ if (of_irq_map_one(node, 1, &oirq)) {
+ pr_err("PCIEXC:Failed to map irq\n");
+ goto error;
+ }
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+ if (request_irq(virq, pciex_handle_internal_irq,
+ IRQF_DISABLED, "pciex", (void *)phb)) {
+ pr_err("PCIEXC:Failed to request irq\n");
+ goto error;
+ }
+
+ /* enable all interrupts */
+ pciex_clear_intr_all(phb->cfg_addr);
+ pciex_enable_intr_all(phb->cfg_addr);
+ /* MSI: TBD */
+
+ return 0;
+
+error:
+ phb->cfg_data = NULL;
+ if (phb->cfg_addr)
+ iounmap(phb->cfg_addr);
+ phb->cfg_addr = NULL;
+ return 1;
+}
+
+struct celleb_phb_spec celleb_pciex_spec __initdata = {
+ .setup = celleb_setup_pciex,
+ .ops = &scc_pciex_ops,
+ .iowa_init = &scc_pciex_iowa_init,
+};
diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/cell/celleb_scc_sio.c
index 3a16c5b3c464..3a16c5b3c464 100644
--- a/arch/powerpc/platforms/celleb/scc_sio.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c
diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/cell/celleb_scc_uhc.c
index cb4307994087..d63b720bfe3a 100644
--- a/arch/powerpc/platforms/celleb/scc_uhc.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_uhc.c
@@ -25,7 +25,7 @@
#include <asm/io.h>
#include <asm/machdep.h>
-#include "scc.h"
+#include "celleb_scc.h"
#define UHC_RESET_WAIT_MAX 10000
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/cell/celleb_setup.c
index f27ae1e3fb58..b11cb30decb2 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/cell/celleb_setup.c
@@ -56,13 +56,13 @@
#include <asm/rtas.h>
#include <asm/cell-regs.h>
-#include "interrupt.h"
+#include "beat_interrupt.h"
#include "beat_wrapper.h"
#include "beat.h"
-#include "pci.h"
-#include "../cell/interrupt.h"
-#include "../cell/pervasive.h"
-#include "../cell/ras.h"
+#include "celleb_pci.h"
+#include "interrupt.h"
+#include "pervasive.h"
+#include "ras.h"
static char celleb_machine_type[128] = "Celleb";
@@ -114,8 +114,6 @@ static int __init celleb_publish_devices(void)
/* Publish OF platform devices for southbridge IOs */
of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
- celleb_pci_workaround_init();
-
return 0;
}
machine_device_initcall(celleb_beat, celleb_publish_devices);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 979d4b67efb4..3b84e8be314c 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -1,6 +1,9 @@
/*
+ * Support PCI IO workaround
+ *
* Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* IBM, Corp.
+ * (C) Copyright 2007-2008 TOSHIBA CORPORATION
*
* 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
@@ -9,335 +12,174 @@
#undef DEBUG
#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
+
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
+#include <asm/pgtable.h>
#include <asm/ppc-pci.h>
+#include "io-workarounds.h"
-#define SPIDER_PCI_REG_BASE 0xd000
-#define SPIDER_PCI_VCI_CNTL_STAT 0x0110
-#define SPIDER_PCI_DUMMY_READ 0x0810
-#define SPIDER_PCI_DUMMY_READ_BASE 0x0814
+#define IOWA_MAX_BUS 8
-/* Undefine that to re-enable bogus prefetch
- *
- * Without that workaround, the chip will do bogus prefetch past
- * page boundary from system memory. This setting will disable that,
- * though the documentation is unclear as to the consequences of doing
- * so, either purely performances, or possible misbehaviour... It's not
- * clear wether the chip can handle unaligned accesses at all without
- * prefetching enabled.
- *
- * For now, things appear to be behaving properly with that prefetching
- * disabled and IDE, possibly because IDE isn't doing any unaligned
- * access.
- */
-#define SPIDER_DISABLE_PREFETCH
+static struct iowa_bus iowa_busses[IOWA_MAX_BUS];
+static unsigned int iowa_bus_count;
-#define MAX_SPIDERS 3
+static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
+{
+ int i, j;
+ struct resource *res;
+ unsigned long vstart, vend;
-static struct spider_pci_bus {
- void __iomem *regs;
- unsigned long mmio_start;
- unsigned long mmio_end;
- unsigned long pio_vstart;
- unsigned long pio_vend;
-} spider_pci_busses[MAX_SPIDERS];
-static int spider_pci_count;
+ for (i = 0; i < iowa_bus_count; i++) {
+ struct iowa_bus *bus = &iowa_busses[i];
+ struct pci_controller *phb = bus->phb;
-static struct spider_pci_bus *spider_pci_find(unsigned long vaddr,
- unsigned long paddr)
-{
- int i;
-
- for (i = 0; i < spider_pci_count; i++) {
- struct spider_pci_bus *bus = &spider_pci_busses[i];
- if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end)
- return bus;
- if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend)
- return bus;
+ if (vaddr) {
+ vstart = (unsigned long)phb->io_base_virt;
+ vend = vstart + phb->pci_io_size - 1;
+ if ((vaddr >= vstart) && (vaddr <= vend))
+ return bus;
+ }
+
+ if (paddr)
+ for (j = 0; j < 3; j++) {
+ res = &phb->mem_resources[j];
+ if (paddr >= res->start && paddr <= res->end)
+ return bus;
+ }
}
+
return NULL;
}
-static void spider_io_flush(const volatile void __iomem *addr)
+struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
{
- struct spider_pci_bus *bus;
+ struct iowa_bus *bus;
int token;
- /* Get platform token (set by ioremap) from address */
token = PCI_GET_ADDR_TOKEN(addr);
- /* Fast path if we have a non-0 token, it indicates which bus we
- * are on.
- *
- * If the token is 0, that means either that the ioremap was done
- * before we initialized this layer, or it's a PIO operation. We
- * fallback to a low path in this case. Hopefully, internal devices
- * which are ioremap'ed early should use in_XX/out_XX functions
- * instead of the PCI ones and thus not suffer from the slowdown.
- *
- * Also note that currently, the workaround will not work for areas
- * that are not mapped with PTEs (bolted in the hash table). This
- * is the case for ioremaps done very early at boot (before
- * mem_init_done) and includes the mapping of the ISA IO space.
- *
- * Fortunately, none of the affected devices is expected to do DMA
- * and thus there should be no problem in practice.
- *
- * In order to improve performances, we only do the PTE search for
- * addresses falling in the PHB IO space area. That means it will
- * not work for hotplug'ed PHBs but those don't exist with Spider.
- */
- if (token && token <= spider_pci_count)
- bus = &spider_pci_busses[token - 1];
+ if (token && token <= iowa_bus_count)
+ bus = &iowa_busses[token - 1];
else {
unsigned long vaddr, paddr;
pte_t *ptep;
- /* Fixup physical address */
vaddr = (unsigned long)PCI_FIX_ADDR(addr);
+ if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
+ return NULL;
- /* Check if it's in allowed range for PIO */
- if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END)
- return;
-
- /* Try to find a PTE. If not, clear the paddr, we'll do
- * a vaddr only lookup (PIO only)
- */
ptep = find_linux_pte(init_mm.pgd, vaddr);
if (ptep == NULL)
paddr = 0;
else
paddr = pte_pfn(*ptep) << PAGE_SHIFT;
+ bus = iowa_pci_find(vaddr, paddr);
- bus = spider_pci_find(vaddr, paddr);
if (bus == NULL)
- return;
+ return NULL;
}
- /* Now do the workaround
- */
- (void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ);
+ return bus;
}
-static u8 spider_readb(const volatile void __iomem *addr)
+struct iowa_bus *iowa_pio_find_bus(unsigned long port)
{
- u8 val = __do_readb(addr);
- spider_io_flush(addr);
- return val;
+ unsigned long vaddr = (unsigned long)pci_io_base + port;
+ return iowa_pci_find(vaddr, 0);
}
-static u16 spider_readw(const volatile void __iomem *addr)
-{
- u16 val = __do_readw(addr);
- spider_io_flush(addr);
- return val;
-}
-static u32 spider_readl(const volatile void __iomem *addr)
-{
- u32 val = __do_readl(addr);
- spider_io_flush(addr);
- return val;
+#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
+static ret iowa_##name at \
+{ \
+ struct iowa_bus *bus; \
+ bus = iowa_##space##_find_bus(aa); \
+ if (bus && bus->ops && bus->ops->name) \
+ return bus->ops->name al; \
+ return __do_##name al; \
}
-static u64 spider_readq(const volatile void __iomem *addr)
-{
- u64 val = __do_readq(addr);
- spider_io_flush(addr);
- return val;
+#define DEF_PCI_AC_NORET(name, at, al, space, aa) \
+static void iowa_##name at \
+{ \
+ struct iowa_bus *bus; \
+ bus = iowa_##space##_find_bus(aa); \
+ if (bus && bus->ops && bus->ops->name) { \
+ bus->ops->name al; \
+ return; \
+ } \
+ __do_##name al; \
}
-static u16 spider_readw_be(const volatile void __iomem *addr)
-{
- u16 val = __do_readw_be(addr);
- spider_io_flush(addr);
- return val;
-}
+#include <asm/io-defs.h>
-static u32 spider_readl_be(const volatile void __iomem *addr)
-{
- u32 val = __do_readl_be(addr);
- spider_io_flush(addr);
- return val;
-}
+#undef DEF_PCI_AC_RET
+#undef DEF_PCI_AC_NORET
-static u64 spider_readq_be(const volatile void __iomem *addr)
-{
- u64 val = __do_readq_be(addr);
- spider_io_flush(addr);
- return val;
-}
+static struct ppc_pci_io __initdata iowa_pci_io = {
-static void spider_readsb(const volatile void __iomem *addr, void *buf,
- unsigned long count)
-{
- __do_readsb(addr, buf, count);
- spider_io_flush(addr);
-}
+#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name,
+#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name,
-static void spider_readsw(const volatile void __iomem *addr, void *buf,
- unsigned long count)
-{
- __do_readsw(addr, buf, count);
- spider_io_flush(addr);
-}
+#include <asm/io-defs.h>
-static void spider_readsl(const volatile void __iomem *addr, void *buf,
- unsigned long count)
-{
- __do_readsl(addr, buf, count);
- spider_io_flush(addr);
-}
-
-static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src,
- unsigned long n)
-{
- __do_memcpy_fromio(dest, src, n);
- spider_io_flush(src);
-}
+#undef DEF_PCI_AC_RET
+#undef DEF_PCI_AC_NORET
+};
-static void __iomem * spider_ioremap(unsigned long addr, unsigned long size,
- unsigned long flags)
+static void __iomem *iowa_ioremap(unsigned long addr, unsigned long size,
+ unsigned long flags)
{
- struct spider_pci_bus *bus;
+ struct iowa_bus *bus;
void __iomem *res = __ioremap(addr, size, flags);
int busno;
- pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n",
- addr, size, flags, res);
-
- bus = spider_pci_find(0, addr);
+ bus = iowa_pci_find(0, addr);
if (bus != NULL) {
- busno = bus - spider_pci_busses;
- pr_debug(" found bus %d, setting token\n", busno);
+ busno = bus - iowa_busses;
PCI_SET_ADDR_TOKEN(res, busno + 1);
}
- pr_debug(" result=0x%p\n", res);
-
return res;
}
-static void __init spider_pci_setup_chip(struct spider_pci_bus *bus)
-{
-#ifdef SPIDER_DISABLE_PREFETCH
- u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT);
- pr_debug(" PVCI_Control_Status was 0x%08x\n", val);
- out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
-#endif
-
- /* Configure the dummy address for the workaround */
- out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000);
-}
-
-static void __init spider_pci_add_one(struct pci_controller *phb)
+/* Regist new bus to support workaround */
+void __init iowa_register_bus(struct pci_controller *phb,
+ struct ppc_pci_io *ops,
+ int (*initfunc)(struct iowa_bus *, void *), void *data)
{
- struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count];
+ struct iowa_bus *bus;
struct device_node *np = phb->dn;
- struct resource rsrc;
- void __iomem *regs;
- if (spider_pci_count >= MAX_SPIDERS) {
- printk(KERN_ERR "Too many spider bridges, workarounds"
- " disabled for %s\n", np->full_name);
+ if (iowa_bus_count >= IOWA_MAX_BUS) {
+ pr_err("IOWA:Too many pci bridges, "
+ "workarounds disabled for %s\n", np->full_name);
return;
}
- /* Get the registers for the beast */
- if (of_address_to_resource(np, 0, &rsrc)) {
- printk(KERN_ERR "Failed to get registers for spider %s"
- " workarounds disabled\n", np->full_name);
- return;
- }
+ bus = &iowa_busses[iowa_bus_count];
+ bus->phb = phb;
+ bus->ops = ops;
- /* Mask out some useless bits in there to get to the base of the
- * spider chip
- */
- rsrc.start &= ~0xfffffffful;
-
- /* Map them */
- regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000);
- if (regs == NULL) {
- printk(KERN_ERR "Failed to map registers for spider %s"
- " workarounds disabled\n", np->full_name);
- return;
- }
-
- spider_pci_count++;
-
- /* We assume spiders only have one MMIO resource */
- bus->mmio_start = phb->mem_resources[0].start;
- bus->mmio_end = phb->mem_resources[0].end + 1;
-
- bus->pio_vstart = (unsigned long)phb->io_base_virt;
- bus->pio_vend = bus->pio_vstart + phb->pci_io_size;
-
- bus->regs = regs;
-
- printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name);
+ if (initfunc)
+ if ((*initfunc)(bus, data))
+ return;
- pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n",
- bus->mmio_start, bus->mmio_end);
- pr_debug(" pio (V) = 0x%016lx..0x%016lx\n",
- bus->pio_vstart, bus->pio_vend);
- pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n",
- rsrc.start + SPIDER_PCI_REG_BASE, bus->regs);
+ iowa_bus_count++;
- spider_pci_setup_chip(bus);
+ pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name);
}
-static struct ppc_pci_io __initdata spider_pci_io = {
- .readb = spider_readb,
- .readw = spider_readw,
- .readl = spider_readl,
- .readq = spider_readq,
- .readw_be = spider_readw_be,
- .readl_be = spider_readl_be,
- .readq_be = spider_readq_be,
- .readsb = spider_readsb,
- .readsw = spider_readsw,
- .readsl = spider_readsl,
- .memcpy_fromio = spider_memcpy_fromio,
-};
-
-static int __init spider_pci_workaround_init(void)
+/* enable IO workaround */
+void __init io_workaround_init(void)
{
- struct pci_controller *phb;
-
- /* Find spider bridges. We assume they have been all probed
- * in setup_arch(). If that was to change, we would need to
- * update this code to cope with dynamically added busses
- */
- list_for_each_entry(phb, &hose_list, list_node) {
- struct device_node *np = phb->dn;
- const char *model = of_get_property(np, "model", NULL);
-
- /* If no model property or name isn't exactly "pci", skip */
- if (model == NULL || strcmp(np->name, "pci"))
- continue;
- /* If model is not "Spider", skip */
- if (strcmp(model, "Spider"))
- continue;
- spider_pci_add_one(phb);
- }
-
- /* No Spider PCI found, exit */
- if (spider_pci_count == 0)
- return 0;
+ static int io_workaround_inited;
- /* Setup IO callbacks. We only setup MMIO reads. PIO reads will
- * fallback to MMIO reads (though without a token, thus slower)
- */
- ppc_pci_io = spider_pci_io;
-
- /* Setup ioremap callback */
- ppc_md.ioremap = spider_ioremap;
-
- return 0;
+ if (io_workaround_inited)
+ return;
+ ppc_pci_io = iowa_pci_io;
+ ppc_md.ioremap = iowa_ioremap;
+ io_workaround_inited = 1;
}
-machine_arch_initcall(cell, spider_pci_workaround_init);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/platforms/cell/io-workarounds.h
new file mode 100644
index 000000000000..79d8ed3d510f
--- /dev/null
+++ b/arch/powerpc/platforms/cell/io-workarounds.h
@@ -0,0 +1,49 @@
+/*
+ * Support PCI IO workaround
+ *
+ * (C) Copyright 2007-2008 TOSHIBA CORPORATION
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _IO_WORKAROUNDS_H
+#define _IO_WORKAROUNDS_H
+
+#include <linux/io.h>
+#include <asm/pci-bridge.h>
+
+/* Bus info */
+struct iowa_bus {
+ struct pci_controller *phb;
+ struct ppc_pci_io *ops;
+ void *private;
+};
+
+void __init io_workaround_init(void);
+void __init iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
+ int (*)(struct iowa_bus *, void *), void *);
+struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR);
+struct iowa_bus *iowa_pio_find_bus(unsigned long);
+
+extern struct ppc_pci_io spiderpci_ops;
+extern int spiderpci_iowa_init(struct iowa_bus *, void *);
+
+#define SPIDER_PCI_REG_BASE 0xd000
+#define SPIDER_PCI_REG_SIZE 0x1000
+#define SPIDER_PCI_VCI_CNTL_STAT 0x0110
+#define SPIDER_PCI_DUMMY_READ 0x0810
+#define SPIDER_PCI_DUMMY_READ_BASE 0x0814
+
+#endif /* _IO_WORKAROUNDS_H */
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 5c531e8f9f6f..ab721b50fbba 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -57,6 +57,7 @@
#include "interrupt.h"
#include "pervasive.h"
#include "ras.h"
+#include "io-workarounds.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -117,13 +118,50 @@ static void cell_fixup_pcie_rootcomplex(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex);
+static int __devinit cell_setup_phb(struct pci_controller *phb)
+{
+ const char *model;
+ struct device_node *np;
+
+ int rc = rtas_setup_phb(phb);
+ if (rc)
+ return rc;
+
+ np = phb->dn;
+ model = of_get_property(np, "model", NULL);
+ if (model == NULL || strcmp(np->name, "pci"))
+ return 0;
+
+ /* Setup workarounds for spider */
+ if (strcmp(model, "Spider"))
+ return 0;
+
+ iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init,
+ (void *)SPIDER_PCI_REG_BASE);
+ io_workaround_init();
+
+ return 0;
+}
+
static int __init cell_publish_devices(void)
{
+ struct device_node *root = of_find_node_by_path("/");
+ struct device_node *np;
int node;
/* Publish OF platform devices for southbridge IOs */
of_platform_bus_probe(NULL, NULL, NULL);
+ /* On spider based blades, we need to manually create the OF
+ * platform devices for the PCI host bridges
+ */
+ for_each_child_of_node(root, np) {
+ if (np->type == NULL || (strcmp(np->type, "pci") != 0 &&
+ strcmp(np->type, "pciex") != 0))
+ continue;
+ of_platform_device_create(np, NULL, NULL);
+ }
+
/* There is no device for the MIC memory controller, thus we create
* a platform device for it to attach the EDAC driver to.
*/
@@ -132,6 +170,7 @@ static int __init cell_publish_devices(void)
continue;
platform_device_register_simple("cbe-mic", node, NULL, 0);
}
+
return 0;
}
machine_subsys_initcall(cell, cell_publish_devices);
@@ -213,7 +252,7 @@ static void __init cell_setup_arch(void)
/* Find and initialize PCI host bridges */
init_pci_config_tokens();
- find_and_init_phbs();
+
cbe_pervasive_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -249,7 +288,7 @@ define_machine(cell) {
.calibrate_decr = generic_calibrate_decr,
.progress = cell_progress,
.init_IRQ = cell_init_irq,
- .pci_setup_phb = rtas_setup_phb,
+ .pci_setup_phb = cell_setup_phb,
#ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c
new file mode 100644
index 000000000000..418b605ac35a
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spider-pci.c
@@ -0,0 +1,184 @@
+/*
+ * IO workarounds for PCI on Celleb/Cell platform
+ *
+ * (C) Copyright 2006-2007 TOSHIBA CORPORATION
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+#include <asm/ppc-pci.h>
+#include <asm/pci-bridge.h>
+
+#include "io-workarounds.h"
+
+#define SPIDER_PCI_DISABLE_PREFETCH
+
+struct spiderpci_iowa_private {
+ void __iomem *regs;
+};
+
+static void spiderpci_io_flush(struct iowa_bus *bus)
+{
+ struct spiderpci_iowa_private *priv;
+ u32 val;
+
+ priv = bus->private;
+ val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ);
+ iosync();
+}
+
+#define SPIDER_PCI_MMIO_READ(name, ret) \
+static ret spiderpci_##name(const PCI_IO_ADDR addr) \
+{ \
+ ret val = __do_##name(addr); \
+ spiderpci_io_flush(iowa_mem_find_bus(addr)); \
+ return val; \
+}
+
+#define SPIDER_PCI_MMIO_READ_STR(name) \
+static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \
+ unsigned long count) \
+{ \
+ __do_##name(addr, buf, count); \
+ spiderpci_io_flush(iowa_mem_find_bus(addr)); \
+}
+
+SPIDER_PCI_MMIO_READ(readb, u8)
+SPIDER_PCI_MMIO_READ(readw, u16)
+SPIDER_PCI_MMIO_READ(readl, u32)
+SPIDER_PCI_MMIO_READ(readq, u64)
+SPIDER_PCI_MMIO_READ(readw_be, u16)
+SPIDER_PCI_MMIO_READ(readl_be, u32)
+SPIDER_PCI_MMIO_READ(readq_be, u64)
+SPIDER_PCI_MMIO_READ_STR(readsb)
+SPIDER_PCI_MMIO_READ_STR(readsw)
+SPIDER_PCI_MMIO_READ_STR(readsl)
+
+static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src,
+ unsigned long n)
+{
+ __do_memcpy_fromio(dest, src, n);
+ spiderpci_io_flush(iowa_mem_find_bus(src));
+}
+
+static int __init spiderpci_pci_setup_chip(struct pci_controller *phb,
+ void __iomem *regs)
+{
+ void *dummy_page_va;
+ dma_addr_t dummy_page_da;
+
+#ifdef SPIDER_PCI_DISABLE_PREFETCH
+ u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT);
+ pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val);
+ out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
+#endif /* SPIDER_PCI_DISABLE_PREFETCH */
+
+ /* setup dummy read */
+ /*
+ * On CellBlade, we can't know that which XDR memory is used by
+ * kmalloc() to allocate dummy_page_va.
+ * In order to imporve the performance, the XDR which is used to
+ * allocate dummy_page_va is the nearest the spider-pci.
+ * We have to select the CBE which is the nearest the spider-pci
+ * to allocate memory from the best XDR, but I don't know that
+ * how to do.
+ *
+ * Celleb does not have this problem, because it has only one XDR.
+ */
+ dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!dummy_page_va) {
+ pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n");
+ return -1;
+ }
+
+ dummy_page_da = dma_map_single(phb->parent, dummy_page_va,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dummy_page_da)) {
+ pr_err("SPIDER-IOWA:Map dummy page filed.\n");
+ kfree(dummy_page_va);
+ return -1;
+ }
+
+ out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da);
+
+ return 0;
+}
+
+int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data)
+{
+ void __iomem *regs = NULL;
+ struct spiderpci_iowa_private *priv;
+ struct device_node *np = bus->phb->dn;
+ struct resource r;
+ unsigned long offset = (unsigned long)data;
+
+ pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%s)\n",
+ np->full_name);
+
+ priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL);
+ if (!priv) {
+ pr_err("SPIDERPCI-IOWA:"
+ "Can't allocate struct spiderpci_iowa_private");
+ return -1;
+ }
+
+ if (of_address_to_resource(np, 0, &r)) {
+ pr_err("SPIDERPCI-IOWA:Can't get resource.\n");
+ goto error;
+ }
+
+ regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE);
+ if (!regs) {
+ pr_err("SPIDERPCI-IOWA:ioremap failed.\n");
+ goto error;
+ }
+ priv->regs = regs;
+ bus->private = priv;
+
+ if (spiderpci_pci_setup_chip(bus->phb, regs))
+ goto error;
+
+ return 0;
+
+error:
+ kfree(priv);
+ bus->private = NULL;
+
+ if (regs)
+ iounmap(regs);
+
+ return -1;
+}
+
+struct ppc_pci_io spiderpci_ops = {
+ .readb = spiderpci_readb,
+ .readw = spiderpci_readw,
+ .readl = spiderpci_readl,
+ .readq = spiderpci_readq,
+ .readw_be = spiderpci_readw_be,
+ .readl_be = spiderpci_readl_be,
+ .readq_be = spiderpci_readq_be,
+ .readsb = spiderpci_readsb,
+ .readsw = spiderpci_readsw,
+ .readsl = spiderpci_readsl,
+ .memcpy_fromio = spiderpci_memcpy_fromio,
+};
+
diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig
deleted file mode 100644
index 372891edcdd2..000000000000
--- a/arch/powerpc/platforms/celleb/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config PPC_CELLEB
- bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
- depends on PPC_MULTIPLATFORM && PPC64
- select PPC_CELL
- select PPC_CELL_NATIVE
- select PPC_RTAS
- select PPC_INDIRECT_IO
- select PPC_OF_PLATFORM_PCI
- select HAS_TXX9_SERIAL
- select PPC_UDBG_BEAT
- select USB_OHCI_BIG_ENDIAN_MMIO
- select USB_EHCI_BIG_ENDIAN_MMIO
diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile
deleted file mode 100644
index 889d43f715ea..000000000000
--- a/arch/powerpc/platforms/celleb/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-obj-y += interrupt.o iommu.o setup.o \
- htab.o beat.o hvCall.o pci.o \
- scc_epci.o scc_uhc.o \
- io-workarounds.o
-
-obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o
-obj-$(CONFIG_SERIAL_TXX9) += scc_sio.o
-obj-$(CONFIG_SPU_BASE) += spu_priv1.o
diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c
deleted file mode 100644
index 423339be1bac..000000000000
--- a/arch/powerpc/platforms/celleb/io-workarounds.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Support for Celleb io workarounds
- *
- * (C) Copyright 2006-2007 TOSHIBA CORPORATION
- *
- * This file is based to arch/powerpc/platform/cell/io-workarounds.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#undef DEBUG
-
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/irq.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc-pci.h>
-
-#include "pci.h"
-
-#define MAX_CELLEB_PCI_BUS 4
-
-void *celleb_dummy_page_va;
-
-static struct celleb_pci_bus {
- struct pci_controller *phb;
- void (*dummy_read)(struct pci_controller *);
-} celleb_pci_busses[MAX_CELLEB_PCI_BUS];
-
-static int celleb_pci_count = 0;
-
-static struct celleb_pci_bus *celleb_pci_find(unsigned long vaddr,
- unsigned long paddr)
-{
- int i, j;
- struct resource *res;
-
- for (i = 0; i < celleb_pci_count; i++) {
- struct celleb_pci_bus *bus = &celleb_pci_busses[i];
- struct pci_controller *phb = bus->phb;
- if (paddr)
- for (j = 0; j < 3; j++) {
- res = &phb->mem_resources[j];
- if (paddr >= res->start && paddr <= res->end)
- return bus;
- }
- res = &phb->io_resource;
- if (vaddr && vaddr >= res->start && vaddr <= res->end)
- return bus;
- }
- return NULL;
-}
-
-static void celleb_io_flush(const PCI_IO_ADDR addr)
-{
- struct celleb_pci_bus *bus;
- int token;
-
- token = PCI_GET_ADDR_TOKEN(addr);
-
- if (token && token <= celleb_pci_count)
- bus = &celleb_pci_busses[token - 1];
- else {
- unsigned long vaddr, paddr;
- pte_t *ptep;
-
- vaddr = (unsigned long)PCI_FIX_ADDR(addr);
- if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
- return;
-
- ptep = find_linux_pte(init_mm.pgd, vaddr);
- if (ptep == NULL)
- paddr = 0;
- else
- paddr = pte_pfn(*ptep) << PAGE_SHIFT;
- bus = celleb_pci_find(vaddr, paddr);
-
- if (bus == NULL)
- return;
- }
-
- if (bus->dummy_read)
- bus->dummy_read(bus->phb);
-}
-
-static u8 celleb_readb(const PCI_IO_ADDR addr)
-{
- u8 val;
- val = __do_readb(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static u16 celleb_readw(const PCI_IO_ADDR addr)
-{
- u16 val;
- val = __do_readw(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static u32 celleb_readl(const PCI_IO_ADDR addr)
-{
- u32 val;
- val = __do_readl(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static u64 celleb_readq(const PCI_IO_ADDR addr)
-{
- u64 val;
- val = __do_readq(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static u16 celleb_readw_be(const PCI_IO_ADDR addr)
-{
- u16 val;
- val = __do_readw_be(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static u32 celleb_readl_be(const PCI_IO_ADDR addr)
-{
- u32 val;
- val = __do_readl_be(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static u64 celleb_readq_be(const PCI_IO_ADDR addr)
-{
- u64 val;
- val = __do_readq_be(addr);
- celleb_io_flush(addr);
- return val;
-}
-
-static void celleb_readsb(const PCI_IO_ADDR addr,
- void *buf, unsigned long count)
-{
- __do_readsb(addr, buf, count);
- celleb_io_flush(addr);
-}
-
-static void celleb_readsw(const PCI_IO_ADDR addr,
- void *buf, unsigned long count)
-{
- __do_readsw(addr, buf, count);
- celleb_io_flush(addr);
-}
-
-static void celleb_readsl(const PCI_IO_ADDR addr,
- void *buf, unsigned long count)
-{
- __do_readsl(addr, buf, count);
- celleb_io_flush(addr);
-}
-
-static void celleb_memcpy_fromio(void *dest,
- const PCI_IO_ADDR src,
- unsigned long n)
-{
- __do_memcpy_fromio(dest, src, n);
- celleb_io_flush(src);
-}
-
-static void __iomem *celleb_ioremap(unsigned long addr,
- unsigned long size,
- unsigned long flags)
-{
- struct celleb_pci_bus *bus;
- void __iomem *res = __ioremap(addr, size, flags);
- int busno;
-
- bus = celleb_pci_find(0, addr);
- if (bus != NULL) {
- busno = bus - celleb_pci_busses;
- PCI_SET_ADDR_TOKEN(res, busno + 1);
- }
- return res;
-}
-
-static void celleb_iounmap(volatile void __iomem *addr)
-{
- return __iounmap(PCI_FIX_ADDR(addr));
-}
-
-static struct ppc_pci_io celleb_pci_io __initdata = {
- .readb = celleb_readb,
- .readw = celleb_readw,
- .readl = celleb_readl,
- .readq = celleb_readq,
- .readw_be = celleb_readw_be,
- .readl_be = celleb_readl_be,
- .readq_be = celleb_readq_be,
- .readsb = celleb_readsb,
- .readsw = celleb_readsw,
- .readsl = celleb_readsl,
- .memcpy_fromio = celleb_memcpy_fromio,
-};
-
-void __init celleb_pci_add_one(struct pci_controller *phb,
- void (*dummy_read)(struct pci_controller *))
-{
- struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count];
- struct device_node *np = phb->dn;
-
- if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) {
- printk(KERN_ERR "Too many pci bridges, workarounds"
- " disabled for %s\n", np->full_name);
- return;
- }
-
- celleb_pci_count++;
-
- bus->phb = phb;
- bus->dummy_read = dummy_read;
-}
-
-static struct of_device_id celleb_pci_workaround_match[] __initdata = {
- {
- .name = "pci-pseudo",
- .data = fake_pci_workaround_init,
- }, {
- .name = "epci",
- .data = epci_workaround_init,
- }, {
- },
-};
-
-int __init celleb_pci_workaround_init(void)
-{
- struct pci_controller *phb;
- struct device_node *node;
- const struct of_device_id *match;
- void (*init_func)(struct pci_controller *);
-
- celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!celleb_dummy_page_va) {
- printk(KERN_ERR "Celleb: dummy read disabled. "
- "Alloc celleb_dummy_page_va failed\n");
- return 1;
- }
-
- list_for_each_entry(phb, &hose_list, list_node) {
- node = phb->dn;
- match = of_match_node(celleb_pci_workaround_match, node);
-
- if (match) {
- init_func = match->data;
- (*init_func)(phb);
- }
- }
-
- ppc_pci_io = celleb_pci_io;
- ppc_md.ioremap = celleb_ioremap;
- ppc_md.iounmap = celleb_iounmap;
-
- return 0;
-}
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
index c775cd4b3d6e..8ff330d026ca 100644
--- a/arch/powerpc/platforms/iseries/exception.S
+++ b/arch/powerpc/platforms/iseries/exception.S
@@ -59,8 +59,33 @@ system_reset_iSeries:
andc r4,r4,r5
mtspr SPRN_CTRLT,r4
+/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
+/* In the UP case we'll yeild() later, and we will not access the paca anyway */
+#ifdef CONFIG_SMP
1:
HMT_LOW
+ LOAD_REG_IMMEDIATE(r23, __secondary_hold_spinloop)
+ ld r23,0(r23)
+ sync
+ LOAD_REG_IMMEDIATE(r3,current_set)
+ sldi r28,r24,3 /* get current_set[cpu#] */
+ ldx r3,r3,r28
+ addi r1,r3,THREAD_SIZE
+ subi r1,r1,STACK_FRAME_OVERHEAD
+
+ cmpwi 0,r23,0 /* Keep poking the Hypervisor until */
+ bne 2f /* we're released */
+ /* Let the Hypervisor know we are alive */
+ /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
+ lis r3,0x8002
+ rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
+ li r0,-1 /* r0=-1 indicates a Hypervisor call */
+ sc /* Invoke the hypervisor via a system call */
+ b 1b
+#endif
+
+2:
+ HMT_LOW
#ifdef CONFIG_SMP
lbz r23,PACAPROCSTART(r13) /* Test if this processor
* should start */
@@ -91,7 +116,7 @@ iSeries_secondary_smp_loop:
li r0,-1 /* r0=-1 indicates a Hypervisor call */
sc /* Invoke the hypervisor via a system call */
mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */
- b 1b /* If SMP not configured, secondaries
+ b 2b /* If SMP not configured, secondaries
* loop forever */
/*** ISeries-LPAR interrupt handlers ***/
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index c73379ec9141..1d201782d4e5 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -25,6 +25,7 @@
#include <linux/syscalls.h>
#include <linux/ctype.h>
#include <linux/lmb.h>
+#include <linux/of.h>
#include <asm/prom.h>
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 306a9d07491d..07fe5b69b9e2 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -34,3 +34,8 @@ config LPARCFG
help
Provide system capacity information via human readable
<key word>=<value> pairs through a /proc/ppc64/lparcfg interface.
+
+config PPC_PSERIES_DEBUG
+ depends on PPC_PSERIES && PPC_EARLY_DEBUG
+ bool "Enable extra debug logging in platforms/pseries"
+ default y
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index bdae04bb7a01..bd2593ed28dd 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -2,6 +2,10 @@ ifeq ($(CONFIG_PPC64),y)
EXTRA_CFLAGS += -mno-minimal-toc
endif
+ifeq ($(CONFIG_PPC_PSERIES_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
obj-y := lpar.o hvCall.o nvram.o reconfig.o \
setup.o iommu.o ras.o rtasd.o \
firmware.o power.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 550b2f7d2cc1..a3fd56b186e6 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -39,7 +39,6 @@
#include <asm/ppc-pci.h>
#include <asm/rtas.h>
-#undef DEBUG
/** Overview:
* EEH, or "Extended Error Handling" is a PCI bridge technology for
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index 1e83fcd0df31..ce37040af870 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -28,7 +28,6 @@
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
-#undef DEBUG
/**
* The pci address cache subsystem. This subsystem places
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index b765b7c77b65..9d3a40f45974 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -21,17 +21,11 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
#include <asm/firmware.h>
#include <asm/prom.h>
#include <asm/udbg.h>
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
typedef struct {
unsigned long val;
@@ -72,7 +66,7 @@ void __init fw_feature_init(const char *hypertas, unsigned long len)
const char *s;
int i;
- DBG(" -> fw_feature_init()\n");
+ pr_debug(" -> fw_feature_init()\n");
for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
@@ -88,5 +82,5 @@ void __init fw_feature_init(const char *hypertas, unsigned long len)
}
}
- DBG(" <- fw_feature_init()\n");
+ pr_debug(" <- fw_feature_init()\n");
}
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index a65c76308201..176f1f39d2d5 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -47,7 +47,6 @@
#include "plpar_wrappers.h"
-#define DBG(fmt...)
static void tce_build_pSeries(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr,
@@ -322,7 +321,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
dn = pci_bus_to_OF_node(bus);
- DBG("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name);
+ pr_debug("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name);
if (bus->self) {
/* This is not a root bus, any setup will be done for the
@@ -347,7 +346,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling)
children++;
- DBG("Children: %d\n", children);
+ pr_debug("Children: %d\n", children);
/* Calculate amount of DMA window per slot. Each window must be
* a power of two (due to pci_alloc_consistent requirements).
@@ -361,8 +360,8 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
while (pci->phb->dma_window_size * children > 0x80000000ul)
pci->phb->dma_window_size >>= 1;
- DBG("No ISA/IDE, window size is 0x%lx\n",
- pci->phb->dma_window_size);
+ pr_debug("No ISA/IDE, window size is 0x%lx\n",
+ pci->phb->dma_window_size);
pci->phb->dma_window_base_cur = 0;
return;
@@ -387,8 +386,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
while (pci->phb->dma_window_size * children > 0x70000000ul)
pci->phb->dma_window_size >>= 1;
- DBG("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size);
-
+ pr_debug("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size);
}
@@ -401,7 +399,8 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
dn = pci_bus_to_OF_node(bus);
- DBG("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", dn->full_name);
+ pr_debug("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n",
+ dn->full_name);
/* Find nearest ibm,dma-window, walking up the device tree */
for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
@@ -411,14 +410,14 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
}
if (dma_window == NULL) {
- DBG(" no ibm,dma-window property !\n");
+ pr_debug(" no ibm,dma-window property !\n");
return;
}
ppci = PCI_DN(pdn);
- DBG(" parent is %s, iommu_table: 0x%p\n",
- pdn->full_name, ppci->iommu_table);
+ pr_debug(" parent is %s, iommu_table: 0x%p\n",
+ pdn->full_name, ppci->iommu_table);
if (!ppci->iommu_table) {
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
@@ -426,7 +425,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window,
bus->number);
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
- DBG(" created table: %p\n", ppci->iommu_table);
+ pr_debug(" created table: %p\n", ppci->iommu_table);
}
if (pdn != dn)
@@ -439,7 +438,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
struct device_node *dn;
struct iommu_table *tbl;
- DBG("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev));
+ pr_debug("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev));
dn = dev->dev.archdata.of_node;
@@ -450,7 +449,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
if (!dev->bus->self) {
struct pci_controller *phb = PCI_DN(dn)->phb;
- DBG(" --> first child, no bridge. Allocating iommu table.\n");
+ pr_debug(" --> first child, no bridge. Allocating iommu table.\n");
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
phb->node);
iommu_table_setparms(phb, dn, tbl);
@@ -480,7 +479,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
const void *dma_window = NULL;
struct pci_dn *pci;
- DBG("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev));
+ pr_debug("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev));
/* dev setup for LPAR is a little tricky, since the device tree might
* contain the dma-window properties per-device and not neccesarily
@@ -489,7 +488,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
* already allocated.
*/
dn = pci_device_to_OF_node(dev);
- DBG(" node is %s\n", dn->full_name);
+ pr_debug(" node is %s\n", dn->full_name);
for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
pdn = pdn->parent) {
@@ -504,13 +503,13 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
pci_name(dev), dn? dn->full_name : "<null>");
return;
}
- DBG(" parent is %s\n", pdn->full_name);
+ pr_debug(" parent is %s\n", pdn->full_name);
/* Check for parent == NULL so we don't try to setup the empty EADS
* slots on POWER4 machines.
*/
if (dma_window == NULL || pdn->parent == NULL) {
- DBG(" no dma window for device, linking to parent\n");
+ pr_debug(" no dma window for device, linking to parent\n");
dev->dev.archdata.dma_data = PCI_DN(pdn)->iommu_table;
return;
}
@@ -522,9 +521,9 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window,
pci->phb->bus->number);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
- DBG(" created table: %p\n", pci->iommu_table);
+ pr_debug(" created table: %p\n", pci->iommu_table);
} else {
- DBG(" found DMA window, table: %p\n", pci->iommu_table);
+ pr_debug(" found DMA window, table: %p\n", pci->iommu_table);
}
dev->dev.archdata.dma_data = pci->iommu_table;
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 9235c469449e..2cbaedb17f3e 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -19,7 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#undef DEBUG_LOW
+/* Enables debugging of low-level hash table routines - careful! */
+#undef DEBUG
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
@@ -42,11 +43,6 @@
#include "plpar_wrappers.h"
#include "pseries.h"
-#ifdef DEBUG_LOW
-#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0)
-#else
-#define DBG_LOW(fmt...) do { } while(0)
-#endif
/* in hvCall.S */
EXPORT_SYMBOL(plpar_hcall);
@@ -196,6 +192,8 @@ void __init udbg_init_debug_lpar(void)
udbg_putc = udbg_putcLP;
udbg_getc = udbg_getcLP;
udbg_getc_poll = udbg_getc_pollLP;
+
+ register_early_udbg_console();
}
/* returns 0 if couldn't find or use /chosen/stdout as console */
@@ -288,15 +286,15 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
unsigned long hpte_v, hpte_r;
if (!(vflags & HPTE_V_BOLTED))
- DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
- "rflags=%lx, vflags=%lx, psize=%d)\n",
- hpte_group, va, pa, rflags, vflags, psize);
+ pr_debug("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
+ "rflags=%lx, vflags=%lx, psize=%d)\n",
+ hpte_group, va, pa, rflags, vflags, psize);
hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID;
hpte_r = hpte_encode_r(pa, psize) | rflags;
if (!(vflags & HPTE_V_BOLTED))
- DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
+ pr_debug(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
/* Now fill in the actual HPTE */
/* Set CEC cookie to 0 */
@@ -313,7 +311,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
if (unlikely(lpar_rc == H_PTEG_FULL)) {
if (!(vflags & HPTE_V_BOLTED))
- DBG_LOW(" full\n");
+ pr_debug(" full\n");
return -1;
}
@@ -324,11 +322,11 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
*/
if (unlikely(lpar_rc != H_SUCCESS)) {
if (!(vflags & HPTE_V_BOLTED))
- DBG_LOW(" lpar err %d\n", lpar_rc);
+ pr_debug(" lpar err %lu\n", lpar_rc);
return -2;
}
if (!(vflags & HPTE_V_BOLTED))
- DBG_LOW(" -> slot: %d\n", slot & 7);
+ pr_debug(" -> slot: %lu\n", slot & 7);
/* Because of iSeries, we have to pass down the secondary
* bucket bit here as well
@@ -420,17 +418,17 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot,
want_v = hpte_encode_avpn(va, psize, ssize);
- DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ",
- want_v, slot, flags, psize);
+ pr_debug(" update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...",
+ want_v, slot, flags, psize);
lpar_rc = plpar_pte_protect(flags, slot, want_v);
if (lpar_rc == H_NOT_FOUND) {
- DBG_LOW("not found !\n");
+ pr_debug("not found !\n");
return -1;
}
- DBG_LOW("ok\n");
+ pr_debug("ok\n");
BUG_ON(lpar_rc != H_SUCCESS);
@@ -505,8 +503,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
unsigned long lpar_rc;
unsigned long dummy1, dummy2;
- DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d",
- slot, va, psize, local);
+ pr_debug(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n",
+ slot, va, psize, local);
want_v = hpte_encode_avpn(va, psize, ssize);
lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2);
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index a1ab25c7082f..2b548afd1003 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -67,8 +67,6 @@ static int ras_check_exception_token;
static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
-/* #define DEBUG */
-
static void request_ras_irqs(struct device_node *np,
irq_handler_t handler,
@@ -237,7 +235,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n",
*((unsigned long *)&ras_log_buf), status);
-#ifndef DEBUG
+#ifndef DEBUG_RTAS_POWER_OFF
/* Don't actually power off when debugging so we can test
* without actually failing while injecting errors.
* Error data will not be logged to syslog.
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index e3078ce41518..befadd4f9524 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -29,11 +29,6 @@
#include <asm/atomic.h>
#include <asm/machdep.h>
-#if 0
-#define DEBUG(A...) printk(KERN_ERR A)
-#else
-#define DEBUG(A...)
-#endif
static DEFINE_SPINLOCK(rtasd_log_lock);
@@ -198,7 +193,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)
unsigned long s;
int len = 0;
- DEBUG("logging event\n");
+ pr_debug("rtasd: logging event\n");
if (buf == NULL)
return;
@@ -409,7 +404,8 @@ static int rtasd(void *unused)
daemonize("rtasd");
printk(KERN_DEBUG "RTAS daemon started\n");
- DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate));
+ pr_debug("rtasd: will sleep for %d milliseconds\n",
+ (30000 / rtas_event_scan_rate));
/* See if we have any error stored in NVRAM */
memset(logdata, 0, rtas_error_log_max);
@@ -428,9 +424,9 @@ static int rtasd(void *unused)
do_event_scan_all_cpus(1000);
if (surveillance_timeout != -1) {
- DEBUG("enabling surveillance\n");
+ pr_debug("rtasd: enabling surveillance\n");
enable_surveillance(surveillance_timeout);
- DEBUG("surveillance enabled\n");
+ pr_debug("rtasd: surveillance enabled\n");
}
/* Delay should be at least one second since some
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c
index e5b0ea870164..bec3803f0618 100644
--- a/arch/powerpc/platforms/pseries/scanlog.c
+++ b/arch/powerpc/platforms/pseries/scanlog.c
@@ -38,9 +38,7 @@
#define SCANLOG_HWERROR -1
#define SCANLOG_CONTINUE 1
-#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0)
-static int scanlog_debug;
static unsigned int ibm_scan_log_dump; /* RTAS token */
static struct proc_dir_entry *proc_ppc64_scan_log_dump; /* The proc file */
@@ -86,14 +84,14 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE);
spin_unlock(&rtas_data_buf_lock);
- DEBUG("status=%d, data[0]=%x, data[1]=%x, data[2]=%x\n",
- status, data[0], data[1], data[2]);
+ pr_debug("scanlog: status=%d, data[0]=%x, data[1]=%x, " \
+ "data[2]=%x\n", status, data[0], data[1], data[2]);
switch (status) {
case SCANLOG_COMPLETE:
- DEBUG("hit eof\n");
+ pr_debug("scanlog: hit eof\n");
return 0;
case SCANLOG_HWERROR:
- DEBUG("hardware error reading scan log data\n");
+ pr_debug("scanlog: hardware error reading data\n");
return -EIO;
case SCANLOG_CONTINUE:
/* We may or may not have data yet */
@@ -110,7 +108,8 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
/* Assume extended busy */
wait_time = rtas_busy_delay_time(status);
if (!wait_time) {
- printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status);
+ printk(KERN_ERR "scanlog: unknown error " \
+ "from rtas: %d\n", status);
return -EIO;
}
}
@@ -134,15 +133,9 @@ static ssize_t scanlog_write(struct file * file, const char __user * buf,
if (buf) {
if (strncmp(stkbuf, "reset", 5) == 0) {
- DEBUG("reset scanlog\n");
+ pr_debug("scanlog: reset scanlog\n");
status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, 0, 0);
- DEBUG("rtas returns %d\n", status);
- } else if (strncmp(stkbuf, "debugon", 7) == 0) {
- printk(KERN_ERR "scanlog: debug on\n");
- scanlog_debug = 1;
- } else if (strncmp(stkbuf, "debugoff", 8) == 0) {
- printk(KERN_ERR "scanlog: debug off\n");
- scanlog_debug = 0;
+ pr_debug("scanlog: rtas returns %d\n", status);
}
}
return count;
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index f66aa9c3b135..f5d29f5b13c1 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -16,8 +16,6 @@
* bootup setup stuff..
*/
-#undef DEBUG
-
#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -70,11 +68,6 @@
#include "plpar_wrappers.h"
#include "pseries.h"
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
int fwnmi_active; /* TRUE if an FWNMI handler is present */
@@ -326,7 +319,7 @@ static int pseries_set_xdabr(unsigned long dabr)
*/
static void __init pSeries_init_early(void)
{
- DBG(" -> pSeries_init_early()\n");
+ pr_debug(" -> pSeries_init_early()\n");
if (firmware_has_feature(FW_FEATURE_LPAR))
find_udbg_vterm();
@@ -338,7 +331,7 @@ static void __init pSeries_init_early(void)
iommu_init_early_pSeries();
- DBG(" <- pSeries_init_early()\n");
+ pr_debug(" <- pSeries_init_early()\n");
}
/*
@@ -383,7 +376,7 @@ static int __init pSeries_probe(void)
of_flat_dt_is_compatible(root, "IBM,CBEA"))
return 0;
- DBG("pSeries detected, looking for LPAR capability...\n");
+ pr_debug("pSeries detected, looking for LPAR capability...\n");
/* Now try to figure out if we are running on LPAR */
of_scan_flat_dt(pSeries_probe_hypertas, NULL);
@@ -393,8 +386,8 @@ static int __init pSeries_probe(void)
else
hpte_init_native();
- DBG("Machine is%s LPAR !\n",
- (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
+ pr_debug("Machine is%s LPAR !\n",
+ (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
return 1;
}
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index ea4c65917a64..9d8f8c84ab89 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -12,7 +12,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
@@ -51,12 +50,6 @@
#include "plpar_wrappers.h"
#include "pseries.h"
-#ifdef DEBUG
-#include <asm/udbg.h>
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
/*
* The primary thread of each non-boot processor is recorded here before
@@ -231,7 +224,7 @@ static void __init smp_init_pseries(void)
{
int i;
- DBG(" -> smp_init_pSeries()\n");
+ pr_debug(" -> smp_init_pSeries()\n");
/* Mark threads which are still spinning in hold loops. */
if (cpu_has_feature(CPU_FTR_SMT)) {
@@ -255,7 +248,7 @@ static void __init smp_init_pseries(void)
smp_ops->take_timebase = pSeries_take_timebase;
}
- DBG(" <- smp_init_pSeries()\n");
+ pr_debug(" <- smp_init_pSeries()\n");
}
#ifdef CONFIG_MPIC
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 43df53c30aa0..ebebc28fe895 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
#include <linux/types.h>
#include <linux/threads.h>
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index d359d6e92975..7f59188cd9a1 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -143,7 +143,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
*/
static int
axon_ram_direct_access(struct block_device *device, sector_t sector,
- unsigned long *data)
+ void **kaddr, unsigned long *pfn)
{
struct axon_ram_bank *bank = device->bd_disk->private_data;
loff_t offset;
@@ -154,7 +154,8 @@ axon_ram_direct_access(struct block_device *device, sector_t sector,
return -ERANGE;
}
- *data = bank->ph_addr + offset;
+ *kaddr = (void *)(bank->ph_addr + offset);
+ *pfn = virt_to_phys(kaddr) >> PAGE_SHIFT;
return 0;
}
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 5c1b246aaccc..7b45670c7af3 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -892,3 +892,44 @@ void fsl_rstcr_restart(char *cmd)
while (1) ;
}
#endif
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+struct platform_diu_data_ops diu_ops = {
+ .diu_size = 1280 * 1024 * 4, /* default one 1280x1024 buffer */
+};
+EXPORT_SYMBOL(diu_ops);
+
+int __init preallocate_diu_videomemory(void)
+{
+ pr_debug("diu_size=%lu\n", diu_ops.diu_size);
+
+ diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0);
+ if (!diu_ops.diu_mem) {
+ printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n",
+ diu_ops.diu_size);
+ return -ENOMEM;
+ }
+
+ pr_debug("diu_mem=%p\n", diu_ops.diu_mem);
+
+ rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block),
+ diu_ops.diu_rh_block);
+ return rh_attach_region(&diu_ops.diu_rh_info,
+ (unsigned long) diu_ops.diu_mem,
+ diu_ops.diu_size);
+}
+
+static int __init early_parse_diufb(char *p)
+{
+ if (!p)
+ return 1;
+
+ diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8);
+
+ pr_debug("diu_size=%lu\n", diu_ops.diu_size);
+
+ return 0;
+}
+early_param("diufb", early_parse_diufb);
+
+#endif
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 74c4a9657b33..52c831fa1886 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -17,5 +17,28 @@ extern int fsl_spi_init(struct spi_board_info *board_infos,
void (*deactivate_cs)(u8 cs, u8 polarity));
extern void fsl_rstcr_restart(char *cmd);
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+#include <linux/bootmem.h>
+#include <asm/rheap.h>
+struct platform_diu_data_ops {
+ rh_block_t diu_rh_block[16];
+ rh_info_t diu_rh_info;
+ unsigned long diu_size;
+ void *diu_mem;
+
+ unsigned int (*get_pixel_format) (unsigned int bits_per_pixel,
+ int monitor_port);
+ void (*set_gamma_table) (int monitor_port, char *gamma_table_base);
+ void (*set_monitor_port) (int monitor_port);
+ void (*set_pixel_clock) (unsigned int pixclock);
+ ssize_t (*show_monitor_port) (int monitor_port, char *buf);
+ int (*set_sysfs_monitor_port) (int val);
+};
+
+extern struct platform_diu_data_ops diu_ops;
+int __init preallocate_diu_videomemory(void);
+#endif
+
#endif
#endif
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index 047b31027fa6..41af1223e2a0 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -338,15 +338,13 @@ static int __init mv64x60_i2c_device_setup(struct device_node *np, int id)
pdata.freq_m = 8; /* default */
prop = of_get_property(np, "freq_m", NULL);
- if (!prop)
- return -ENODEV;
- pdata.freq_m = *prop;
+ if (prop)
+ pdata.freq_m = *prop;
pdata.freq_m = 3; /* default */
prop = of_get_property(np, "freq_n", NULL);
- if (!prop)
- return -ENODEV;
- pdata.freq_n = *prop;
+ if (prop)
+ pdata.freq_n = *prop;
pdata.timeout = 1000; /* default: 1 second */
@@ -433,9 +431,13 @@ static int __init mv64x60_device_setup(void)
int err;
id = 0;
- for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc")
- if ((err = mv64x60_mpsc_device_setup(np, id++)))
- goto error;
+ for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc") {
+ err = mv64x60_mpsc_device_setup(np, id++);
+ if (err)
+ printk(KERN_ERR "Failed to initialize MV64x60 "
+ "serial device %s: error %d.\n",
+ np->full_name, err);
+ }
id = 0;
id2 = 0;
@@ -443,38 +445,44 @@ static int __init mv64x60_device_setup(void)
pdev = mv64x60_eth_register_shared_pdev(np, id++);
if (IS_ERR(pdev)) {
err = PTR_ERR(pdev);
- goto error;
+ printk(KERN_ERR "Failed to initialize MV64x60 "
+ "network block %s: error %d.\n",
+ np->full_name, err);
+ continue;
}
for_each_child_of_node(np, np2) {
if (!of_device_is_compatible(np2,
"marvell,mv64360-eth"))
continue;
err = mv64x60_eth_device_setup(np2, id2++, pdev);
- if (err) {
- of_node_put(np2);
- goto error;
- }
+ if (err)
+ printk(KERN_ERR "Failed to initialize "
+ "MV64x60 network device %s: "
+ "error %d.\n",
+ np2->full_name, err);
}
}
id = 0;
- for_each_compatible_node(np, "i2c", "marvell,mv64360-i2c")
- if ((err = mv64x60_i2c_device_setup(np, id++)))
- goto error;
+ for_each_compatible_node(np, "i2c", "marvell,mv64360-i2c") {
+ err = mv64x60_i2c_device_setup(np, id++);
+ if (err)
+ printk(KERN_ERR "Failed to initialize MV64x60 I2C "
+ "bus %s: error %d.\n",
+ np->full_name, err);
+ }
/* support up to one watchdog timer */
np = of_find_compatible_node(np, NULL, "marvell,mv64360-wdt");
if (np) {
if ((err = mv64x60_wdt_device_setup(np, id)))
- goto error;
+ printk(KERN_ERR "Failed to initialize MV64x60 "
+ "Watchdog %s: error %d.\n",
+ np->full_name, err);
of_node_put(np);
}
return 0;
-
-error:
- of_node_put(np);
- return err;
}
arch_initcall(mv64x60_device_setup);
diff --git a/arch/powerpc/sysdev/mv64x60_udbg.c b/arch/powerpc/sysdev/mv64x60_udbg.c
index ccdb3b0418fc..2792dc8b038c 100644
--- a/arch/powerpc/sysdev/mv64x60_udbg.c
+++ b/arch/powerpc/sysdev/mv64x60_udbg.c
@@ -94,7 +94,7 @@ static void mv64x60_udbg_init(void)
if (!np)
return;
- block_index = of_get_property(np, "block-index", NULL);
+ block_index = of_get_property(np, "cell-index", NULL);
if (!block_index)
goto error;
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index bcc3aa9d04f3..d38b57e24cee 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -165,9 +165,6 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
#ifdef CONFIG_SBC82xx
#define F1_RXCLK 9
#define F1_TXCLK 10
-#elif defined(CONFIG_ADS8272)
-#define F1_RXCLK 11
-#define F1_TXCLK 10
#else
#define F1_RXCLK 12
#define F1_TXCLK 11
@@ -175,13 +172,8 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
/* FCC2 Clock Source Configuration. There are board specific.
Can only choose from CLK13-16 */
-#ifdef CONFIG_ADS8272
-#define F2_RXCLK 15
-#define F2_TXCLK 16
-#else
#define F2_RXCLK 13
#define F2_TXCLK 14
-#endif
/* FCC3 Clock Source Configuration. There are board specific.
Can only choose from CLK13-16 */
@@ -289,10 +281,7 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
/* TQM8260 has MDIO and MDCK on PC30 and PC31 respectively */
#define PC_MDIO ((uint)0x00000002)
#define PC_MDCK ((uint)0x00000001)
-#elif defined(CONFIG_ADS8272)
-#define PC_MDIO ((uint)0x00002000)
-#define PC_MDCK ((uint)0x00001000)
-#elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260) || defined(CONFIG_PQ2FADS)
+#elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260)
#define PC_MDIO ((uint)0x00400000)
#define PC_MDCK ((uint)0x00200000)
#else
@@ -2118,11 +2107,6 @@ init_fcc_startup(fcc_info_t *fip, struct net_device *dev)
printk("Can't get FCC IRQ %d\n", fip->fc_interrupt);
#ifdef PHY_INTERRUPT
-#ifdef CONFIG_ADS8272
- if (request_irq(PHY_INTERRUPT, mii_link_interrupt, IRQF_SHARED,
- "mii", dev) < 0)
- printk(KERN_CRIT "Can't get MII IRQ %d\n", PHY_INTERRUPT);
-#else
/* Make IRQn edge triggered. This does not work if PHY_INTERRUPT is
* on Port C.
*/
@@ -2132,7 +2116,6 @@ init_fcc_startup(fcc_info_t *fip, struct net_device *dev)
if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0,
"mii", dev) < 0)
printk(KERN_CRIT "Can't get MII IRQ %d\n", PHY_INTERRUPT);
-#endif
#endif /* PHY_INTERRUPT */
/* Set GFMR to enable Ethernet operating mode.
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index c6d047ae77ac..5899aea1644b 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -946,29 +946,6 @@ static int __init scc_enet_init(void)
*((volatile uint *)BCSR1) &= ~BCSR1_ETHEN;
#endif
-#ifdef CONFIG_MPC885ADS
-
- /* Deassert PHY reset and enable the PHY.
- */
- {
- volatile uint __iomem *bcsr = ioremap(BCSR_ADDR, BCSR_SIZE);
- uint tmp;
-
- tmp = in_be32(bcsr + 1 /* BCSR1 */);
- tmp |= BCSR1_ETHEN;
- out_be32(bcsr + 1, tmp);
- tmp = in_be32(bcsr + 4 /* BCSR4 */);
- tmp |= BCSR4_ETH10_RST;
- out_be32(bcsr + 4, tmp);
- iounmap(bcsr);
- }
-
- /* On MPC885ADS SCC ethernet PHY defaults to the full duplex mode
- * upon reset. SCC is set to half duplex by default. So this
- * inconsistency should be better fixed by the software.
- */
-#endif
-
dev->base_addr = (unsigned long)ep;
#if 0
dev->name = "CPM_ENET";
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index abc877faf123..0f1863ed9c1c 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -372,22 +372,6 @@ config MPC8XXFADS
bool "FADS"
select FADS
-config MPC86XADS
- bool "MPC86XADS"
- help
- MPC86x Application Development System by Freescale Semiconductor.
- The MPC86xADS is meant to serve as a platform for s/w and h/w
- development around the MPC86X processor families.
- select FADS
-
-config MPC885ADS
- bool "MPC885ADS"
- help
- Freescale Semiconductor MPC885 Application Development System (ADS).
- Also known as DUET.
- The MPC885ADS is meant to serve as a platform for s/w and h/w
- development around the MPC885 processor family.
-
config TQM823L
bool "TQM823L"
help
@@ -479,53 +463,6 @@ config WINCEPT
endchoice
-menu "Freescale Ethernet driver platform-specific options"
- depends on FS_ENET
-
- config MPC8xx_SECOND_ETH
- bool "Second Ethernet channel"
- depends on (MPC885ADS || MPC86XADS)
- default y
- help
- This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
- The latter will use SCC1, for 885ADS you can select it below.
-
- choice
- prompt "Second Ethernet channel"
- depends on MPC8xx_SECOND_ETH
- default MPC8xx_SECOND_ETH_FEC2
-
- config MPC8xx_SECOND_ETH_FEC2
- bool "FEC2"
- depends on MPC885ADS
- help
- Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
- (often 2-nd UART) will not work if this is enabled.
-
- config MPC8xx_SECOND_ETH_SCC1
- bool "SCC1"
- depends on MPC86XADS
- select MPC8xx_SCC_ENET_FIXED
- help
- Enable SCC1 to serve as 2-nd Ethernet channel. Note that SMC1
- (often 1-nd UART) will not work if this is enabled.
-
- config MPC8xx_SECOND_ETH_SCC3
- bool "SCC3"
- depends on MPC885ADS
- help
- Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
- (often 1-nd UART) will not work if this is enabled.
-
- endchoice
-
- config MPC8xx_SCC_ENET_FIXED
- depends on MPC8xx_SECOND_ETH_SCC
- default n
- bool "Use fixed MII-less mode for SCC Ethernet"
-
-endmenu
-
choice
prompt "Machine Type"
depends on 6xx
@@ -666,9 +603,6 @@ config TQM8260
End of Life: not yet :-)
URL: <http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf>
-config ADS8272
- bool "ADS8272"
-
config PQ2FADS
bool "Freescale-PQ2FADS"
help
@@ -698,11 +632,6 @@ config EV64360
platform.
endchoice
-config PQ2ADS
- bool
- depends on ADS8272
- default y
-
config TQM8xxL
bool
depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L)
@@ -725,15 +654,6 @@ config 8260
this option means that you wish to build a kernel for a machine with
an 8260 class CPU.
-config 8272
- bool
- depends on 6xx
- default y if ADS8272
- select 8260
- help
- The MPC8272 CPM has a different internal dpram setup than other CPM2
- devices
-
config CPM1
bool
depends on 8xx
@@ -1069,7 +989,7 @@ config PCI_8260
config 8260_PCI9
bool "Enable workaround for MPC826x erratum PCI 9"
- depends on PCI_8260 && !ADS8272
+ depends on PCI_8260
default y
choice
diff --git a/arch/ppc/configs/ads8272_defconfig b/arch/ppc/configs/ads8272_defconfig
deleted file mode 100644
index 6619f9118b00..000000000000
--- a/arch/ppc/configs/ads8272_defconfig
+++ /dev/null
@@ -1,930 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc5
-# Wed Apr 4 20:55:16 2007
-#
-CONFIG_MMU=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_ARCH_HAS_ILOG2_U32=y
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-CONFIG_GENERIC_BUG=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
-# CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
-CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY 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_SYSCTL_SYSCALL=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-CONFIG_SHMEM=y
-CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# Block layer
-#
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-
-#
-# Processor
-#
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_8xx is not set
-# CONFIG_E200 is not set
-# CONFIG_E500 is not set
-CONFIG_PPC_FPU=y
-# CONFIG_PPC_DCR_NATIVE is not set
-# CONFIG_KEXEC is not set
-# CONFIG_CPU_FREQ is not set
-# CONFIG_WANT_EARLY_SERIAL is not set
-CONFIG_EMBEDDEDBOOT=y
-CONFIG_PPC_STD_MMU=y
-
-#
-# Platform options
-#
-
-#
-# Freescale Ethernet driver platform-specific options
-#
-# CONFIG_PPC_PREP is not set
-# CONFIG_APUS is not set
-# CONFIG_KATANA is not set
-# CONFIG_WILLOW is not set
-# CONFIG_CPCI690 is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_CHESTNUT is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_HDPU is not set
-# CONFIG_EV64260 is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_RADSTONE_PPC7D is not set
-# CONFIG_PAL4 is not set
-# CONFIG_EST8260 is not set
-# CONFIG_SBC82xx is not set
-# CONFIG_SBS8260 is not set
-# CONFIG_RPX8260 is not set
-# CONFIG_TQM8260 is not set
-CONFIG_ADS8272=y
-# CONFIG_PQ2FADS is not set
-# CONFIG_LITE5200 is not set
-# CONFIG_MPC834x_SYS is not set
-# CONFIG_EV64360 is not set
-CONFIG_PQ2ADS=y
-CONFIG_8260=y
-CONFIG_8272=y
-CONFIG_CPM2=y
-# CONFIG_PC_KEYBOARD is not set
-# CONFIG_SMP is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-# 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_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT 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_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-# CONFIG_PM is not set
-CONFIG_SECCOMP=y
-CONFIG_ISA_DMA_API=y
-
-#
-# Bus options
-#
-CONFIG_ZONE_DMA=y
-# CONFIG_PPC_I8259 is not set
-CONFIG_PPC_INDIRECT_PCI=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_8260=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NETDEBUG is not set
-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_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE 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_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_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# 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
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_NETLINK is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-# CONFIG_MAC_EMUMOUSEBTN is not set
-# CONFIG_WINDFARM is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-CONFIG_DAVICOM_PHY=y
-# 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_FIXED_PHY is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-CONFIG_FS_ENET=y
-# CONFIG_FS_ENET_HAS_SCC is not set
-CONFIG_FS_ENET_HAS_FCC=y
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-# CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV 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_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_UARTLITE is not set
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-CONFIG_SERIAL_CPM_SCC1=y
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-CONFIG_SERIAL_CPM_SCC4=y
-# CONFIG_SERIAL_CPM_SMC1 is not set
-# CONFIG_SERIAL_CPM_SMC2 is not set
-# CONFIG_SERIAL_JSM is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
-# CONFIG_NVRAM is not set
-CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-# CONFIG_FB is not set
-# CONFIG_FB_IBM_GXT4500 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-# CONFIG_USB is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# 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_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# 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_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM is not set
-# CONFIG_SCC_ENET is not set
-# CONFIG_FEC_ENET is not set
-
-#
-# CPM2 Options
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC32 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_KGDB_CONSOLE is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=y
-# CONFIG_CRYPTO_LRW is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/ppc/configs/mpc86x_ads_defconfig b/arch/ppc/configs/mpc86x_ads_defconfig
deleted file mode 100644
index f63c6f59d68a..000000000000
--- a/arch/ppc/configs/mpc86x_ads_defconfig
+++ /dev/null
@@ -1,633 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc4
-# Tue Jun 14 13:36:35 2005
-#
-CONFIG_MMU=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-# CONFIG_BASE_FULL is not set
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SHMEM is not set
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-CONFIG_TINY_SHMEM=y
-CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-# CONFIG_KMOD is not set
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-CONFIG_8xx=y
-# CONFIG_E500 is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_EMBEDDEDBOOT=y
-# CONFIG_PM is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-CONFIG_FADS=y
-# CONFIG_RPXLITE is not set
-# CONFIG_RPXCLASSIC is not set
-# CONFIG_BSEIP is not set
-# CONFIG_MPC8XXFADS is not set
-CONFIG_MPC86XADS=y
-# CONFIG_TQM823L is not set
-# CONFIG_TQM850L is not set
-# CONFIG_TQM855L is not set
-# CONFIG_TQM860L is not set
-# CONFIG_FPS850L is not set
-# CONFIG_SPD823TS is not set
-# CONFIG_IVMS8 is not set
-# CONFIG_IVML24 is not set
-# CONFIG_SM850 is not set
-# CONFIG_HERMES_PRO is not set
-# CONFIG_IP860 is not set
-# CONFIG_LWMON is not set
-# CONFIG_PCU_E is not set
-# CONFIG_CCM is not set
-# CONFIG_LANTEC is not set
-# CONFIG_MBX is not set
-# CONFIG_WINCEPT is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_ISA_DMA_API=y
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_CONSISTENT_START=0xff100000
-CONFIG_CONSISTENT_SIZE=0x00200000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-# CONFIG_STANDALONE is not set
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# 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 is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-CONFIG_IPV6=m
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP 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_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_SERIAL_CPM_SCC1 is not set
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-# CONFIG_SERIAL_CPM_SCC4 is not set
-CONFIG_SERIAL_CPM_SMC1=y
-# CONFIG_SERIAL_CPM_SMC2 is not set
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_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_KCORE=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# 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_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# MPC8xx CPM Options
-#
-CONFIG_SCC_ENET=y
-CONFIG_SCC1_ENET=y
-# CONFIG_SCC2_ENET is not set
-# CONFIG_SCC3_ENET is not set
-# CONFIG_FEC_ENET is not set
-# CONFIG_ENET_BIG_BUFFERS is not set
-
-#
-# Generic MPC8xx Options
-#
-# CONFIG_8xx_COPYBACK is not set
-# CONFIG_8xx_CPU6 is not set
-CONFIG_NO_UCODE_PATCH=y
-# CONFIG_USB_SOF_UCODE_PATCH is not set
-# CONFIG_I2C_SPI_UCODE_PATCH is not set
-# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
-# CONFIG_LIBCRC32C is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/ppc/configs/mpc885ads_defconfig b/arch/ppc/configs/mpc885ads_defconfig
deleted file mode 100644
index 016f94d9325f..000000000000
--- a/arch/ppc/configs/mpc885ads_defconfig
+++ /dev/null
@@ -1,622 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc6
-# Thu Jun 9 21:17:29 2005
-#
-CONFIG_MMU=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_HAVE_DEC_LOCK=y
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_GENERIC_NVRAM=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-# CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# Processor
-#
-# CONFIG_6xx is not set
-# CONFIG_40x is not set
-# CONFIG_44x is not set
-# CONFIG_POWER3 is not set
-# CONFIG_POWER4 is not set
-CONFIG_8xx=y
-# CONFIG_E500 is not set
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_CPU_FREQ is not set
-CONFIG_EMBEDDEDBOOT=y
-# CONFIG_PM is not set
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# Platform options
-#
-# CONFIG_RPXLITE is not set
-# CONFIG_RPXCLASSIC is not set
-# CONFIG_BSEIP is not set
-# CONFIG_FADS is not set
-CONFIG_MPC885ADS=y
-# CONFIG_TQM823L is not set
-# CONFIG_TQM850L is not set
-# CONFIG_TQM855L is not set
-# CONFIG_TQM860L is not set
-# CONFIG_FPS850L is not set
-# CONFIG_SPD823TS is not set
-# CONFIG_IVMS8 is not set
-# CONFIG_IVML24 is not set
-# CONFIG_SM850 is not set
-# CONFIG_HERMES_PRO is not set
-# CONFIG_IP860 is not set
-# CONFIG_LWMON is not set
-# CONFIG_PCU_E is not set
-# CONFIG_CCM is not set
-# CONFIG_LANTEC is not set
-# CONFIG_MBX is not set
-# CONFIG_WINCEPT is not set
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_ISA_DMA_API=y
-
-#
-# Bus options
-#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_QSPAN is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Advanced setup
-#
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Default settings for advanced configuration options are used
-#
-CONFIG_HIGHMEM_START=0xfe000000
-CONFIG_LOWMEM_SIZE=0x30000000
-CONFIG_KERNEL_START=0xc0000000
-CONFIG_TASK_SIZE=0x80000000
-CONFIG_CONSISTENT_START=0xff100000
-CONFIG_CONSISTENT_SIZE=0x00200000
-CONFIG_BOOT_LOAD=0x00400000
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# 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_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
-# CONFIG_CDROM_PKTCDVD 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_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
-# Macintosh device drivers
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# 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 is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP 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_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_OAKNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-CONFIG_PPP=y
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPPOE is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_SERIAL_CPM_SCC1 is not set
-# CONFIG_SERIAL_CPM_SCC2 is not set
-# CONFIG_SERIAL_CPM_SCC3 is not set
-# CONFIG_SERIAL_CPM_SCC4 is not set
-CONFIG_SERIAL_CPM_SMC1=y
-CONFIG_SERIAL_CPM_SMC2=y
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-# CONFIG_EXT2_FS_POSIX_ACL is not set
-# CONFIG_EXT2_FS_SECURITY is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_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_KCORE is not set
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# 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_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# MPC8xx CPM Options
-#
-CONFIG_SCC_ENET=y
-# CONFIG_SCC1_ENET is not set
-# CONFIG_SCC2_ENET is not set
-CONFIG_SCC3_ENET=y
-# CONFIG_FEC_ENET is not set
-# CONFIG_ENET_BIG_BUFFERS is not set
-
-#
-# Generic MPC8xx Options
-#
-CONFIG_8xx_COPYBACK=y
-CONFIG_8xx_CPU6=y
-CONFIG_NO_UCODE_PATCH=y
-# CONFIG_USB_SOF_UCODE_PATCH is not set
-# CONFIG_I2C_SPI_UCODE_PATCH is not set
-# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=y
-# CONFIG_CRC32 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 2ba659f401be..d9036ef0b658 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -88,6 +88,7 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
index 84ed33ab4c2d..927253bfc826 100644
--- a/arch/ppc/lib/string.S
+++ b/arch/ppc/lib/string.S
@@ -121,6 +121,20 @@ _GLOBAL(strcmp)
beq 1b
blr
+_GLOBAL(strncmp)
+ PPC_LCMPI r5,0
+ beqlr
+ mtctr r5
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ bdnzt eq,1b
+ blr
+
_GLOBAL(strlen)
addi r4,r3,-1
1: lbzu r0,1(r4)
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index 40f53fbe6d35..6260231987cb 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -4,7 +4,6 @@
obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o
obj-$(CONFIG_PREP_RESIDUAL) += residual.o
-obj-$(CONFIG_PQ2ADS) += pq2ads.o
obj-$(CONFIG_TQM8260) += tqm8260_setup.o
obj-$(CONFIG_CPCI690) += cpci690.o
obj-$(CONFIG_EV64260) += ev64260.o
@@ -24,6 +23,3 @@ obj-$(CONFIG_SBC82xx) += sbc82xx.o
obj-$(CONFIG_SPRUCE) += spruce.o
obj-$(CONFIG_LITE5200) += lite5200.o
obj-$(CONFIG_EV64360) += ev64360.o
-obj-$(CONFIG_MPC86XADS) += mpc866ads_setup.o
-obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o
-obj-$(CONFIG_ADS8272) += mpc8272ads_setup.o
diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h
index 2f9f0f60e3f7..5219366667b3 100644
--- a/arch/ppc/platforms/fads.h
+++ b/arch/ppc/platforms/fads.h
@@ -22,29 +22,6 @@
#include <asm/ppcboot.h>
-#if defined(CONFIG_MPC86XADS)
-
-#define BOARD_CHIP_NAME "MPC86X"
-
-/* U-Boot maps BCSR to 0xff080000 */
-#define BCSR_ADDR ((uint)0xff080000)
-
-/* MPC86XADS has one more CPLD and an additional BCSR.
- */
-#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
-#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
-
-#define BCSR5_T1_RST 0x10
-#define BCSR5_ATM155_RST 0x08
-#define BCSR5_ATM25_RST 0x04
-#define BCSR5_MII1_EN 0x02
-#define BCSR5_MII1_RST 0x01
-
-/* There is no PHY link change interrupt */
-#define PHY_INTERRUPT (-1)
-
-#else /* FADS */
-
/* Memory map is configured by the PROM startup.
* I tried to follow the FADS manual, although the startup PROM
* dictates this and we simply have to move some of the physical
@@ -55,8 +32,6 @@
/* PHY link change interrupt */
#define PHY_INTERRUPT SIU_IRQ2
-#endif /* CONFIG_MPC86XADS */
-
#define BCSR_SIZE ((uint)(64 * 1024))
#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c
deleted file mode 100644
index 47f4b38edb5f..000000000000
--- a/arch/ppc/platforms/mpc8272ads_setup.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * arch/ppc/platforms/mpc8272ads_setup.c
- *
- * MPC82xx Board-specific PlatformDevice descriptions
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.mvista.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/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/ioport.h>
-#include <linux/fs_enet_pd.h>
-#include <linux/platform_device.h>
-#include <linux/phy.h>
-
-#include <asm/io.h>
-#include <asm/mpc8260.h>
-#include <asm/cpm2.h>
-#include <asm/immap_cpm2.h>
-#include <asm/irq.h>
-#include <asm/ppc_sys.h>
-#include <asm/ppcboot.h>
-#include <linux/fs_uart_pd.h>
-
-#include "pq2ads_pd.h"
-
-static void init_fcc1_ioports(struct fs_platform_info*);
-static void init_fcc2_ioports(struct fs_platform_info*);
-static void init_scc1_uart_ioports(struct fs_uart_platform_info*);
-static void init_scc4_uart_ioports(struct fs_uart_platform_info*);
-
-static struct fs_uart_platform_info mpc8272_uart_pdata[] = {
- [fsid_scc1_uart] = {
- .init_ioports = init_scc1_uart_ioports,
- .fs_no = fsid_scc1_uart,
- .brg = 1,
- .tx_num_fifo = 4,
- .tx_buf_size = 32,
- .rx_num_fifo = 4,
- .rx_buf_size = 32,
- },
- [fsid_scc4_uart] = {
- .init_ioports = init_scc4_uart_ioports,
- .fs_no = fsid_scc4_uart,
- .brg = 4,
- .tx_num_fifo = 4,
- .tx_buf_size = 32,
- .rx_num_fifo = 4,
- .rx_buf_size = 32,
- },
-};
-
-static struct fs_mii_bb_platform_info m82xx_mii_bb_pdata = {
- .mdio_dat.bit = 18,
- .mdio_dir.bit = 18,
- .mdc_dat.bit = 19,
- .delay = 1,
-};
-
-static struct fs_platform_info mpc82xx_enet_pdata[] = {
- [fsid_fcc1] = {
- .fs_no = fsid_fcc1,
- .cp_page = CPM_CR_FCC1_PAGE,
- .cp_block = CPM_CR_FCC1_SBLOCK,
-
- .clk_trx = (PC_F1RXCLK | PC_F1TXCLK),
- .clk_route = CMX1_CLK_ROUTE,
- .clk_mask = CMX1_CLK_MASK,
- .init_ioports = init_fcc1_ioports,
-
- .mem_offset = FCC1_MEM_OFFSET,
-
- .rx_ring = 32,
- .tx_ring = 32,
- .rx_copybreak = 240,
- .use_napi = 0,
- .napi_weight = 17,
- .bus_id = "0:00",
- },
- [fsid_fcc2] = {
- .fs_no = fsid_fcc2,
- .cp_page = CPM_CR_FCC2_PAGE,
- .cp_block = CPM_CR_FCC2_SBLOCK,
- .clk_trx = (PC_F2RXCLK | PC_F2TXCLK),
- .clk_route = CMX2_CLK_ROUTE,
- .clk_mask = CMX2_CLK_MASK,
- .init_ioports = init_fcc2_ioports,
-
- .mem_offset = FCC2_MEM_OFFSET,
-
- .rx_ring = 32,
- .tx_ring = 32,
- .rx_copybreak = 240,
- .use_napi = 0,
- .napi_weight = 17,
- .bus_id = "0:03",
- },
-};
-
-static void init_fcc1_ioports(struct fs_platform_info* pdata)
-{
- struct io_port *io;
- u32 tempval;
- cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
- u32 *bcsr = ioremap(BCSR_ADDR+4, sizeof(u32));
-
- io = &immap->im_ioport;
-
- /* Enable the PHY */
- clrbits32(bcsr, BCSR1_FETHIEN);
- setbits32(bcsr, BCSR1_FETH_RST);
-
- /* FCC1 pins are on port A/C. */
- /* Configure port A and C pins for FCC1 Ethernet. */
-
- tempval = in_be32(&io->iop_pdira);
- tempval &= ~PA1_DIRA0;
- tempval |= PA1_DIRA1;
- out_be32(&io->iop_pdira, tempval);
-
- tempval = in_be32(&io->iop_psora);
- tempval &= ~PA1_PSORA0;
- tempval |= PA1_PSORA1;
- out_be32(&io->iop_psora, tempval);
-
- setbits32(&io->iop_ppara,PA1_DIRA0 | PA1_DIRA1);
-
- /* Alter clocks */
- tempval = PC_F1TXCLK|PC_F1RXCLK;
-
- clrbits32(&io->iop_psorc, tempval);
- clrbits32(&io->iop_pdirc, tempval);
- setbits32(&io->iop_pparc, tempval);
-
- clrbits32(&immap->im_cpmux.cmx_fcr, CMX1_CLK_MASK);
- setbits32(&immap->im_cpmux.cmx_fcr, CMX1_CLK_ROUTE);
- iounmap(bcsr);
- iounmap(immap);
-}
-
-static void init_fcc2_ioports(struct fs_platform_info* pdata)
-{
- cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
- u32 *bcsr = ioremap(BCSR_ADDR+12, sizeof(u32));
-
- struct io_port *io;
- u32 tempval;
-
- immap = cpm2_immr;
-
- io = &immap->im_ioport;
-
- /* Enable the PHY */
- clrbits32(bcsr, BCSR3_FETHIEN2);
- setbits32(bcsr, BCSR3_FETH2_RST);
-
- /* FCC2 are port B/C. */
- /* Configure port A and C pins for FCC2 Ethernet. */
-
- tempval = in_be32(&io->iop_pdirb);
- tempval &= ~PB2_DIRB0;
- tempval |= PB2_DIRB1;
- out_be32(&io->iop_pdirb, tempval);
-
- tempval = in_be32(&io->iop_psorb);
- tempval &= ~PB2_PSORB0;
- tempval |= PB2_PSORB1;
- out_be32(&io->iop_psorb, tempval);
-
- setbits32(&io->iop_pparb,PB2_DIRB0 | PB2_DIRB1);
-
- tempval = PC_F2RXCLK|PC_F2TXCLK;
-
- /* Alter clocks */
- clrbits32(&io->iop_psorc,tempval);
- clrbits32(&io->iop_pdirc,tempval);
- setbits32(&io->iop_pparc,tempval);
-
- clrbits32(&immap->im_cpmux.cmx_fcr, CMX2_CLK_MASK);
- setbits32(&immap->im_cpmux.cmx_fcr, CMX2_CLK_ROUTE);
-
- iounmap(bcsr);
- iounmap(immap);
-}
-
-
-static void __init mpc8272ads_fixup_enet_pdata(struct platform_device *pdev,
- int idx)
-{
- bd_t* bi = (void*)__res;
- int fs_no = fsid_fcc1+pdev->id-1;
-
- if(fs_no >= ARRAY_SIZE(mpc82xx_enet_pdata)) {
- return;
- }
-
- mpc82xx_enet_pdata[fs_no].dpram_offset=
- (u32)cpm2_immr->im_dprambase;
- mpc82xx_enet_pdata[fs_no].fcc_regs_c =
- (u32)cpm2_immr->im_fcc_c;
- memcpy(&mpc82xx_enet_pdata[fs_no].macaddr,bi->bi_enetaddr,6);
-
- /* prevent dup mac */
- if(fs_no == fsid_fcc2)
- mpc82xx_enet_pdata[fs_no].macaddr[5] ^= 1;
-
- pdev->dev.platform_data = &mpc82xx_enet_pdata[fs_no];
-}
-
-static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev,
- int idx)
-{
- bd_t *bd = (bd_t *) __res;
- struct fs_uart_platform_info *pinfo;
- int num = ARRAY_SIZE(mpc8272_uart_pdata);
- int id = fs_uart_id_scc2fsid(idx);
-
- /* no need to alter anything if console */
- if ((id < num) && (!pdev->dev.platform_data)) {
- pinfo = &mpc8272_uart_pdata[id];
- pinfo->uart_clk = bd->bi_intfreq;
- pdev->dev.platform_data = pinfo;
- }
-}
-
-static void init_scc1_uart_ioports(struct fs_uart_platform_info* pdata)
-{
- cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
-
- /* SCC1 is only on port D */
- setbits32(&immap->im_ioport.iop_ppard,0x00000003);
- clrbits32(&immap->im_ioport.iop_psord,0x00000001);
- setbits32(&immap->im_ioport.iop_psord,0x00000002);
- clrbits32(&immap->im_ioport.iop_pdird,0x00000001);
- setbits32(&immap->im_ioport.iop_pdird,0x00000002);
-
- /* Wire BRG1 to SCC1 */
- clrbits32(&immap->im_cpmux.cmx_scr,0x00ffffff);
-
- iounmap(immap);
-}
-
-static void init_scc4_uart_ioports(struct fs_uart_platform_info* pdata)
-{
- cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
-
- setbits32(&immap->im_ioport.iop_ppard,0x00000600);
- clrbits32(&immap->im_ioport.iop_psord,0x00000600);
- clrbits32(&immap->im_ioport.iop_pdird,0x00000200);
- setbits32(&immap->im_ioport.iop_pdird,0x00000400);
-
- /* Wire BRG4 to SCC4 */
- clrbits32(&immap->im_cpmux.cmx_scr,0x000000ff);
- setbits32(&immap->im_cpmux.cmx_scr,0x0000001b);
-
- iounmap(immap);
-}
-
-static void __init mpc8272ads_fixup_mdio_pdata(struct platform_device *pdev,
- int idx)
-{
- m82xx_mii_bb_pdata.irq[0] = PHY_INTERRUPT;
- m82xx_mii_bb_pdata.irq[1] = PHY_POLL;
- m82xx_mii_bb_pdata.irq[2] = PHY_POLL;
- m82xx_mii_bb_pdata.irq[3] = PHY_INTERRUPT;
- m82xx_mii_bb_pdata.irq[31] = PHY_POLL;
-
-
- m82xx_mii_bb_pdata.mdio_dat.offset =
- (u32)&cpm2_immr->im_ioport.iop_pdatc;
-
- m82xx_mii_bb_pdata.mdio_dir.offset =
- (u32)&cpm2_immr->im_ioport.iop_pdirc;
-
- m82xx_mii_bb_pdata.mdc_dat.offset =
- (u32)&cpm2_immr->im_ioport.iop_pdatc;
-
-
- pdev->dev.platform_data = &m82xx_mii_bb_pdata;
-}
-
-static int mpc8272ads_platform_notify(struct device *dev)
-{
- static const struct platform_notify_dev_map dev_map[] = {
- {
- .bus_id = "fsl-cpm-fcc",
- .rtn = mpc8272ads_fixup_enet_pdata,
- },
- {
- .bus_id = "fsl-cpm-scc:uart",
- .rtn = mpc8272ads_fixup_uart_pdata,
- },
- {
- .bus_id = "fsl-bb-mdio",
- .rtn = mpc8272ads_fixup_mdio_pdata,
- },
- {
- .bus_id = NULL
- }
- };
- platform_notify_map(dev_map,dev);
-
- return 0;
-
-}
-
-int __init mpc8272ads_init(void)
-{
- printk(KERN_NOTICE "mpc8272ads: Init\n");
-
- platform_notify = mpc8272ads_platform_notify;
-
- ppc_sys_device_initfunc();
-
- ppc_sys_device_disable_all();
- ppc_sys_device_enable(MPC82xx_CPM_FCC1);
- ppc_sys_device_enable(MPC82xx_CPM_FCC2);
-
- /* to be ready for console, let's attach pdata here */
-#ifdef CONFIG_SERIAL_CPM_SCC1
- ppc_sys_device_setfunc(MPC82xx_CPM_SCC1, PPC_SYS_FUNC_UART);
- ppc_sys_device_enable(MPC82xx_CPM_SCC1);
-
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SCC4
- ppc_sys_device_setfunc(MPC82xx_CPM_SCC4, PPC_SYS_FUNC_UART);
- ppc_sys_device_enable(MPC82xx_CPM_SCC4);
-#endif
-
- ppc_sys_device_enable(MPC82xx_MDIO_BB);
-
- return 0;
-}
-
-/*
- To prevent confusion, console selection is gross:
- by 0 assumed SCC1 and by 1 assumed SCC4
- */
-struct platform_device* early_uart_get_pdev(int index)
-{
- bd_t *bd = (bd_t *) __res;
- struct fs_uart_platform_info *pinfo;
-
- struct platform_device* pdev = NULL;
- if(index) { /*assume SCC4 here*/
- pdev = &ppc_sys_platform_devices[MPC82xx_CPM_SCC4];
- pinfo = &mpc8272_uart_pdata[fsid_scc4_uart];
- } else { /*over SCC1*/
- pdev = &ppc_sys_platform_devices[MPC82xx_CPM_SCC1];
- pinfo = &mpc8272_uart_pdata[fsid_scc1_uart];
- }
-
- pinfo->uart_clk = bd->bi_intfreq;
- pdev->dev.platform_data = pinfo;
- ppc_sys_fixup_mem_resource(pdev, CPM_MAP_ADDR);
- return NULL;
-}
-
-arch_initcall(mpc8272ads_init);
diff --git a/arch/ppc/platforms/mpc885ads.h b/arch/ppc/platforms/mpc885ads.h
deleted file mode 100644
index d3bbbb3c9a1f..000000000000
--- a/arch/ppc/platforms/mpc885ads.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * A collection of structures, addresses, and values associated with
- * the Freescale MPC885ADS board.
- * Copied from the FADS stuff.
- *
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- *
- * 2005 (c) MontaVista Software, Inc. 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.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_MPC885ADS_H__
-#define __ASM_MPC885ADS_H__
-
-
-#include <asm/ppcboot.h>
-
-/* U-Boot maps BCSR to 0xff080000 */
-#define BCSR_ADDR ((uint)0xff080000)
-#define BCSR_SIZE ((uint)32)
-#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
-#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
-#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
-#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
-#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
-
-#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
-#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
-
-#define IMAP_ADDR ((uint)0xff000000)
-#define IMAP_SIZE ((uint)(64 * 1024))
-
-#define PCMCIA_MEM_ADDR ((uint)0xff020000)
-#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
-
-/* Bits of interest in the BCSRs.
- */
-#define BCSR1_ETHEN ((uint)0x20000000)
-#define BCSR1_IRDAEN ((uint)0x10000000)
-#define BCSR1_RS232EN_1 ((uint)0x01000000)
-#define BCSR1_PCCEN ((uint)0x00800000)
-#define BCSR1_PCCVCC0 ((uint)0x00400000)
-#define BCSR1_PCCVPP0 ((uint)0x00200000)
-#define BCSR1_PCCVPP1 ((uint)0x00100000)
-#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
-#define BCSR1_RS232EN_2 ((uint)0x00040000)
-#define BCSR1_PCCVCC1 ((uint)0x00010000)
-#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
-
-#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
-#define BCSR4_USB_LO_SPD ((uint)0x04000000)
-#define BCSR4_USB_VCC ((uint)0x02000000)
-#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
-#define BCSR4_USB_EN ((uint)0x00020000)
-
-#define BCSR5_MII2_EN 0x40
-#define BCSR5_MII2_RST 0x20
-#define BCSR5_T1_RST 0x10
-#define BCSR5_ATM155_RST 0x08
-#define BCSR5_ATM25_RST 0x04
-#define BCSR5_MII1_EN 0x02
-#define BCSR5_MII1_RST 0x01
-
-/* Interrupt level assignments */
-#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */
-#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */
-#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */
-#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */
-
-/* We don't use the 8259 */
-#define NR_8259_INTS 0
-
-/* CPM Ethernet through SCC3 */
-#define PA_ENET_RXD ((ushort)0x0040)
-#define PA_ENET_TXD ((ushort)0x0080)
-#define PE_ENET_TCLK ((uint)0x00004000)
-#define PE_ENET_RCLK ((uint)0x00008000)
-#define PE_ENET_TENA ((uint)0x00000010)
-#define PC_ENET_CLSN ((ushort)0x0400)
-#define PC_ENET_RENA ((ushort)0x0800)
-
-/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to
- * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */
-#define SICR_ENET_MASK ((uint)0x00ff0000)
-#define SICR_ENET_CLKRT ((uint)0x002c0000)
-
-#define BOARD_CHIP_NAME "MPC885"
-
-#endif /* __ASM_MPC885ADS_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c
deleted file mode 100644
index ba06cc08cdab..000000000000
--- a/arch/ppc/platforms/mpc885ads_setup.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*arch/ppc/platforms/mpc885ads_setup.c
- *
- * Platform setup for the Freescale mpc885ads board
- *
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * Copyright 2005 MontaVista Software Inc.
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-
-#include <linux/fs_enet_pd.h>
-#include <linux/fs_uart_pd.h>
-#include <linux/mii.h>
-
-#include <asm/delay.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/time.h>
-#include <asm/ppcboot.h>
-#include <asm/8xx_immap.h>
-#include <asm/cpm1.h>
-#include <asm/ppc_sys.h>
-
-extern unsigned char __res[];
-static void setup_smc1_ioports(struct fs_uart_platform_info*);
-static void setup_smc2_ioports(struct fs_uart_platform_info*);
-
-static struct fs_mii_fec_platform_info mpc8xx_mdio_fec_pdata;
-static void setup_fec1_ioports(struct fs_platform_info*);
-static void setup_fec2_ioports(struct fs_platform_info*);
-static void setup_scc3_ioports(struct fs_platform_info*);
-
-static struct fs_uart_platform_info mpc885_uart_pdata[] = {
- [fsid_smc1_uart] = {
- .brg = 1,
- .fs_no = fsid_smc1_uart,
- .init_ioports = setup_smc1_ioports,
- .tx_num_fifo = 4,
- .tx_buf_size = 32,
- .rx_num_fifo = 4,
- .rx_buf_size = 32,
- },
- [fsid_smc2_uart] = {
- .brg = 2,
- .fs_no = fsid_smc2_uart,
- .init_ioports = setup_smc2_ioports,
- .tx_num_fifo = 4,
- .tx_buf_size = 32,
- .rx_num_fifo = 4,
- .rx_buf_size = 32,
- },
-};
-
-static struct fs_platform_info mpc8xx_enet_pdata[] = {
- [fsid_fec1] = {
- .rx_ring = 128,
- .tx_ring = 16,
- .rx_copybreak = 240,
-
- .use_napi = 1,
- .napi_weight = 17,
-
- .init_ioports = setup_fec1_ioports,
-
- .bus_id = "0:00",
- .has_phy = 1,
- },
- [fsid_fec2] = {
- .rx_ring = 128,
- .tx_ring = 16,
- .rx_copybreak = 240,
-
- .use_napi = 1,
- .napi_weight = 17,
-
- .init_ioports = setup_fec2_ioports,
-
- .bus_id = "0:01",
- .has_phy = 1,
- },
- [fsid_scc3] = {
- .rx_ring = 64,
- .tx_ring = 8,
- .rx_copybreak = 240,
-
- .use_napi = 1,
- .napi_weight = 17,
-
- .init_ioports = setup_scc3_ioports,
-#ifdef CONFIG_FIXED_MII_10_FDX
- .bus_id = "fixed@100:1",
-#else
- .bus_id = "0:02",
- #endif
- },
-};
-
-void __init board_init(void)
-{
- cpm8xx_t *cp = cpmp;
- unsigned int *bcsr_io;
-
-#ifdef CONFIG_FS_ENET
- immap_t *immap = (immap_t *) IMAP_ADDR;
-#endif
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-
- if (bcsr_io == NULL) {
- printk(KERN_CRIT "Could not remap BCSR\n");
- return;
- }
-#ifdef CONFIG_SERIAL_CPM_SMC1
- cp->cp_simode &= ~(0xe0000000 >> 17); /* brg1 */
- clrbits32(bcsr_io, BCSR1_RS232EN_1);
- cp->cp_smc[0].smc_smcm |= (SMCM_RX | SMCM_TX);
- cp->cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-#else
- setbits32(bcsr_io,BCSR1_RS232EN_1);
- cp->cp_smc[0].smc_smcmr = 0;
- cp->cp_smc[0].smc_smce = 0;
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SMC2
- cp->cp_simode &= ~(0xe0000000 >> 1);
- cp->cp_simode |= (0x20000000 >> 1); /* brg2 */
- clrbits32(bcsr_io,BCSR1_RS232EN_2);
- cp->cp_smc[1].smc_smcm |= (SMCM_RX | SMCM_TX);
- cp->cp_smc[1].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-#else
- setbits32(bcsr_io,BCSR1_RS232EN_2);
- cp->cp_smc[1].smc_smcmr = 0;
- cp->cp_smc[1].smc_smce = 0;
-#endif
- iounmap(bcsr_io);
-
-#ifdef CONFIG_FS_ENET
- /* use MDC for MII (common) */
- setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
- clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
- bcsr_io = ioremap(BCSR5, sizeof(unsigned long));
- clrbits32(bcsr_io,BCSR5_MII1_EN);
- clrbits32(bcsr_io,BCSR5_MII1_RST);
-#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
- clrbits32(bcsr_io,BCSR5_MII2_EN);
- clrbits32(bcsr_io,BCSR5_MII2_RST);
-#endif
- iounmap(bcsr_io);
-#endif
-}
-
-static void setup_fec1_ioports(struct fs_platform_info* pdata)
-{
- immap_t *immap = (immap_t *) IMAP_ADDR;
-
- /* configure FEC1 pins */
- setbits16(&immap->im_ioport.iop_papar, 0xf830);
- setbits16(&immap->im_ioport.iop_padir, 0x0830);
- clrbits16(&immap->im_ioport.iop_padir, 0xf000);
- setbits32(&immap->im_cpm.cp_pbpar, 0x00001001);
-
- clrbits32(&immap->im_cpm.cp_pbdir, 0x00001001);
- setbits16(&immap->im_ioport.iop_pcpar, 0x000c);
- clrbits16(&immap->im_ioport.iop_pcdir, 0x000c);
- setbits32(&immap->im_cpm.cp_pepar, 0x00000003);
-
- setbits32(&immap->im_cpm.cp_pedir, 0x00000003);
- clrbits32(&immap->im_cpm.cp_peso, 0x00000003);
- clrbits32(&immap->im_cpm.cp_cptr, 0x00000100);
-}
-
-static void setup_fec2_ioports(struct fs_platform_info* pdata)
-{
- immap_t *immap = (immap_t *) IMAP_ADDR;
-
- /* configure FEC2 pins */
- setbits32(&immap->im_cpm.cp_pepar, 0x0003fffc);
- setbits32(&immap->im_cpm.cp_pedir, 0x0003fffc);
- clrbits32(&immap->im_cpm.cp_peso, 0x000087fc);
- setbits32(&immap->im_cpm.cp_peso, 0x00037800);
- clrbits32(&immap->im_cpm.cp_cptr, 0x00000080);
-}
-
-static void setup_scc3_ioports(struct fs_platform_info* pdata)
-{
- immap_t *immap = (immap_t *) IMAP_ADDR;
- unsigned *bcsr_io;
-
- bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
-
- if (bcsr_io == NULL) {
- printk(KERN_CRIT "Could not remap BCSR\n");
- return;
- }
-
- /* Enable the PHY.
- */
- clrbits32(bcsr_io+4, BCSR4_ETH10_RST);
- udelay(1000);
- setbits32(bcsr_io+4, BCSR4_ETH10_RST);
- /* Configure port A pins for Txd and Rxd.
- */
- setbits16(&immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
- clrbits16(&immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
-
- /* Configure port C pins to enable CLSN and RENA.
- */
- clrbits16(&immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
- clrbits16(&immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
- setbits16(&immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
-
- /* Configure port E for TCLK and RCLK.
- */
- setbits32(&immap->im_cpm.cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
- clrbits32(&immap->im_cpm.cp_pepar, PE_ENET_TENA);
- clrbits32(&immap->im_cpm.cp_pedir,
- PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
- clrbits32(&immap->im_cpm.cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
- setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
-
- /* Configure Serial Interface clock routing.
- * First, clear all SCC bits to zero, then set the ones we want.
- */
- clrbits32(&immap->im_cpm.cp_sicr, SICR_ENET_MASK);
- setbits32(&immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
-
- /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
- */
- immap->im_cpm.cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
- * by H/W setting after reset. SCC ethernet controller support only half duplex.
- * This discrepancy of modes causes a lot of carrier lost errors.
- */
-
- /* In the original SCC enet driver the following code is placed at
- the end of the initialization */
- setbits32(&immap->im_cpm.cp_pepar, PE_ENET_TENA);
- clrbits32(&immap->im_cpm.cp_pedir, PE_ENET_TENA);
- setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
-
- setbits32(bcsr_io+4, BCSR1_ETHEN);
- iounmap(bcsr_io);
-}
-
-static int mac_count = 0;
-
-static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
-{
- struct fs_platform_info *fpi;
- bd_t *bd = (bd_t *) __res;
- char *e;
- int i;
-
- if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) {
- printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
- return;
- }
-
- fpi = &mpc8xx_enet_pdata[fs_no];
-
- switch (fs_no) {
- case fsid_fec1:
- fpi->init_ioports = &setup_fec1_ioports;
- break;
- case fsid_fec2:
- fpi->init_ioports = &setup_fec2_ioports;
- break;
- case fsid_scc3:
- fpi->init_ioports = &setup_scc3_ioports;
- break;
- default:
- printk(KERN_WARNING "Device %s is not supported!\n", pdev->name);
- return;
- }
-
- pdev->dev.platform_data = fpi;
- fpi->fs_no = fs_no;
-
- e = (unsigned char *)&bd->bi_enetaddr;
- for (i = 0; i < 6; i++)
- fpi->macaddr[i] = *e++;
-
- fpi->macaddr[5] += mac_count++;
-
-}
-
-static void mpc885ads_fixup_fec_enet_pdata(struct platform_device *pdev,
- int idx)
-{
- /* This is for FEC devices only */
- if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec")))
- return;
- mpc885ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
-}
-
-static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device *pdev,
- int idx)
-{
- /* This is for SCC devices only */
- if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc")))
- return;
-
- mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
-}
-
-static void setup_smc1_ioports(struct fs_uart_platform_info* pdata)
-{
- immap_t *immap = (immap_t *) IMAP_ADDR;
- unsigned *bcsr_io;
- unsigned int iobits = 0x000000c0;
-
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-
- if (bcsr_io == NULL) {
- printk(KERN_CRIT "Could not remap BCSR1\n");
- return;
- }
- clrbits32(bcsr_io,BCSR1_RS232EN_1);
- iounmap(bcsr_io);
-
- setbits32(&immap->im_cpm.cp_pbpar, iobits);
- clrbits32(&immap->im_cpm.cp_pbdir, iobits);
- clrbits16(&immap->im_cpm.cp_pbodr, iobits);
-}
-
-static void setup_smc2_ioports(struct fs_uart_platform_info* pdata)
-{
- immap_t *immap = (immap_t *) IMAP_ADDR;
- unsigned *bcsr_io;
- unsigned int iobits = 0x00000c00;
-
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-
- if (bcsr_io == NULL) {
- printk(KERN_CRIT "Could not remap BCSR1\n");
- return;
- }
- clrbits32(bcsr_io,BCSR1_RS232EN_2);
- iounmap(bcsr_io);
-
-#ifndef CONFIG_SERIAL_CPM_ALT_SMC2
- setbits32(&immap->im_cpm.cp_pbpar, iobits);
- clrbits32(&immap->im_cpm.cp_pbdir, iobits);
- clrbits16(&immap->im_cpm.cp_pbodr, iobits);
-#else
- setbits16(&immap->im_ioport.iop_papar, iobits);
- clrbits16(&immap->im_ioport.iop_padir, iobits);
- clrbits16(&immap->im_ioport.iop_paodr, iobits);
-#endif
-}
-
-static void __init mpc885ads_fixup_uart_pdata(struct platform_device *pdev,
- int idx)
-{
- bd_t *bd = (bd_t *) __res;
- struct fs_uart_platform_info *pinfo;
- int num = ARRAY_SIZE(mpc885_uart_pdata);
-
- int id = fs_uart_id_smc2fsid(idx);
-
- /* no need to alter anything if console */
- if ((id < num) && (!pdev->dev.platform_data)) {
- pinfo = &mpc885_uart_pdata[id];
- pinfo->uart_clk = bd->bi_intfreq;
- pdev->dev.platform_data = pinfo;
- }
-}
-
-
-static int mpc885ads_platform_notify(struct device *dev)
-{
-
- static const struct platform_notify_dev_map dev_map[] = {
- {
- .bus_id = "fsl-cpm-fec",
- .rtn = mpc885ads_fixup_fec_enet_pdata,
- },
- {
- .bus_id = "fsl-cpm-scc",
- .rtn = mpc885ads_fixup_scc_enet_pdata,
- },
- {
- .bus_id = "fsl-cpm-smc:uart",
- .rtn = mpc885ads_fixup_uart_pdata
- },
- {
- .bus_id = NULL
- }
- };
-
- platform_notify_map(dev_map,dev);
-
- return 0;
-}
-
-int __init mpc885ads_init(void)
-{
- struct fs_mii_fec_platform_info* fmpi;
- bd_t *bd = (bd_t *) __res;
-
- printk(KERN_NOTICE "mpc885ads: Init\n");
-
- platform_notify = mpc885ads_platform_notify;
-
- ppc_sys_device_initfunc();
- ppc_sys_device_disable_all();
-
- ppc_sys_device_enable(MPC8xx_CPM_FEC1);
-
- ppc_sys_device_enable(MPC8xx_MDIO_FEC);
- fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data =
- &mpc8xx_mdio_fec_pdata;
-
- fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1;
-
- /* No PHY interrupt line here */
- fmpi->irq[0xf] = SIU_IRQ7;
-
-#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
- ppc_sys_device_enable(MPC8xx_CPM_SCC3);
-
-#endif
-#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
- ppc_sys_device_enable(MPC8xx_CPM_FEC2);
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SMC1
- ppc_sys_device_enable(MPC8xx_CPM_SMC1);
- ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART);
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SMC2
- ppc_sys_device_enable(MPC8xx_CPM_SMC2);
- ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART);
-#endif
- return 0;
-}
-
-arch_initcall(mpc885ads_init);
-
-/*
- To prevent confusion, console selection is gross:
- by 0 assumed SMC1 and by 1 assumed SMC2
- */
-struct platform_device* early_uart_get_pdev(int index)
-{
- bd_t *bd = (bd_t *) __res;
- struct fs_uart_platform_info *pinfo;
-
- struct platform_device* pdev = NULL;
- if(index) { /*assume SMC2 here*/
- pdev = &ppc_sys_platform_devices[MPC8xx_CPM_SMC2];
- pinfo = &mpc885_uart_pdata[1];
- } else { /*over SMC1*/
- pdev = &ppc_sys_platform_devices[MPC8xx_CPM_SMC1];
- pinfo = &mpc885_uart_pdata[0];
- }
-
- pinfo->uart_clk = bd->bi_intfreq;
- pdev->dev.platform_data = pinfo;
- ppc_sys_fixup_mem_resource(pdev, IMAP_ADDR);
- return NULL;
-}
-
diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c
deleted file mode 100644
index 7fc2e02f5246..000000000000
--- a/arch/ppc/platforms/pq2ads.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * PQ2ADS platform support
- *
- * Author: Kumar Gala <galak@kernel.crashing.org>
- * Derived from: est8260_setup.c by Allen Curtis
- *
- * Copyright 2004 Freescale Semiconductor, Inc.
- *
- * 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/init.h>
-
-#include <asm/io.h>
-#include <asm/mpc8260.h>
-#include <asm/cpm2.h>
-#include <asm/immap_cpm2.h>
-
-void __init
-m82xx_board_setup(void)
-{
- cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
- u32 *bcsr = ioremap(BCSR_ADDR+4, sizeof(u32));
-
- /* Enable the 2nd UART port */
- clrbits32(bcsr, BCSR1_RS232_EN2);
-
-#ifdef CONFIG_SERIAL_CPM_SCC1
- clrbits32((u32*)&immap->im_scc[0].scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
- clrbits32((u32*)&immap->im_scc[0].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SCC2
- clrbits32((u32*)&immap->im_scc[1].scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
- clrbits32((u32*)&immap->im_scc[1].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SCC3
- clrbits32((u32*)&immap->im_scc[2].scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
- clrbits32((u32*)&immap->im_scc[2].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-
-#ifdef CONFIG_SERIAL_CPM_SCC4
- clrbits32((u32*)&immap->im_scc[3].scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
- clrbits32((u32*)&immap->im_scc[3].scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
-
- iounmap(bcsr);
- iounmap(immap);
-}
diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h
deleted file mode 100644
index 2b287f4e0ca3..000000000000
--- a/arch/ppc/platforms/pq2ads.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * A collection of structures, addresses, and values associated with
- * the Motorola MPC8260ADS/MPC8266ADS-PCI boards.
- * Copied from the RPX-Classic and SBS8260 stuff.
- *
- * Copyright (c) 2001 Dan Malek (dan@mvista.com)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_ADS8260_DEFS
-#define __MACH_ADS8260_DEFS
-
-
-#include <asm/ppcboot.h>
-
-#if defined(CONFIG_ADS8272)
-#define BOARD_CHIP_NAME "8272"
-#endif
-
-/* Memory map is configured by the PROM startup.
- * We just map a few things we need. The CSR is actually 4 byte-wide
- * registers that can be accessed as 8-, 16-, or 32-bit values.
- */
-#define CPM_MAP_ADDR ((uint)0xf0000000)
-#define BCSR_ADDR ((uint)0xf4500000)
-#define BCSR_SIZE ((uint)(32 * 1024))
-
-#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
-
-/* For our show_cpuinfo hooks. */
-#define CPUINFO_VENDOR "Motorola"
-#define CPUINFO_MACHINE "PQ2 ADS PowerPC"
-
-/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
- * only on word boundaries.
- * Not all are used (yet), or are interesting to us (yet).
- */
-
-/* Things of interest in the CSR.
-*/
-#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */
-#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */
-#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable */
-#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */
-#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 == enable */
-#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 == enable */
-#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable */
-#define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */
-
-#define PHY_INTERRUPT SIU_INT_IRQ7
-
-#ifdef CONFIG_PCI
-/* PCI interrupt controller */
-#define PCI_INT_STAT_REG 0xF8200000
-#define PCI_INT_MASK_REG 0xF8200004
-#define PIRQA (NR_CPM_INTS + 0)
-#define PIRQB (NR_CPM_INTS + 1)
-#define PIRQC (NR_CPM_INTS + 2)
-#define PIRQD (NR_CPM_INTS + 3)
-
-/*
- * PCI memory map definitions for MPC8266ADS-PCI.
- *
- * processor view
- * local address PCI address target
- * 0x80000000-0x9FFFFFFF 0x80000000-0x9FFFFFFF PCI mem with prefetch
- * 0xA0000000-0xBFFFFFFF 0xA0000000-0xBFFFFFFF PCI mem w/o prefetch
- * 0xF4000000-0xF7FFFFFF 0x00000000-0x03FFFFFF PCI IO
- *
- * PCI master view
- * local address PCI address target
- * 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory
- */
-
-/* All the other PCI memory map definitions reside at syslib/m82xx_pci.h
- Here we should redefine what is unique for this board */
-#define M82xx_PCI_SLAVE_MEM_LOCAL 0x00000000 /* Local base */
-#define M82xx_PCI_SLAVE_MEM_BUS 0x00000000 /* PCI base */
-#define M82xx_PCI_SLAVE_MEM_SIZE 0x10000000 /* 256 Mb */
-
-#define M82xx_PCI_SLAVE_SEC_WND_SIZE ~(0x40000000 - 1U) /* 2 x 512Mb */
-#define M82xx_PCI_SLAVE_SEC_WND_BASE 0x80000000 /* PCI Memory base */
-
-#if defined(CONFIG_ADS8272)
-#define PCI_INT_TO_SIU SIU_INT_IRQ2
-#elif defined(CONFIG_PQ2FADS)
-#define PCI_INT_TO_SIU SIU_INT_IRQ6
-#else
-#warning PCI Bridge will be without interrupts support
-#endif
-
-#endif /* CONFIG_PCI */
-
-#endif /* __MACH_ADS8260_DEFS */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/pq2ads_pd.h b/arch/ppc/platforms/pq2ads_pd.h
deleted file mode 100644
index 672483df8079..000000000000
--- a/arch/ppc/platforms/pq2ads_pd.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __PQ2ADS_PD_H
-#define __PQ2ADS_PD_H
-/*
- * arch/ppc/platforms/82xx/pq2ads_pd.h
- *
- * Some defines for MPC82xx board-specific PlatformDevice descriptions
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.mvista.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.
- */
-
-/* FCC1 Clock Source Configuration. These can be redefined in the board specific file.
- Can only choose from CLK9-12 */
-
-#define F1_RXCLK 11
-#define F1_TXCLK 10
-
-/* FCC2 Clock Source Configuration. These can be redefined in the board specific file.
- Can only choose from CLK13-16 */
-#define F2_RXCLK 15
-#define F2_TXCLK 16
-
-/* FCC3 Clock Source Configuration. These can be redefined in the board specific file.
- Can only choose from CLK13-16 */
-#define F3_RXCLK 13
-#define F3_TXCLK 14
-
-#endif
diff --git a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c
index 46588fa94381..b40583724de3 100644
--- a/arch/ppc/syslib/m8260_setup.c
+++ b/arch/ppc/syslib/m8260_setup.c
@@ -175,12 +175,6 @@ m8260_init_IRQ(void)
* in case the boot rom changed something on us.
*/
cpm2_immr->im_intctl.ic_siprr = 0x05309770;
-
-#if defined(CONFIG_PCI) && (defined(CONFIG_ADS8272) || defined(CONFIG_PQ2FADS))
- /* Initialize stuff for the 82xx CPLD IC and install demux */
- pq2pci_init_irq();
-#endif
-
}
/*
diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c
index fe860d52e2e4..657a1c25a2ab 100644
--- a/arch/ppc/syslib/m82xx_pci.c
+++ b/arch/ppc/syslib/m82xx_pci.c
@@ -150,14 +150,6 @@ pq2pci_init_irq(void)
{
int irq;
volatile cpm2_map_t *immap = cpm2_immr;
-#if defined CONFIG_ADS8272
- /* configure chip select for PCI interrupt controller */
- immap->im_memctl.memc_br3 = PCI_INT_STAT_REG | 0x00001801;
- immap->im_memctl.memc_or3 = 0xffff8010;
-#elif defined CONFIG_PQ2FADS
- immap->im_memctl.memc_br8 = PCI_INT_STAT_REG | 0x00001801;
- immap->im_memctl.memc_or8 = 0xffff8010;
-#endif
for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++)
irq_desc[irq].chip = &pq2pci_ic;
@@ -222,26 +214,6 @@ pq2ads_setup_pci(struct pci_controller *hose)
immap->im_memctl.memc_pcibr1 = M82xx_PCI_SEC_WND_BASE | PCIBR_ENABLE;
#endif
-#if defined CONFIG_ADS8272
- immap->im_siu_conf.siu_82xx.sc_siumcr =
- (immap->im_siu_conf.siu_82xx.sc_siumcr &
- ~(SIUMCR_BBD | SIUMCR_ESE | SIUMCR_PBSE |
- SIUMCR_CDIS | SIUMCR_DPPC11 | SIUMCR_L2CPC11 |
- SIUMCR_LBPC11 | SIUMCR_APPC11 |
- SIUMCR_CS10PC11 | SIUMCR_BCTLC11 | SIUMCR_MMR11)) |
- SIUMCR_DPPC11 | SIUMCR_L2CPC01 | SIUMCR_LBPC00 |
- SIUMCR_APPC10 | SIUMCR_CS10PC00 |
- SIUMCR_BCTLC00 | SIUMCR_MMR11 ;
-
-#elif defined CONFIG_PQ2FADS
- /*
- * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
- * and local bus for PCI (SIUMCR [LBPC]).
- */
- immap->im_siu_conf.siu_82xx.sc_siumcr = (immap->im_siu_conf.siu_82xx.sc_siumcr &
- ~(SIUMCR_L2CPC11 | SIUMCR_LBPC11 | SIUMCR_CS10PC11 | SIUMCR_APPC11) |
- SIUMCR_BBD | SIUMCR_LBPC01 | SIUMCR_DPPC11 | SIUMCR_APPC10);
-#endif
/* Enable PCI */
immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
@@ -284,12 +256,6 @@ pq2ads_setup_pci(struct pci_controller *hose)
immap->im_pci.pci_pibar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_BUS >> PITA_ADDR_SHIFT);
immap->im_pci.pci_pitar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_LOCAL>> PITA_ADDR_SHIFT);
-#if defined CONFIG_ADS8272
- /* PCI int highest prio */
- immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x01236745;
-#elif defined CONFIG_PQ2FADS
- immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
-#endif
/* park bus on PCI */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
@@ -320,10 +286,6 @@ void __init pq2_find_bridges(void)
hose->bus_offset = 0;
hose->last_busno = 0xff;
-#ifdef CONFIG_ADS8272
- hose->set_cfg_type = 1;
-#endif
-
setup_m8260_indirect_pci(hose,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 19749e9bcf91..18da720fc1b0 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -141,16 +141,6 @@ m8xx_setup_arch(void)
#endif
#endif
-#if defined (CONFIG_MPC86XADS) || defined (CONFIG_MPC885ADS)
-#if defined(CONFIG_MTD_PHYSMAP)
- physmap_configure(binfo->bi_flashstart, binfo->bi_flashsize,
- MPC8xxADS_BANK_WIDTH, NULL);
-#ifdef CONFIG_MTD_PARTITIONS
- physmap_set_partitions(mpc8xxads_partitions, mpc8xxads_part_num);
-#endif /* CONFIG_MTD_PARTITIONS */
-#endif /* CONFIG_MTD_PHYSMAP */
-#endif
-
board_init();
}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index f6a68e178fc5..8f5f02160ffc 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -62,6 +62,10 @@ config GENERIC_LOCKBREAK
default y
depends on SMP && PREEMPT
+config PGSTE
+ bool
+ default y if KVM
+
mainmenu "Linux Kernel Configuration"
config S390
@@ -69,6 +73,7 @@ config S390
select HAVE_OPROFILE
select HAVE_KPROBES
select HAVE_KRETPROBES
+ select HAVE_KVM if 64BIT
source "init/Kconfig"
@@ -515,6 +520,13 @@ config ZFCPDUMP
Select this option if you want to build an zfcpdump enabled kernel.
Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
+config S390_GUEST
+bool "s390 guest support (EXPERIMENTAL)"
+ depends on 64BIT && EXPERIMENTAL
+ select VIRTIO
+ select VIRTIO_RING
+ help
+ Select this option if you want to run the kernel under s390 linux
endmenu
source "net/Kconfig"
@@ -536,3 +548,5 @@ source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
+
+source "arch/s390/kvm/Kconfig"
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index f708be367b03..792a4e7743ce 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -87,7 +87,7 @@ LDFLAGS_vmlinux := -e start
head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
- arch/s390/appldata/ arch/s390/hypfs/
+ arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
libs-y += arch/s390/lib/
drivers-y += drivers/s390/
drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 540a67f979b6..68ec4083bf73 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -144,6 +144,10 @@ static noinline __init void detect_machine_type(void)
/* Running on a P/390 ? */
if (cpuinfo->cpu_id.machine == 0x7490)
machine_flags |= 4;
+
+ /* Running under KVM ? */
+ if (cpuinfo->cpu_id.version == 0xfe)
+ machine_flags |= 64;
}
#ifdef CONFIG_64BIT
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 7141147e6b63..a9d18aafa5f4 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -316,7 +316,11 @@ static int __init early_parse_ipldelay(char *p)
early_param("ipldelay", early_parse_ipldelay);
#ifdef CONFIG_S390_SWITCH_AMODE
+#ifdef CONFIG_PGSTE
+unsigned int switch_amode = 1;
+#else
unsigned int switch_amode = 0;
+#endif
EXPORT_SYMBOL_GPL(switch_amode);
static void set_amode_and_uaccess(unsigned long user_amode,
@@ -797,9 +801,13 @@ setup_arch(char **cmdline_p)
"This machine has an IEEE fpu\n" :
"This machine has no IEEE fpu\n");
#else /* CONFIG_64BIT */
- printk((MACHINE_IS_VM) ?
- "We are running under VM (64 bit mode)\n" :
- "We are running native (64 bit mode)\n");
+ if (MACHINE_IS_VM)
+ printk("We are running under VM (64 bit mode)\n");
+ else if (MACHINE_IS_KVM) {
+ printk("We are running under KVM (64 bit mode)\n");
+ add_preferred_console("ttyS", 1, NULL);
+ } else
+ printk("We are running native (64 bit mode)\n");
#endif /* CONFIG_64BIT */
/* Save unparsed command line copy for /proc/cmdline */
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index c5f05b3fb2c3..ca90ee3f930e 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -110,6 +110,7 @@ void account_system_vtime(struct task_struct *tsk)
S390_lowcore.steal_clock -= cputime << 12;
account_system_time(tsk, 0, cputime);
}
+EXPORT_SYMBOL_GPL(account_system_vtime);
static inline void set_vtimer(__u64 expires)
{
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
new file mode 100644
index 000000000000..1761b74d639b
--- /dev/null
+++ b/arch/s390/kvm/Kconfig
@@ -0,0 +1,46 @@
+#
+# KVM configuration
+#
+config HAVE_KVM
+ bool
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ default y
+ ---help---
+ Say Y here to get to see options for using your Linux host to run other
+ operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ tristate "Kernel-based Virtual Machine (KVM) support"
+ depends on HAVE_KVM && EXPERIMENTAL
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ select S390_SWITCH_AMODE
+ select PREEMPT
+ ---help---
+ Support hosting paravirtualized guest machines using the SIE
+ virtualization capability on the mainframe. This should work
+ on any 64bit machine.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ To compile this as a module, choose M here: the module
+ will be called kvm.
+
+ If unsure, say N.
+
+config KVM_TRACE
+ bool
+
+# OK, it's a little counter-intuitive to do this, but it puts it neatly under
+# the virtualization menu.
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
new file mode 100644
index 000000000000..e5221ec0b8e3
--- /dev/null
+++ b/arch/s390/kvm/Makefile
@@ -0,0 +1,14 @@
+# Makefile for kernel virtual machines on s390
+#
+# Copyright IBM Corp. 2008
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (version 2 only)
+# as published by the Free Software Foundation.
+
+common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
+
+EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm
+
+kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o priv.o sigp.o diag.o
+obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
new file mode 100644
index 000000000000..f639a152869f
--- /dev/null
+++ b/arch/s390/kvm/diag.c
@@ -0,0 +1,67 @@
+/*
+ * diag.c - handling diagnose instructions
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include "kvm-s390.h"
+
+static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
+{
+ VCPU_EVENT(vcpu, 5, "%s", "diag time slice end");
+ vcpu->stat.diagnose_44++;
+ vcpu_put(vcpu);
+ schedule();
+ vcpu_load(vcpu);
+ return 0;
+}
+
+static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
+{
+ unsigned int reg = vcpu->arch.sie_block->ipa & 0xf;
+ unsigned long subcode = vcpu->arch.guest_gprs[reg] & 0xffff;
+
+ VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode);
+ switch (subcode) {
+ case 3:
+ vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
+ break;
+ case 4:
+ vcpu->run->s390_reset_flags = 0;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+ vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM;
+ vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL;
+ vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT;
+ vcpu->run->exit_reason = KVM_EXIT_S390_RESET;
+ VCPU_EVENT(vcpu, 3, "requesting userspace resets %lx",
+ vcpu->run->s390_reset_flags);
+ return -EREMOTE;
+}
+
+int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
+{
+ int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
+
+ switch (code) {
+ case 0x44:
+ return __diag_time_slice_end(vcpu);
+ case 0x308:
+ return __diag_ipl_functions(vcpu);
+ default:
+ return -ENOTSUPP;
+ }
+}
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h
new file mode 100644
index 000000000000..4e0633c413f3
--- /dev/null
+++ b/arch/s390/kvm/gaccess.h
@@ -0,0 +1,274 @@
+/*
+ * gaccess.h - access guest memory
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ */
+
+#ifndef __KVM_S390_GACCESS_H
+#define __KVM_S390_GACCESS_H
+
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+#include <asm/uaccess.h>
+
+static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
+ u64 guestaddr)
+{
+ u64 prefix = vcpu->arch.sie_block->prefix;
+ u64 origin = vcpu->kvm->arch.guest_origin;
+ u64 memsize = vcpu->kvm->arch.guest_memsize;
+
+ if (guestaddr < 2 * PAGE_SIZE)
+ guestaddr += prefix;
+ else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE))
+ guestaddr -= prefix;
+
+ if (guestaddr > memsize)
+ return (void __user __force *) ERR_PTR(-EFAULT);
+
+ guestaddr += origin;
+
+ return (void __user *) guestaddr;
+}
+
+static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u64 *result)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ BUG_ON(guestaddr & 7);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return get_user(*result, (u64 __user *) uptr);
+}
+
+static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u32 *result)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ BUG_ON(guestaddr & 3);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return get_user(*result, (u32 __user *) uptr);
+}
+
+static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u16 *result)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ BUG_ON(guestaddr & 1);
+
+ if (IS_ERR(uptr))
+ return PTR_ERR(uptr);
+
+ return get_user(*result, (u16 __user *) uptr);
+}
+
+static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u8 *result)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return get_user(*result, (u8 __user *) uptr);
+}
+
+static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u64 value)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ BUG_ON(guestaddr & 7);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return put_user(value, (u64 __user *) uptr);
+}
+
+static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u32 value)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ BUG_ON(guestaddr & 3);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return put_user(value, (u32 __user *) uptr);
+}
+
+static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u16 value)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ BUG_ON(guestaddr & 1);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return put_user(value, (u16 __user *) uptr);
+}
+
+static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
+ u8 value)
+{
+ void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
+
+ if (IS_ERR((void __force *) uptr))
+ return PTR_ERR((void __force *) uptr);
+
+ return put_user(value, (u8 __user *) uptr);
+}
+
+
+static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest,
+ const void *from, unsigned long n)
+{
+ int rc;
+ unsigned long i;
+ const u8 *data = from;
+
+ for (i = 0; i < n; i++) {
+ rc = put_guest_u8(vcpu, guestdest++, *(data++));
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static inline int copy_to_guest(struct kvm_vcpu *vcpu, u64 guestdest,
+ const void *from, unsigned long n)
+{
+ u64 prefix = vcpu->arch.sie_block->prefix;
+ u64 origin = vcpu->kvm->arch.guest_origin;
+ u64 memsize = vcpu->kvm->arch.guest_memsize;
+
+ if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
+ goto slowpath;
+
+ if ((guestdest < prefix) && (guestdest + n > prefix))
+ goto slowpath;
+
+ if ((guestdest < prefix + 2 * PAGE_SIZE)
+ && (guestdest + n > prefix + 2 * PAGE_SIZE))
+ goto slowpath;
+
+ if (guestdest < 2 * PAGE_SIZE)
+ guestdest += prefix;
+ else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE))
+ guestdest -= prefix;
+
+ if (guestdest + n > memsize)
+ return -EFAULT;
+
+ if (guestdest + n < guestdest)
+ return -EFAULT;
+
+ guestdest += origin;
+
+ return copy_to_user((void __user *) guestdest, from, n);
+slowpath:
+ return __copy_to_guest_slow(vcpu, guestdest, from, n);
+}
+
+static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
+ u64 guestsrc, unsigned long n)
+{
+ int rc;
+ unsigned long i;
+ u8 *data = to;
+
+ for (i = 0; i < n; i++) {
+ rc = get_guest_u8(vcpu, guestsrc++, data++);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
+ u64 guestsrc, unsigned long n)
+{
+ u64 prefix = vcpu->arch.sie_block->prefix;
+ u64 origin = vcpu->kvm->arch.guest_origin;
+ u64 memsize = vcpu->kvm->arch.guest_memsize;
+
+ if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
+ goto slowpath;
+
+ if ((guestsrc < prefix) && (guestsrc + n > prefix))
+ goto slowpath;
+
+ if ((guestsrc < prefix + 2 * PAGE_SIZE)
+ && (guestsrc + n > prefix + 2 * PAGE_SIZE))
+ goto slowpath;
+
+ if (guestsrc < 2 * PAGE_SIZE)
+ guestsrc += prefix;
+ else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE))
+ guestsrc -= prefix;
+
+ if (guestsrc + n > memsize)
+ return -EFAULT;
+
+ if (guestsrc + n < guestsrc)
+ return -EFAULT;
+
+ guestsrc += origin;
+
+ return copy_from_user(to, (void __user *) guestsrc, n);
+slowpath:
+ return __copy_from_guest_slow(vcpu, to, guestsrc, n);
+}
+
+static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest,
+ const void *from, unsigned long n)
+{
+ u64 origin = vcpu->kvm->arch.guest_origin;
+ u64 memsize = vcpu->kvm->arch.guest_memsize;
+
+ if (guestdest + n > memsize)
+ return -EFAULT;
+
+ if (guestdest + n < guestdest)
+ return -EFAULT;
+
+ guestdest += origin;
+
+ return copy_to_user((void __user *) guestdest, from, n);
+}
+
+static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
+ u64 guestsrc, unsigned long n)
+{
+ u64 origin = vcpu->kvm->arch.guest_origin;
+ u64 memsize = vcpu->kvm->arch.guest_memsize;
+
+ if (guestsrc + n > memsize)
+ return -EFAULT;
+
+ if (guestsrc + n < guestsrc)
+ return -EFAULT;
+
+ guestsrc += origin;
+
+ return copy_from_user(to, (void __user *) guestsrc, n);
+}
+#endif
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
new file mode 100644
index 000000000000..349581a26103
--- /dev/null
+++ b/arch/s390/kvm/intercept.c
@@ -0,0 +1,216 @@
+/*
+ * intercept.c - in-kernel handling for sie intercepts
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/errno.h>
+#include <linux/pagemap.h>
+
+#include <asm/kvm_host.h>
+
+#include "kvm-s390.h"
+#include "gaccess.h"
+
+static int handle_lctg(struct kvm_vcpu *vcpu)
+{
+ int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+ int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) +
+ ((vcpu->arch.sie_block->ipb & 0xff00) << 4);
+ u64 useraddr;
+ int reg, rc;
+
+ vcpu->stat.instruction_lctg++;
+ if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f)
+ return -ENOTSUPP;
+
+ useraddr = disp2;
+ if (base2)
+ useraddr += vcpu->arch.guest_gprs[base2];
+
+ reg = reg1;
+
+ VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
+ disp2);
+
+ do {
+ rc = get_guest_u64(vcpu, useraddr,
+ &vcpu->arch.sie_block->gcr[reg]);
+ if (rc == -EFAULT) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ break;
+ }
+ useraddr += 8;
+ if (reg == reg3)
+ break;
+ reg = (reg + 1) % 16;
+ } while (1);
+ return 0;
+}
+
+static int handle_lctl(struct kvm_vcpu *vcpu)
+{
+ int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+ int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u64 useraddr;
+ u32 val = 0;
+ int reg, rc;
+
+ vcpu->stat.instruction_lctl++;
+
+ useraddr = disp2;
+ if (base2)
+ useraddr += vcpu->arch.guest_gprs[base2];
+
+ VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
+ disp2);
+
+ reg = reg1;
+ do {
+ rc = get_guest_u32(vcpu, useraddr, &val);
+ if (rc == -EFAULT) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ break;
+ }
+ vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul;
+ vcpu->arch.sie_block->gcr[reg] |= val;
+ useraddr += 4;
+ if (reg == reg3)
+ break;
+ reg = (reg + 1) % 16;
+ } while (1);
+ return 0;
+}
+
+static intercept_handler_t instruction_handlers[256] = {
+ [0x83] = kvm_s390_handle_diag,
+ [0xae] = kvm_s390_handle_sigp,
+ [0xb2] = kvm_s390_handle_priv,
+ [0xb7] = handle_lctl,
+ [0xeb] = handle_lctg,
+};
+
+static int handle_noop(struct kvm_vcpu *vcpu)
+{
+ switch (vcpu->arch.sie_block->icptcode) {
+ case 0x10:
+ vcpu->stat.exit_external_request++;
+ break;
+ case 0x14:
+ vcpu->stat.exit_external_interrupt++;
+ break;
+ default:
+ break; /* nothing */
+ }
+ return 0;
+}
+
+static int handle_stop(struct kvm_vcpu *vcpu)
+{
+ int rc;
+
+ vcpu->stat.exit_stop_request++;
+ atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+ spin_lock_bh(&vcpu->arch.local_int.lock);
+ if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
+ vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
+ rc = __kvm_s390_vcpu_store_status(vcpu,
+ KVM_S390_STORE_STATUS_NOADDR);
+ if (rc >= 0)
+ rc = -ENOTSUPP;
+ }
+
+ if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
+ vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP;
+ VCPU_EVENT(vcpu, 3, "%s", "cpu stopped");
+ rc = -ENOTSUPP;
+ } else
+ rc = 0;
+ spin_unlock_bh(&vcpu->arch.local_int.lock);
+ return rc;
+}
+
+static int handle_validity(struct kvm_vcpu *vcpu)
+{
+ int viwhy = vcpu->arch.sie_block->ipb >> 16;
+ vcpu->stat.exit_validity++;
+ if (viwhy == 0x37) {
+ fault_in_pages_writeable((char __user *)
+ vcpu->kvm->arch.guest_origin +
+ vcpu->arch.sie_block->prefix,
+ PAGE_SIZE);
+ return 0;
+ }
+ VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
+ viwhy);
+ return -ENOTSUPP;
+}
+
+static int handle_instruction(struct kvm_vcpu *vcpu)
+{
+ intercept_handler_t handler;
+
+ vcpu->stat.exit_instruction++;
+ handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8];
+ if (handler)
+ return handler(vcpu);
+ return -ENOTSUPP;
+}
+
+static int handle_prog(struct kvm_vcpu *vcpu)
+{
+ vcpu->stat.exit_program_interruption++;
+ return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
+}
+
+static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
+{
+ int rc, rc2;
+
+ vcpu->stat.exit_instr_and_program++;
+ rc = handle_instruction(vcpu);
+ rc2 = handle_prog(vcpu);
+
+ if (rc == -ENOTSUPP)
+ vcpu->arch.sie_block->icptcode = 0x04;
+ if (rc)
+ return rc;
+ return rc2;
+}
+
+static const intercept_handler_t intercept_funcs[0x48 >> 2] = {
+ [0x00 >> 2] = handle_noop,
+ [0x04 >> 2] = handle_instruction,
+ [0x08 >> 2] = handle_prog,
+ [0x0C >> 2] = handle_instruction_and_prog,
+ [0x10 >> 2] = handle_noop,
+ [0x14 >> 2] = handle_noop,
+ [0x1C >> 2] = kvm_s390_handle_wait,
+ [0x20 >> 2] = handle_validity,
+ [0x28 >> 2] = handle_stop,
+};
+
+int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
+{
+ intercept_handler_t func;
+ u8 code = vcpu->arch.sie_block->icptcode;
+
+ if (code & 3 || code > 0x48)
+ return -ENOTSUPP;
+ func = intercept_funcs[code >> 2];
+ if (func)
+ return func(vcpu);
+ return -ENOTSUPP;
+}
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
new file mode 100644
index 000000000000..fcd1ed8015c1
--- /dev/null
+++ b/arch/s390/kvm/interrupt.c
@@ -0,0 +1,592 @@
+/*
+ * interrupt.c - handling kvm guest interrupts
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ */
+
+#include <asm/lowcore.h>
+#include <asm/uaccess.h>
+#include <linux/kvm_host.h>
+#include "kvm-s390.h"
+#include "gaccess.h"
+
+static int psw_extint_disabled(struct kvm_vcpu *vcpu)
+{
+ return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
+}
+
+static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
+{
+ if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||
+ (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) ||
+ (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT))
+ return 0;
+ return 1;
+}
+
+static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
+ struct interrupt_info *inti)
+{
+ switch (inti->type) {
+ case KVM_S390_INT_EMERGENCY:
+ if (psw_extint_disabled(vcpu))
+ return 0;
+ if (vcpu->arch.sie_block->gcr[0] & 0x4000ul)
+ return 1;
+ return 0;
+ case KVM_S390_INT_SERVICE:
+ if (psw_extint_disabled(vcpu))
+ return 0;
+ if (vcpu->arch.sie_block->gcr[0] & 0x200ul)
+ return 1;
+ return 0;
+ case KVM_S390_INT_VIRTIO:
+ if (psw_extint_disabled(vcpu))
+ return 0;
+ if (vcpu->arch.sie_block->gcr[0] & 0x200ul)
+ return 1;
+ return 0;
+ case KVM_S390_PROGRAM_INT:
+ case KVM_S390_SIGP_STOP:
+ case KVM_S390_SIGP_SET_PREFIX:
+ case KVM_S390_RESTART:
+ return 1;
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+static void __set_cpu_idle(struct kvm_vcpu *vcpu)
+{
+ BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
+ atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
+ set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
+}
+
+static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
+{
+ BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
+ atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
+ clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
+}
+
+static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
+{
+ atomic_clear_mask(CPUSTAT_ECALL_PEND |
+ CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT,
+ &vcpu->arch.sie_block->cpuflags);
+ vcpu->arch.sie_block->lctl = 0x0000;
+}
+
+static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
+{
+ atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags);
+}
+
+static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
+ struct interrupt_info *inti)
+{
+ switch (inti->type) {
+ case KVM_S390_INT_EMERGENCY:
+ case KVM_S390_INT_SERVICE:
+ case KVM_S390_INT_VIRTIO:
+ if (psw_extint_disabled(vcpu))
+ __set_cpuflag(vcpu, CPUSTAT_EXT_INT);
+ else
+ vcpu->arch.sie_block->lctl |= LCTL_CR0;
+ break;
+ case KVM_S390_SIGP_STOP:
+ __set_cpuflag(vcpu, CPUSTAT_STOP_INT);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
+ struct interrupt_info *inti)
+{
+ const unsigned short table[] = { 2, 4, 4, 6 };
+ int rc, exception = 0;
+
+ switch (inti->type) {
+ case KVM_S390_INT_EMERGENCY:
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
+ vcpu->stat.deliver_emergency_signal++;
+ rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+
+ case KVM_S390_INT_SERVICE:
+ VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
+ inti->ext.ext_params);
+ vcpu->stat.deliver_service_signal++;
+ rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params);
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+
+ case KVM_S390_INT_VIRTIO:
+ VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%lx",
+ inti->ext.ext_params, inti->ext.ext_params2);
+ vcpu->stat.deliver_virtio_interrupt++;
+ rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u64(vcpu, __LC_PFAULT_INTPARM,
+ inti->ext.ext_params2);
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+
+ case KVM_S390_SIGP_STOP:
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
+ vcpu->stat.deliver_stop_signal++;
+ __set_intercept_indicator(vcpu, inti);
+ break;
+
+ case KVM_S390_SIGP_SET_PREFIX:
+ VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
+ inti->prefix.address);
+ vcpu->stat.deliver_prefix_signal++;
+ vcpu->arch.sie_block->prefix = inti->prefix.address;
+ vcpu->arch.sie_block->ihcpu = 0xffff;
+ break;
+
+ case KVM_S390_RESTART:
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
+ vcpu->stat.deliver_restart_signal++;
+ rc = copy_to_guest(vcpu, offsetof(struct _lowcore,
+ restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ offsetof(struct _lowcore, restart_psw), sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+
+ case KVM_S390_PROGRAM_INT:
+ VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x",
+ inti->pgm.code,
+ table[vcpu->arch.sie_block->ipa >> 14]);
+ vcpu->stat.deliver_program_int++;
+ rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u16(vcpu, __LC_PGM_ILC,
+ table[vcpu->arch.sie_block->ipa >> 14]);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_PGM_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+
+ default:
+ BUG();
+ }
+
+ if (exception) {
+ VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering"
+ " interrupt");
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ if (inti->type == KVM_S390_PROGRAM_INT) {
+ printk(KERN_WARNING "kvm: recursive program check\n");
+ BUG();
+ }
+ }
+}
+
+static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
+{
+ int rc, exception = 0;
+
+ if (psw_extint_disabled(vcpu))
+ return 0;
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))
+ return 0;
+ rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004);
+ if (rc == -EFAULT)
+ exception = 1;
+ rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ if (exception) {
+ VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" \
+ " ckc interrupt");
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ return 0;
+ }
+
+ return 1;
+}
+
+int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
+{
+ struct local_interrupt *li = &vcpu->arch.local_int;
+ struct float_interrupt *fi = vcpu->arch.local_int.float_int;
+ struct interrupt_info *inti;
+ int rc = 0;
+
+ if (atomic_read(&li->active)) {
+ spin_lock_bh(&li->lock);
+ list_for_each_entry(inti, &li->list, list)
+ if (__interrupt_is_deliverable(vcpu, inti)) {
+ rc = 1;
+ break;
+ }
+ spin_unlock_bh(&li->lock);
+ }
+
+ if ((!rc) && atomic_read(&fi->active)) {
+ spin_lock_bh(&fi->lock);
+ list_for_each_entry(inti, &fi->list, list)
+ if (__interrupt_is_deliverable(vcpu, inti)) {
+ rc = 1;
+ break;
+ }
+ spin_unlock_bh(&fi->lock);
+ }
+
+ if ((!rc) && (vcpu->arch.sie_block->ckc <
+ get_clock() + vcpu->arch.sie_block->epoch)) {
+ if ((!psw_extint_disabled(vcpu)) &&
+ (vcpu->arch.sie_block->gcr[0] & 0x800ul))
+ rc = 1;
+ }
+
+ return rc;
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
+{
+ u64 now, sltime;
+ DECLARE_WAITQUEUE(wait, current);
+
+ vcpu->stat.exit_wait_state++;
+ if (kvm_cpu_has_interrupt(vcpu))
+ return 0;
+
+ if (psw_interrupts_disabled(vcpu)) {
+ VCPU_EVENT(vcpu, 3, "%s", "disabled wait");
+ __unset_cpu_idle(vcpu);
+ return -ENOTSUPP; /* disabled wait */
+ }
+
+ if (psw_extint_disabled(vcpu) ||
+ (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) {
+ VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer");
+ goto no_timer;
+ }
+
+ now = get_clock() + vcpu->arch.sie_block->epoch;
+ if (vcpu->arch.sie_block->ckc < now) {
+ __unset_cpu_idle(vcpu);
+ return 0;
+ }
+
+ sltime = (vcpu->arch.sie_block->ckc - now) / (0xf4240000ul / HZ) + 1;
+
+ vcpu->arch.ckc_timer.expires = jiffies + sltime;
+
+ add_timer(&vcpu->arch.ckc_timer);
+ VCPU_EVENT(vcpu, 5, "enabled wait timer:%lx jiffies", sltime);
+no_timer:
+ spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
+ spin_lock_bh(&vcpu->arch.local_int.lock);
+ __set_cpu_idle(vcpu);
+ vcpu->arch.local_int.timer_due = 0;
+ add_wait_queue(&vcpu->arch.local_int.wq, &wait);
+ while (list_empty(&vcpu->arch.local_int.list) &&
+ list_empty(&vcpu->arch.local_int.float_int->list) &&
+ (!vcpu->arch.local_int.timer_due) &&
+ !signal_pending(current)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_bh(&vcpu->arch.local_int.lock);
+ spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
+ vcpu_put(vcpu);
+ schedule();
+ vcpu_load(vcpu);
+ spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
+ spin_lock_bh(&vcpu->arch.local_int.lock);
+ }
+ __unset_cpu_idle(vcpu);
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcpu->wq, &wait);
+ spin_unlock_bh(&vcpu->arch.local_int.lock);
+ spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
+ del_timer(&vcpu->arch.ckc_timer);
+ return 0;
+}
+
+void kvm_s390_idle_wakeup(unsigned long data)
+{
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+
+ spin_lock_bh(&vcpu->arch.local_int.lock);
+ vcpu->arch.local_int.timer_due = 1;
+ if (waitqueue_active(&vcpu->arch.local_int.wq))
+ wake_up_interruptible(&vcpu->arch.local_int.wq);
+ spin_unlock_bh(&vcpu->arch.local_int.lock);
+}
+
+
+void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
+{
+ struct local_interrupt *li = &vcpu->arch.local_int;
+ struct float_interrupt *fi = vcpu->arch.local_int.float_int;
+ struct interrupt_info *n, *inti = NULL;
+ int deliver;
+
+ __reset_intercept_indicators(vcpu);
+ if (atomic_read(&li->active)) {
+ do {
+ deliver = 0;
+ spin_lock_bh(&li->lock);
+ list_for_each_entry_safe(inti, n, &li->list, list) {
+ if (__interrupt_is_deliverable(vcpu, inti)) {
+ list_del(&inti->list);
+ deliver = 1;
+ break;
+ }
+ __set_intercept_indicator(vcpu, inti);
+ }
+ if (list_empty(&li->list))
+ atomic_set(&li->active, 0);
+ spin_unlock_bh(&li->lock);
+ if (deliver) {
+ __do_deliver_interrupt(vcpu, inti);
+ kfree(inti);
+ }
+ } while (deliver);
+ }
+
+ if ((vcpu->arch.sie_block->ckc <
+ get_clock() + vcpu->arch.sie_block->epoch))
+ __try_deliver_ckc_interrupt(vcpu);
+
+ if (atomic_read(&fi->active)) {
+ do {
+ deliver = 0;
+ spin_lock_bh(&fi->lock);
+ list_for_each_entry_safe(inti, n, &fi->list, list) {
+ if (__interrupt_is_deliverable(vcpu, inti)) {
+ list_del(&inti->list);
+ deliver = 1;
+ break;
+ }
+ __set_intercept_indicator(vcpu, inti);
+ }
+ if (list_empty(&fi->list))
+ atomic_set(&fi->active, 0);
+ spin_unlock_bh(&fi->lock);
+ if (deliver) {
+ __do_deliver_interrupt(vcpu, inti);
+ kfree(inti);
+ }
+ } while (deliver);
+ }
+}
+
+int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
+{
+ struct local_interrupt *li = &vcpu->arch.local_int;
+ struct interrupt_info *inti;
+
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ inti->type = KVM_S390_PROGRAM_INT;;
+ inti->pgm.code = code;
+
+ VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
+ spin_lock_bh(&li->lock);
+ list_add(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ BUG_ON(waitqueue_active(&li->wq));
+ spin_unlock_bh(&li->lock);
+ return 0;
+}
+
+int kvm_s390_inject_vm(struct kvm *kvm,
+ struct kvm_s390_interrupt *s390int)
+{
+ struct local_interrupt *li;
+ struct float_interrupt *fi;
+ struct interrupt_info *inti;
+ int sigcpu;
+
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ switch (s390int->type) {
+ case KVM_S390_INT_VIRTIO:
+ VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%lx",
+ s390int->parm, s390int->parm64);
+ inti->type = s390int->type;
+ inti->ext.ext_params = s390int->parm;
+ inti->ext.ext_params2 = s390int->parm64;
+ break;
+ case KVM_S390_INT_SERVICE:
+ VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm);
+ inti->type = s390int->type;
+ inti->ext.ext_params = s390int->parm;
+ break;
+ case KVM_S390_PROGRAM_INT:
+ case KVM_S390_SIGP_STOP:
+ case KVM_S390_INT_EMERGENCY:
+ default:
+ kfree(inti);
+ return -EINVAL;
+ }
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock_bh(&fi->lock);
+ list_add_tail(&inti->list, &fi->list);
+ atomic_set(&fi->active, 1);
+ sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
+ if (sigcpu == KVM_MAX_VCPUS) {
+ do {
+ sigcpu = fi->next_rr_cpu++;
+ if (sigcpu == KVM_MAX_VCPUS)
+ sigcpu = fi->next_rr_cpu = 0;
+ } while (fi->local_int[sigcpu] == NULL);
+ }
+ li = fi->local_int[sigcpu];
+ spin_lock_bh(&li->lock);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ if (waitqueue_active(&li->wq))
+ wake_up_interruptible(&li->wq);
+ spin_unlock_bh(&li->lock);
+ spin_unlock_bh(&fi->lock);
+ mutex_unlock(&kvm->lock);
+ return 0;
+}
+
+int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int)
+{
+ struct local_interrupt *li;
+ struct interrupt_info *inti;
+
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ switch (s390int->type) {
+ case KVM_S390_PROGRAM_INT:
+ if (s390int->parm & 0xffff0000) {
+ kfree(inti);
+ return -EINVAL;
+ }
+ inti->type = s390int->type;
+ inti->pgm.code = s390int->parm;
+ VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)",
+ s390int->parm);
+ break;
+ case KVM_S390_SIGP_STOP:
+ case KVM_S390_RESTART:
+ case KVM_S390_SIGP_SET_PREFIX:
+ case KVM_S390_INT_EMERGENCY:
+ VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
+ inti->type = s390int->type;
+ break;
+ case KVM_S390_INT_VIRTIO:
+ case KVM_S390_INT_SERVICE:
+ default:
+ kfree(inti);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vcpu->kvm->lock);
+ li = &vcpu->arch.local_int;
+ spin_lock_bh(&li->lock);
+ if (inti->type == KVM_S390_PROGRAM_INT)
+ list_add(&inti->list, &li->list);
+ else
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ if (inti->type == KVM_S390_SIGP_STOP)
+ li->action_bits |= ACTION_STOP_ON_STOP;
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ if (waitqueue_active(&li->wq))
+ wake_up_interruptible(&vcpu->arch.local_int.wq);
+ spin_unlock_bh(&li->lock);
+ mutex_unlock(&vcpu->kvm->lock);
+ return 0;
+}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
new file mode 100644
index 000000000000..98d1e73e01f1
--- /dev/null
+++ b/arch/s390/kvm/kvm-s390.c
@@ -0,0 +1,685 @@
+/*
+ * s390host.c -- hosting zSeries kernel virtual machines
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <asm/lowcore.h>
+#include <asm/pgtable.h>
+
+#include "kvm-s390.h"
+#include "gaccess.h"
+
+#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+ { "userspace_handled", VCPU_STAT(exit_userspace) },
+ { "exit_validity", VCPU_STAT(exit_validity) },
+ { "exit_stop_request", VCPU_STAT(exit_stop_request) },
+ { "exit_external_request", VCPU_STAT(exit_external_request) },
+ { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) },
+ { "exit_instruction", VCPU_STAT(exit_instruction) },
+ { "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
+ { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
+ { "instruction_lctg", VCPU_STAT(instruction_lctg) },
+ { "instruction_lctl", VCPU_STAT(instruction_lctl) },
+ { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
+ { "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
+ { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) },
+ { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) },
+ { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) },
+ { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
+ { "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
+ { "exit_wait_state", VCPU_STAT(exit_wait_state) },
+ { "instruction_stidp", VCPU_STAT(instruction_stidp) },
+ { "instruction_spx", VCPU_STAT(instruction_spx) },
+ { "instruction_stpx", VCPU_STAT(instruction_stpx) },
+ { "instruction_stap", VCPU_STAT(instruction_stap) },
+ { "instruction_storage_key", VCPU_STAT(instruction_storage_key) },
+ { "instruction_stsch", VCPU_STAT(instruction_stsch) },
+ { "instruction_chsc", VCPU_STAT(instruction_chsc) },
+ { "instruction_stsi", VCPU_STAT(instruction_stsi) },
+ { "instruction_stfl", VCPU_STAT(instruction_stfl) },
+ { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
+ { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
+ { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
+ { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
+ { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) },
+ { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
+ { "diagnose_44", VCPU_STAT(diagnose_44) },
+ { NULL }
+};
+
+
+/* Section: not file related */
+void kvm_arch_hardware_enable(void *garbage)
+{
+ /* every s390 is virtualization enabled ;-) */
+}
+
+void kvm_arch_hardware_disable(void *garbage)
+{
+}
+
+void decache_vcpus_on_cpu(int cpu)
+{
+}
+
+int kvm_arch_hardware_setup(void)
+{
+ return 0;
+}
+
+void kvm_arch_hardware_unsetup(void)
+{
+}
+
+void kvm_arch_check_processor_compat(void *rtn)
+{
+}
+
+int kvm_arch_init(void *opaque)
+{
+ return 0;
+}
+
+void kvm_arch_exit(void)
+{
+}
+
+/* Section: device related */
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ if (ioctl == KVM_S390_ENABLE_SIE)
+ return s390_enable_sie();
+ return -EINVAL;
+}
+
+int kvm_dev_ioctl_check_extension(long ext)
+{
+ return 0;
+}
+
+/* Section: vm related */
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+ struct kvm_dirty_log *log)
+{
+ return 0;
+}
+
+long kvm_arch_vm_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ int r;
+
+ switch (ioctl) {
+ case KVM_S390_INTERRUPT: {
+ struct kvm_s390_interrupt s390int;
+
+ r = -EFAULT;
+ if (copy_from_user(&s390int, argp, sizeof(s390int)))
+ break;
+ r = kvm_s390_inject_vm(kvm, &s390int);
+ break;
+ }
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+struct kvm *kvm_arch_create_vm(void)
+{
+ struct kvm *kvm;
+ int rc;
+ char debug_name[16];
+
+ rc = s390_enable_sie();
+ if (rc)
+ goto out_nokvm;
+
+ rc = -ENOMEM;
+ kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+ if (!kvm)
+ goto out_nokvm;
+
+ kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
+ if (!kvm->arch.sca)
+ goto out_nosca;
+
+ sprintf(debug_name, "kvm-%u", current->pid);
+
+ kvm->arch.dbf = debug_register(debug_name, 8, 2, 8 * sizeof(long));
+ if (!kvm->arch.dbf)
+ goto out_nodbf;
+
+ spin_lock_init(&kvm->arch.float_int.lock);
+ INIT_LIST_HEAD(&kvm->arch.float_int.list);
+
+ debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
+ VM_EVENT(kvm, 3, "%s", "vm created");
+
+ try_module_get(THIS_MODULE);
+
+ return kvm;
+out_nodbf:
+ free_page((unsigned long)(kvm->arch.sca));
+out_nosca:
+ kfree(kvm);
+out_nokvm:
+ return ERR_PTR(rc);
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ debug_unregister(kvm->arch.dbf);
+ free_page((unsigned long)(kvm->arch.sca));
+ kfree(kvm);
+ module_put(THIS_MODULE);
+}
+
+/* Section: vcpu related */
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+ /* kvm common code refers to this, but does'nt call it */
+ BUG();
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+ save_fp_regs(&vcpu->arch.host_fpregs);
+ save_access_regs(vcpu->arch.host_acrs);
+ vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
+ restore_fp_regs(&vcpu->arch.guest_fpregs);
+ restore_access_regs(vcpu->arch.guest_acrs);
+
+ if (signal_pending(current))
+ atomic_set_mask(CPUSTAT_STOP_INT,
+ &vcpu->arch.sie_block->cpuflags);
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+ save_fp_regs(&vcpu->arch.guest_fpregs);
+ save_access_regs(vcpu->arch.guest_acrs);
+ restore_fp_regs(&vcpu->arch.host_fpregs);
+ restore_access_regs(vcpu->arch.host_acrs);
+}
+
+static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
+{
+ /* this equals initial cpu reset in pop, but we don't switch to ESA */
+ vcpu->arch.sie_block->gpsw.mask = 0UL;
+ vcpu->arch.sie_block->gpsw.addr = 0UL;
+ vcpu->arch.sie_block->prefix = 0UL;
+ vcpu->arch.sie_block->ihcpu = 0xffff;
+ vcpu->arch.sie_block->cputm = 0UL;
+ vcpu->arch.sie_block->ckc = 0UL;
+ vcpu->arch.sie_block->todpr = 0;
+ memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
+ vcpu->arch.sie_block->gcr[0] = 0xE0UL;
+ vcpu->arch.sie_block->gcr[14] = 0xC2000000UL;
+ vcpu->arch.guest_fpregs.fpc = 0;
+ asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
+ vcpu->arch.sie_block->gbea = 1;
+}
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
+ vcpu->arch.sie_block->gmslm = 0xffffffffffUL;
+ vcpu->arch.sie_block->gmsor = 0x000000000000;
+ vcpu->arch.sie_block->ecb = 2;
+ vcpu->arch.sie_block->eca = 0xC1002001U;
+ setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup,
+ (unsigned long) vcpu);
+ get_cpu_id(&vcpu->arch.cpu_id);
+ vcpu->arch.cpu_id.version = 0xfe;
+ return 0;
+}
+
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
+ unsigned int id)
+{
+ struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+ int rc = -ENOMEM;
+
+ if (!vcpu)
+ goto out_nomem;
+
+ vcpu->arch.sie_block = (struct sie_block *) get_zeroed_page(GFP_KERNEL);
+
+ if (!vcpu->arch.sie_block)
+ goto out_free_cpu;
+
+ vcpu->arch.sie_block->icpua = id;
+ BUG_ON(!kvm->arch.sca);
+ BUG_ON(kvm->arch.sca->cpu[id].sda);
+ kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
+ vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
+ vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
+
+ spin_lock_init(&vcpu->arch.local_int.lock);
+ INIT_LIST_HEAD(&vcpu->arch.local_int.list);
+ vcpu->arch.local_int.float_int = &kvm->arch.float_int;
+ spin_lock_bh(&kvm->arch.float_int.lock);
+ kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
+ init_waitqueue_head(&vcpu->arch.local_int.wq);
+ vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
+ spin_unlock_bh(&kvm->arch.float_int.lock);
+
+ rc = kvm_vcpu_init(vcpu, kvm, id);
+ if (rc)
+ goto out_free_cpu;
+ VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
+ vcpu->arch.sie_block);
+
+ try_module_get(THIS_MODULE);
+
+ return vcpu;
+out_free_cpu:
+ kfree(vcpu);
+out_nomem:
+ return ERR_PTR(rc);
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ VCPU_EVENT(vcpu, 3, "%s", "destroy cpu");
+ free_page((unsigned long)(vcpu->arch.sie_block));
+ kfree(vcpu);
+ module_put(THIS_MODULE);
+}
+
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
+{
+ /* kvm common code refers to this, but never calls it */
+ BUG();
+ return 0;
+}
+
+static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+{
+ vcpu_load(vcpu);
+ kvm_s390_vcpu_initial_reset(vcpu);
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ vcpu_load(vcpu);
+ memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ vcpu_load(vcpu);
+ memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ vcpu_load(vcpu);
+ memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
+ memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ vcpu_load(vcpu);
+ memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
+ memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ vcpu_load(vcpu);
+ memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
+ vcpu->arch.guest_fpregs.fpc = fpu->fpc;
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ vcpu_load(vcpu);
+ memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
+ fpu->fpc = vcpu->arch.guest_fpregs.fpc;
+ vcpu_put(vcpu);
+ return 0;
+}
+
+static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
+{
+ int rc = 0;
+
+ vcpu_load(vcpu);
+ if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
+ rc = -EBUSY;
+ else
+ vcpu->arch.sie_block->gpsw = psw;
+ vcpu_put(vcpu);
+ return rc;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ return -EINVAL; /* not implemented yet */
+}
+
+int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
+ struct kvm_debug_guest *dbg)
+{
+ return -EINVAL; /* not implemented yet */
+}
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL; /* not implemented yet */
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL; /* not implemented yet */
+}
+
+static void __vcpu_run(struct kvm_vcpu *vcpu)
+{
+ memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
+
+ if (need_resched())
+ schedule();
+
+ vcpu->arch.sie_block->icptcode = 0;
+ local_irq_disable();
+ kvm_guest_enter();
+ local_irq_enable();
+ VCPU_EVENT(vcpu, 6, "entering sie flags %x",
+ atomic_read(&vcpu->arch.sie_block->cpuflags));
+ sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs);
+ VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
+ vcpu->arch.sie_block->icptcode);
+ local_irq_disable();
+ kvm_guest_exit();
+ local_irq_enable();
+
+ memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
+}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ int rc;
+ sigset_t sigsaved;
+
+ vcpu_load(vcpu);
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
+ atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+
+ BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
+
+ switch (kvm_run->exit_reason) {
+ case KVM_EXIT_S390_SIEIC:
+ vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask;
+ vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr;
+ break;
+ case KVM_EXIT_UNKNOWN:
+ case KVM_EXIT_S390_RESET:
+ break;
+ default:
+ BUG();
+ }
+
+ might_sleep();
+
+ do {
+ kvm_s390_deliver_pending_interrupts(vcpu);
+ __vcpu_run(vcpu);
+ rc = kvm_handle_sie_intercept(vcpu);
+ } while (!signal_pending(current) && !rc);
+
+ if (signal_pending(current) && !rc)
+ rc = -EINTR;
+
+ if (rc == -ENOTSUPP) {
+ /* intercept cannot be handled in-kernel, prepare kvm-run */
+ kvm_run->exit_reason = KVM_EXIT_S390_SIEIC;
+ kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
+ kvm_run->s390_sieic.mask = vcpu->arch.sie_block->gpsw.mask;
+ kvm_run->s390_sieic.addr = vcpu->arch.sie_block->gpsw.addr;
+ kvm_run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
+ kvm_run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
+ rc = 0;
+ }
+
+ if (rc == -EREMOTE) {
+ /* intercept was handled, but userspace support is needed
+ * kvm_run has been prepared by the handler */
+ rc = 0;
+ }
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+ vcpu_put(vcpu);
+
+ vcpu->stat.exit_userspace++;
+ return rc;
+}
+
+static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, const void *from,
+ unsigned long n, int prefix)
+{
+ if (prefix)
+ return copy_to_guest(vcpu, guestdest, from, n);
+ else
+ return copy_to_guest_absolute(vcpu, guestdest, from, n);
+}
+
+/*
+ * store status at address
+ * we use have two special cases:
+ * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit
+ * KVM_S390_STORE_STATUS_PREFIXED: -> prefix
+ */
+int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+ const unsigned char archmode = 1;
+ int prefix;
+
+ if (addr == KVM_S390_STORE_STATUS_NOADDR) {
+ if (copy_to_guest_absolute(vcpu, 163ul, &archmode, 1))
+ return -EFAULT;
+ addr = SAVE_AREA_BASE;
+ prefix = 0;
+ } else if (addr == KVM_S390_STORE_STATUS_PREFIXED) {
+ if (copy_to_guest(vcpu, 163ul, &archmode, 1))
+ return -EFAULT;
+ addr = SAVE_AREA_BASE;
+ prefix = 1;
+ } else
+ prefix = 0;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, fp_regs),
+ vcpu->arch.guest_fpregs.fprs, 128, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, gp_regs),
+ vcpu->arch.guest_gprs, 128, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, psw),
+ &vcpu->arch.sie_block->gpsw, 16, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, pref_reg),
+ &vcpu->arch.sie_block->prefix, 4, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu,
+ addr + offsetof(struct save_area_s390x, fp_ctrl_reg),
+ &vcpu->arch.guest_fpregs.fpc, 4, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, tod_reg),
+ &vcpu->arch.sie_block->todpr, 4, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, timer),
+ &vcpu->arch.sie_block->cputm, 8, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, clk_cmp),
+ &vcpu->arch.sie_block->ckc, 8, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, acc_regs),
+ &vcpu->arch.guest_acrs, 64, prefix))
+ return -EFAULT;
+
+ if (__guestcopy(vcpu,
+ addr + offsetof(struct save_area_s390x, ctrl_regs),
+ &vcpu->arch.sie_block->gcr, 128, prefix))
+ return -EFAULT;
+ return 0;
+}
+
+static int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+ int rc;
+
+ vcpu_load(vcpu);
+ rc = __kvm_s390_vcpu_store_status(vcpu, addr);
+ vcpu_put(vcpu);
+ return rc;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+
+ switch (ioctl) {
+ case KVM_S390_INTERRUPT: {
+ struct kvm_s390_interrupt s390int;
+
+ if (copy_from_user(&s390int, argp, sizeof(s390int)))
+ return -EFAULT;
+ return kvm_s390_inject_vcpu(vcpu, &s390int);
+ }
+ case KVM_S390_STORE_STATUS:
+ return kvm_s390_vcpu_store_status(vcpu, arg);
+ case KVM_S390_SET_INITIAL_PSW: {
+ psw_t psw;
+
+ if (copy_from_user(&psw, argp, sizeof(psw)))
+ return -EFAULT;
+ return kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+ }
+ case KVM_S390_INITIAL_RESET:
+ return kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+ default:
+ ;
+ }
+ return -EINVAL;
+}
+
+/* Section: memory related */
+int kvm_arch_set_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+ /* A few sanity checks. We can have exactly one memory slot which has
+ to start at guest virtual zero and which has to be located at a
+ page boundary in userland and which has to end at a page boundary.
+ The memory in userland is ok to be fragmented into various different
+ vmas. It is okay to mmap() and munmap() stuff in this slot after
+ doing this call at any time */
+
+ if (mem->slot)
+ return -EINVAL;
+
+ if (mem->guest_phys_addr)
+ return -EINVAL;
+
+ if (mem->userspace_addr & (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ if (mem->memory_size & (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ kvm->arch.guest_origin = mem->userspace_addr;
+ kvm->arch.guest_memsize = mem->memory_size;
+
+ /* FIXME: we do want to interrupt running CPUs and update their memory
+ configuration now to avoid race conditions. But hey, changing the
+ memory layout while virtual CPUs are running is usually bad
+ programming practice. */
+
+ return 0;
+}
+
+gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
+{
+ return gfn;
+}
+
+static int __init kvm_s390_init(void)
+{
+ return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+}
+
+static void __exit kvm_s390_exit(void)
+{
+ kvm_exit();
+}
+
+module_init(kvm_s390_init);
+module_exit(kvm_s390_exit);
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
new file mode 100644
index 000000000000..3893cf12eacf
--- /dev/null
+++ b/arch/s390/kvm/kvm-s390.h
@@ -0,0 +1,64 @@
+/*
+ * kvm_s390.h - definition for kvm on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#ifndef ARCH_S390_KVM_S390_H
+#define ARCH_S390_KVM_S390_H
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
+
+int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
+
+#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
+do { \
+ debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \
+ d_args); \
+} while (0)
+
+#define VCPU_EVENT(d_vcpu, d_loglevel, d_string, d_args...)\
+do { \
+ debug_sprintf_event(d_vcpu->kvm->arch.dbf, d_loglevel, \
+ "%02d[%016lx-%016lx]: " d_string "\n", d_vcpu->vcpu_id, \
+ d_vcpu->arch.sie_block->gpsw.mask, d_vcpu->arch.sie_block->gpsw.addr,\
+ d_args); \
+} while (0)
+
+static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu)
+{
+ return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT;
+}
+
+int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
+void kvm_s390_idle_wakeup(unsigned long data);
+void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
+int kvm_s390_inject_vm(struct kvm *kvm,
+ struct kvm_s390_interrupt *s390int);
+int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int);
+int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
+
+/* implemented in priv.c */
+int kvm_s390_handle_priv(struct kvm_vcpu *vcpu);
+
+/* implemented in sigp.c */
+int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
+
+/* implemented in kvm-s390.c */
+int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
+ unsigned long addr);
+/* implemented in diag.c */
+int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
+
+#endif
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
new file mode 100644
index 000000000000..1465946325c5
--- /dev/null
+++ b/arch/s390/kvm/priv.c
@@ -0,0 +1,323 @@
+/*
+ * priv.c - handling privileged instructions
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#include <linux/kvm.h>
+#include <linux/errno.h>
+#include <asm/current.h>
+#include <asm/debug.h>
+#include <asm/ebcdic.h>
+#include <asm/sysinfo.h>
+#include "gaccess.h"
+#include "kvm-s390.h"
+
+static int handle_set_prefix(struct kvm_vcpu *vcpu)
+{
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u64 operand2;
+ u32 address = 0;
+ u8 tmp;
+
+ vcpu->stat.instruction_spx++;
+
+ operand2 = disp2;
+ if (base2)
+ operand2 += vcpu->arch.guest_gprs[base2];
+
+ /* must be word boundary */
+ if (operand2 & 3) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ /* get the value */
+ if (get_guest_u32(vcpu, operand2, &address)) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ address = address & 0x7fffe000u;
+
+ /* make sure that the new value is valid memory */
+ if (copy_from_guest_absolute(vcpu, &tmp, address, 1) ||
+ (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ vcpu->arch.sie_block->prefix = address;
+ vcpu->arch.sie_block->ihcpu = 0xffff;
+
+ VCPU_EVENT(vcpu, 5, "setting prefix to %x", address);
+out:
+ return 0;
+}
+
+static int handle_store_prefix(struct kvm_vcpu *vcpu)
+{
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u64 operand2;
+ u32 address;
+
+ vcpu->stat.instruction_stpx++;
+ operand2 = disp2;
+ if (base2)
+ operand2 += vcpu->arch.guest_gprs[base2];
+
+ /* must be word boundary */
+ if (operand2 & 3) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ address = vcpu->arch.sie_block->prefix;
+ address = address & 0x7fffe000u;
+
+ /* get the value */
+ if (put_guest_u32(vcpu, operand2, address)) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ VCPU_EVENT(vcpu, 5, "storing prefix to %x", address);
+out:
+ return 0;
+}
+
+static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
+{
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u64 useraddr;
+ int rc;
+
+ vcpu->stat.instruction_stap++;
+ useraddr = disp2;
+ if (base2)
+ useraddr += vcpu->arch.guest_gprs[base2];
+
+ if (useraddr & 1) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id);
+ if (rc == -EFAULT) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ VCPU_EVENT(vcpu, 5, "storing cpu address to %lx", useraddr);
+out:
+ return 0;
+}
+
+static int handle_skey(struct kvm_vcpu *vcpu)
+{
+ vcpu->stat.instruction_storage_key++;
+ vcpu->arch.sie_block->gpsw.addr -= 4;
+ VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
+ return 0;
+}
+
+static int handle_stsch(struct kvm_vcpu *vcpu)
+{
+ vcpu->stat.instruction_stsch++;
+ VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3");
+ /* condition code 3 */
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
+ return 0;
+}
+
+static int handle_chsc(struct kvm_vcpu *vcpu)
+{
+ vcpu->stat.instruction_chsc++;
+ VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3");
+ /* condition code 3 */
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
+ return 0;
+}
+
+static unsigned int kvm_stfl(void)
+{
+ asm volatile(
+ " .insn s,0xb2b10000,0(0)\n" /* stfl */
+ "0:\n"
+ EX_TABLE(0b, 0b));
+ return S390_lowcore.stfl_fac_list;
+}
+
+static int handle_stfl(struct kvm_vcpu *vcpu)
+{
+ unsigned int facility_list = kvm_stfl();
+ int rc;
+
+ vcpu->stat.instruction_stfl++;
+ facility_list &= ~(1UL<<24); /* no stfle */
+
+ rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
+ &facility_list, sizeof(facility_list));
+ if (rc == -EFAULT)
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ else
+ VCPU_EVENT(vcpu, 5, "store facility list value %x",
+ facility_list);
+ return 0;
+}
+
+static int handle_stidp(struct kvm_vcpu *vcpu)
+{
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u64 operand2;
+ int rc;
+
+ vcpu->stat.instruction_stidp++;
+ operand2 = disp2;
+ if (base2)
+ operand2 += vcpu->arch.guest_gprs[base2];
+
+ if (operand2 & 7) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ rc = put_guest_u64(vcpu, operand2, vcpu->arch.stidp_data);
+ if (rc == -EFAULT) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ VCPU_EVENT(vcpu, 5, "%s", "store cpu id");
+out:
+ return 0;
+}
+
+static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
+{
+ struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ int cpus = 0;
+ int n;
+
+ spin_lock_bh(&fi->lock);
+ for (n = 0; n < KVM_MAX_VCPUS; n++)
+ if (fi->local_int[n])
+ cpus++;
+ spin_unlock_bh(&fi->lock);
+
+ /* deal with other level 3 hypervisors */
+ if (stsi(mem, 3, 2, 2) == -ENOSYS)
+ mem->count = 0;
+ if (mem->count < 8)
+ mem->count++;
+ for (n = mem->count - 1; n > 0 ; n--)
+ memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0]));
+
+ mem->vm[0].cpus_total = cpus;
+ mem->vm[0].cpus_configured = cpus;
+ mem->vm[0].cpus_standby = 0;
+ mem->vm[0].cpus_reserved = 0;
+ mem->vm[0].caf = 1000;
+ memcpy(mem->vm[0].name, "KVMguest", 8);
+ ASCEBC(mem->vm[0].name, 8);
+ memcpy(mem->vm[0].cpi, "KVM/Linux ", 16);
+ ASCEBC(mem->vm[0].cpi, 16);
+}
+
+static int handle_stsi(struct kvm_vcpu *vcpu)
+{
+ int fc = (vcpu->arch.guest_gprs[0] & 0xf0000000) >> 28;
+ int sel1 = vcpu->arch.guest_gprs[0] & 0xff;
+ int sel2 = vcpu->arch.guest_gprs[1] & 0xffff;
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u64 operand2;
+ unsigned long mem;
+
+ vcpu->stat.instruction_stsi++;
+ VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2);
+
+ operand2 = disp2;
+ if (base2)
+ operand2 += vcpu->arch.guest_gprs[base2];
+
+ if (operand2 & 0xfff && fc > 0)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ switch (fc) {
+ case 0:
+ vcpu->arch.guest_gprs[0] = 3 << 28;
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ return 0;
+ case 1: /* same handling for 1 and 2 */
+ case 2:
+ mem = get_zeroed_page(GFP_KERNEL);
+ if (!mem)
+ goto out_fail;
+ if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS)
+ goto out_mem;
+ break;
+ case 3:
+ if (sel1 != 2 || sel2 != 2)
+ goto out_fail;
+ mem = get_zeroed_page(GFP_KERNEL);
+ if (!mem)
+ goto out_fail;
+ handle_stsi_3_2_2(vcpu, (void *) mem);
+ break;
+ default:
+ goto out_fail;
+ }
+
+ if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out_mem;
+ }
+ free_page(mem);
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ vcpu->arch.guest_gprs[0] = 0;
+ return 0;
+out_mem:
+ free_page(mem);
+out_fail:
+ /* condition code 3 */
+ vcpu->arch.sie_block->gpsw.mask |= 3ul << 44;
+ return 0;
+}
+
+static intercept_handler_t priv_handlers[256] = {
+ [0x02] = handle_stidp,
+ [0x10] = handle_set_prefix,
+ [0x11] = handle_store_prefix,
+ [0x12] = handle_store_cpu_address,
+ [0x29] = handle_skey,
+ [0x2a] = handle_skey,
+ [0x2b] = handle_skey,
+ [0x34] = handle_stsch,
+ [0x5f] = handle_chsc,
+ [0x7d] = handle_stsi,
+ [0xb1] = handle_stfl,
+};
+
+int kvm_s390_handle_priv(struct kvm_vcpu *vcpu)
+{
+ intercept_handler_t handler;
+
+ handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
+ if (handler)
+ return handler(vcpu);
+ return -ENOTSUPP;
+}
diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S
new file mode 100644
index 000000000000..934fd6a885f6
--- /dev/null
+++ b/arch/s390/kvm/sie64a.S
@@ -0,0 +1,47 @@
+/*
+ * sie64a.S - low level sie call
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/errno.h>
+#include <asm/asm-offsets.h>
+
+SP_R5 = 5 * 8 # offset into stackframe
+SP_R6 = 6 * 8
+
+/*
+ * sie64a calling convention:
+ * %r2 pointer to sie control block
+ * %r3 guest register save area
+ */
+ .globl sie64a
+sie64a:
+ lgr %r5,%r3
+ stmg %r5,%r14,SP_R5(%r15) # save register on entry
+ lgr %r14,%r2 # pointer to sie control block
+ lmg %r0,%r13,0(%r3) # load guest gprs 0-13
+sie_inst:
+ sie 0(%r14)
+ lg %r14,SP_R5(%r15)
+ stmg %r0,%r13,0(%r14) # save guest gprs 0-13
+ lghi %r2,0
+ lmg %r6,%r14,SP_R6(%r15)
+ br %r14
+
+sie_err:
+ lg %r14,SP_R5(%r15)
+ stmg %r0,%r13,0(%r14) # save guest gprs 0-13
+ lghi %r2,-EFAULT
+ lmg %r6,%r14,SP_R6(%r15)
+ br %r14
+
+ .section __ex_table,"a"
+ .quad sie_inst,sie_err
+ .previous
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
new file mode 100644
index 000000000000..0a236acfb5f6
--- /dev/null
+++ b/arch/s390/kvm/sigp.c
@@ -0,0 +1,288 @@
+/*
+ * sigp.c - handlinge interprocessor communication
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include "gaccess.h"
+#include "kvm-s390.h"
+
+/* sigp order codes */
+#define SIGP_SENSE 0x01
+#define SIGP_EXTERNAL_CALL 0x02
+#define SIGP_EMERGENCY 0x03
+#define SIGP_START 0x04
+#define SIGP_STOP 0x05
+#define SIGP_RESTART 0x06
+#define SIGP_STOP_STORE_STATUS 0x09
+#define SIGP_INITIAL_CPU_RESET 0x0b
+#define SIGP_CPU_RESET 0x0c
+#define SIGP_SET_PREFIX 0x0d
+#define SIGP_STORE_STATUS_ADDR 0x0e
+#define SIGP_SET_ARCH 0x12
+
+/* cpu status bits */
+#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL
+#define SIGP_STAT_INCORRECT_STATE 0x00000200UL
+#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
+#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL
+#define SIGP_STAT_STOPPED 0x00000040UL
+#define SIGP_STAT_OPERATOR_INTERV 0x00000020UL
+#define SIGP_STAT_CHECK_STOP 0x00000010UL
+#define SIGP_STAT_INOPERATIVE 0x00000004UL
+#define SIGP_STAT_INVALID_ORDER 0x00000002UL
+#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
+
+
+static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg)
+{
+ struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ int rc;
+
+ if (cpu_addr >= KVM_MAX_VCPUS)
+ return 3; /* not operational */
+
+ spin_lock_bh(&fi->lock);
+ if (fi->local_int[cpu_addr] == NULL)
+ rc = 3; /* not operational */
+ else if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
+ & CPUSTAT_RUNNING) {
+ *reg &= 0xffffffff00000000UL;
+ rc = 1; /* status stored */
+ } else {
+ *reg &= 0xffffffff00000000UL;
+ *reg |= SIGP_STAT_STOPPED;
+ rc = 1; /* status stored */
+ }
+ spin_unlock_bh(&fi->lock);
+
+ VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
+ return rc;
+}
+
+static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
+{
+ struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ struct local_interrupt *li;
+ struct interrupt_info *inti;
+ int rc;
+
+ if (cpu_addr >= KVM_MAX_VCPUS)
+ return 3; /* not operational */
+
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ inti->type = KVM_S390_INT_EMERGENCY;
+
+ spin_lock_bh(&fi->lock);
+ li = fi->local_int[cpu_addr];
+ if (li == NULL) {
+ rc = 3; /* not operational */
+ kfree(inti);
+ goto unlock;
+ }
+ spin_lock_bh(&li->lock);
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ if (waitqueue_active(&li->wq))
+ wake_up_interruptible(&li->wq);
+ spin_unlock_bh(&li->lock);
+ rc = 0; /* order accepted */
+unlock:
+ spin_unlock_bh(&fi->lock);
+ VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
+ return rc;
+}
+
+static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store)
+{
+ struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ struct local_interrupt *li;
+ struct interrupt_info *inti;
+ int rc;
+
+ if (cpu_addr >= KVM_MAX_VCPUS)
+ return 3; /* not operational */
+
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ inti->type = KVM_S390_SIGP_STOP;
+
+ spin_lock_bh(&fi->lock);
+ li = fi->local_int[cpu_addr];
+ if (li == NULL) {
+ rc = 3; /* not operational */
+ kfree(inti);
+ goto unlock;
+ }
+ spin_lock_bh(&li->lock);
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
+ if (store)
+ li->action_bits |= ACTION_STORE_ON_STOP;
+ li->action_bits |= ACTION_STOP_ON_STOP;
+ if (waitqueue_active(&li->wq))
+ wake_up_interruptible(&li->wq);
+ spin_unlock_bh(&li->lock);
+ rc = 0; /* order accepted */
+unlock:
+ spin_unlock_bh(&fi->lock);
+ VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
+ return rc;
+}
+
+static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
+{
+ int rc;
+
+ switch (parameter & 0xff) {
+ case 0:
+ printk(KERN_WARNING "kvm: request to switch to ESA/390 mode"
+ " not supported");
+ rc = 3; /* not operational */
+ break;
+ case 1:
+ case 2:
+ rc = 0; /* order accepted */
+ break;
+ default:
+ rc = -ENOTSUPP;
+ }
+ return rc;
+}
+
+static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
+ u64 *reg)
+{
+ struct float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ struct local_interrupt *li;
+ struct interrupt_info *inti;
+ int rc;
+ u8 tmp;
+
+ /* make sure that the new value is valid memory */
+ address = address & 0x7fffe000u;
+ if ((copy_from_guest(vcpu, &tmp,
+ (u64) (address + vcpu->kvm->arch.guest_origin) , 1)) ||
+ (copy_from_guest(vcpu, &tmp, (u64) (address +
+ vcpu->kvm->arch.guest_origin + PAGE_SIZE), 1))) {
+ *reg |= SIGP_STAT_INVALID_PARAMETER;
+ return 1; /* invalid parameter */
+ }
+
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return 2; /* busy */
+
+ spin_lock_bh(&fi->lock);
+ li = fi->local_int[cpu_addr];
+
+ if ((cpu_addr >= KVM_MAX_VCPUS) || (li == NULL)) {
+ rc = 1; /* incorrect state */
+ *reg &= SIGP_STAT_INCORRECT_STATE;
+ kfree(inti);
+ goto out_fi;
+ }
+
+ spin_lock_bh(&li->lock);
+ /* cpu must be in stopped state */
+ if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
+ rc = 1; /* incorrect state */
+ *reg &= SIGP_STAT_INCORRECT_STATE;
+ kfree(inti);
+ goto out_li;
+ }
+
+ inti->type = KVM_S390_SIGP_SET_PREFIX;
+ inti->prefix.address = address;
+
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ if (waitqueue_active(&li->wq))
+ wake_up_interruptible(&li->wq);
+ rc = 0; /* order accepted */
+
+ VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
+out_li:
+ spin_unlock_bh(&li->lock);
+out_fi:
+ spin_unlock_bh(&fi->lock);
+ return rc;
+}
+
+int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
+{
+ int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+ int r3 = vcpu->arch.sie_block->ipa & 0x000f;
+ int base2 = vcpu->arch.sie_block->ipb >> 28;
+ int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+ u32 parameter;
+ u16 cpu_addr = vcpu->arch.guest_gprs[r3];
+ u8 order_code;
+ int rc;
+
+ order_code = disp2;
+ if (base2)
+ order_code += vcpu->arch.guest_gprs[base2];
+
+ if (r1 % 2)
+ parameter = vcpu->arch.guest_gprs[r1];
+ else
+ parameter = vcpu->arch.guest_gprs[r1 + 1];
+
+ switch (order_code) {
+ case SIGP_SENSE:
+ vcpu->stat.instruction_sigp_sense++;
+ rc = __sigp_sense(vcpu, cpu_addr,
+ &vcpu->arch.guest_gprs[r1]);
+ break;
+ case SIGP_EMERGENCY:
+ vcpu->stat.instruction_sigp_emergency++;
+ rc = __sigp_emergency(vcpu, cpu_addr);
+ break;
+ case SIGP_STOP:
+ vcpu->stat.instruction_sigp_stop++;
+ rc = __sigp_stop(vcpu, cpu_addr, 0);
+ break;
+ case SIGP_STOP_STORE_STATUS:
+ vcpu->stat.instruction_sigp_stop++;
+ rc = __sigp_stop(vcpu, cpu_addr, 1);
+ break;
+ case SIGP_SET_ARCH:
+ vcpu->stat.instruction_sigp_arch++;
+ rc = __sigp_set_arch(vcpu, parameter);
+ break;
+ case SIGP_SET_PREFIX:
+ vcpu->stat.instruction_sigp_prefix++;
+ rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
+ &vcpu->arch.guest_gprs[r1]);
+ break;
+ case SIGP_RESTART:
+ vcpu->stat.instruction_sigp_restart++;
+ /* user space must know about restart */
+ default:
+ return -ENOTSUPP;
+ }
+
+ if (rc < 0)
+ return rc;
+
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ vcpu->arch.sie_block->gpsw.mask |= (rc & 3ul) << 44;
+ return 0;
+}
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index fd072013f88c..5c1aea97cd12 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -30,11 +30,27 @@
#define TABLES_PER_PAGE 4
#define FRAG_MASK 15UL
#define SECOND_HALVES 10UL
+
+void clear_table_pgstes(unsigned long *table)
+{
+ clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/4);
+ memset(table + 256, 0, PAGE_SIZE/4);
+ clear_table(table + 512, _PAGE_TYPE_EMPTY, PAGE_SIZE/4);
+ memset(table + 768, 0, PAGE_SIZE/4);
+}
+
#else
#define ALLOC_ORDER 2
#define TABLES_PER_PAGE 2
#define FRAG_MASK 3UL
#define SECOND_HALVES 2UL
+
+void clear_table_pgstes(unsigned long *table)
+{
+ clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2);
+ memset(table + 256, 0, PAGE_SIZE/2);
+}
+
#endif
unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
@@ -153,7 +169,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
unsigned long *table;
unsigned long bits;
- bits = mm->context.noexec ? 3UL : 1UL;
+ bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL;
spin_lock(&mm->page_table_lock);
page = NULL;
if (!list_empty(&mm->context.pgtable_list)) {
@@ -170,7 +186,10 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
pgtable_page_ctor(page);
page->flags &= ~FRAG_MASK;
table = (unsigned long *) page_to_phys(page);
- clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+ if (mm->context.pgstes)
+ clear_table_pgstes(table);
+ else
+ clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
spin_lock(&mm->page_table_lock);
list_add(&page->lru, &mm->context.pgtable_list);
}
@@ -191,7 +210,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
struct page *page;
unsigned long bits;
- bits = mm->context.noexec ? 3UL : 1UL;
+ bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL;
bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
spin_lock(&mm->page_table_lock);
@@ -228,3 +247,43 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
mm->context.noexec = 0;
update_mm(mm, tsk);
}
+
+/*
+ * switch on pgstes for its userspace process (for kvm)
+ */
+int s390_enable_sie(void)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm;
+ int rc;
+
+ task_lock(tsk);
+
+ rc = 0;
+ if (tsk->mm->context.pgstes)
+ goto unlock;
+
+ rc = -EINVAL;
+ if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
+ tsk->mm != tsk->active_mm || tsk->mm->ioctx_list)
+ goto unlock;
+
+ tsk->mm->context.pgstes = 1; /* dirty little tricks .. */
+ mm = dup_mm(tsk);
+ tsk->mm->context.pgstes = 0;
+
+ rc = -ENOMEM;
+ if (!mm)
+ goto unlock;
+ mmput(tsk->mm);
+ tsk->mm = tsk->active_mm = mm;
+ preempt_disable();
+ update_mm(mm, tsk);
+ cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+ preempt_enable();
+ rc = 0;
+unlock:
+ task_unlock(tsk);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(s390_enable_sie);
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 53dde0607362..d7df26bd1e54 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -307,15 +307,6 @@ void free_initrd_mem(unsigned long start, unsigned long end)
#endif
#ifdef CONFIG_MEMORY_HOTPLUG
-void online_page(struct page *page)
-{
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalram_pages++;
- num_physpages++;
-}
-
int arch_add_memory(int nid, u64 start, u64 size)
{
pg_data_t *pgdat;
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 70c0dd22491d..e7f35198ae34 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -357,8 +357,6 @@ void flush_thread(void)
{
current_thread_info()->w_saved = 0;
- /* No new signal delivery by default */
- current->thread.new_signal = 0;
#ifndef CONFIG_SMP
if(last_task_used_math == current) {
#else
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 3e849e8e3480..3c312290c3c2 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,5 +1,4 @@
-/* $Id: signal.c,v 1.110 2002/02/08 03:57:14 davem Exp $
- * linux/arch/sparc/kernel/signal.c
+/* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -32,37 +31,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
void *fpqueue, unsigned long *fpqdepth);
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-/* Signal frames: the original one (compatible with SunOS):
- *
- * Set up a signal frame... Make the stack look the way SunOS
- * expects it to look which is basically:
- *
- * ---------------------------------- <-- %sp at signal time
- * Struct sigcontext
- * Signal address
- * Ptr to sigcontext area above
- * Signal code
- * The signal number itself
- * One register window
- * ---------------------------------- <-- New %sp
- */
-struct signal_sframe {
- struct reg_window sig_window;
- int sig_num;
- int sig_code;
- struct sigcontext __user *sig_scptr;
- int sig_address;
- struct sigcontext sig_context;
- unsigned int extramask[_NSIG_WORDS - 1];
-};
-
-/*
- * And the new one, intended to be used for Linux applications only
- * (we have enough in there to work with clone).
- * All the interesting bits are in the info field.
- */
-
-struct new_signal_frame {
+struct signal_frame {
struct sparc_stackf ss;
__siginfo_t info;
__siginfo_fpu_t __user *fpu_save;
@@ -85,8 +54,7 @@ struct rt_signal_frame {
};
/* Align macros */
-#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7)))
-#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
+#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
static int _sigpause_common(old_sigset_t set)
@@ -141,15 +109,20 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
return err;
}
-static inline void do_new_sigreturn (struct pt_regs *regs)
+asmlinkage void do_sigreturn(struct pt_regs *regs)
{
- struct new_signal_frame __user *sf;
+ struct signal_frame __user *sf;
unsigned long up_psr, pc, npc;
sigset_t set;
__siginfo_fpu_t __user *fpu_save;
int err;
- sf = (struct new_signal_frame __user *) regs->u_regs[UREG_FP];
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ synchronize_user_stack();
+
+ sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
/* 1. Make sure we are not getting garbage from the user */
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)))
@@ -198,73 +171,6 @@ segv_and_exit:
force_sig(SIGSEGV, current);
}
-asmlinkage void do_sigreturn(struct pt_regs *regs)
-{
- struct sigcontext __user *scptr;
- unsigned long pc, npc, psr;
- sigset_t set;
- int err;
-
- /* Always make any pending restarted system calls return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
- synchronize_user_stack();
-
- if (current->thread.new_signal) {
- do_new_sigreturn(regs);
- return;
- }
-
- scptr = (struct sigcontext __user *) regs->u_regs[UREG_I0];
-
- /* Check sanity of the user arg. */
- if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext)) ||
- (((unsigned long) scptr) & 3))
- goto segv_and_exit;
-
- err = __get_user(pc, &scptr->sigc_pc);
- err |= __get_user(npc, &scptr->sigc_npc);
-
- if ((pc | npc) & 3)
- goto segv_and_exit;
-
- /* This is pretty much atomic, no amount locking would prevent
- * the races which exist anyways.
- */
- err |= __get_user(set.sig[0], &scptr->sigc_mask);
- /* Note that scptr + 1 points to extramask */
- err |= __copy_from_user(&set.sig[1], scptr + 1,
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
-
- if (err)
- goto segv_and_exit;
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->pc = pc;
- regs->npc = npc;
-
- err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
- err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);
- err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);
-
- /* User can only change condition codes in %psr. */
- err |= __get_user(psr, &scptr->sigc_psr);
- if (err)
- goto segv_and_exit;
-
- regs->psr &= ~(PSR_ICC);
- regs->psr |= (psr & PSR_ICC);
- return;
-
-segv_and_exit:
- force_sig(SIGSEGV, current);
-}
-
asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_signal_frame __user *sf;
@@ -351,128 +257,6 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
return (void __user *)(sp - framesize);
}
-static inline void
-setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *oldset, siginfo_t *info)
-{
- struct signal_sframe __user *sframep;
- struct sigcontext __user *sc;
- int window = 0, err;
- unsigned long pc = regs->pc;
- unsigned long npc = regs->npc;
- struct thread_info *tp = current_thread_info();
- void __user *sig_address;
- int sig_code;
-
- synchronize_user_stack();
- sframep = (struct signal_sframe __user *)
- get_sigframe(sa, regs, SF_ALIGNEDSZ);
- if (invalid_frame_pointer(sframep, sizeof(*sframep))){
- /* Don't change signal code and address, so that
- * post mortem debuggers can have a look.
- */
- goto sigill_and_return;
- }
-
- sc = &sframep->sig_context;
-
- /* We've already made sure frame pointer isn't in kernel space... */
- err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK),
- &sc->sigc_onstack);
- err |= __put_user(oldset->sig[0], &sc->sigc_mask);
- err |= __copy_to_user(sframep->extramask, &oldset->sig[1],
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
- err |= __put_user(pc, &sc->sigc_pc);
- err |= __put_user(npc, &sc->sigc_npc);
- err |= __put_user(regs->psr, &sc->sigc_psr);
- err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
- err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
- err |= __put_user(tp->w_saved, &sc->sigc_oswins);
- if (tp->w_saved)
- for (window = 0; window < tp->w_saved; window++) {
- put_user((char *)tp->rwbuf_stkptrs[window],
- &sc->sigc_spbuf[window]);
- err |= __copy_to_user(&sc->sigc_wbuf[window],
- &tp->reg_window[window],
- sizeof(struct reg_window));
- }
- else
- err |= __copy_to_user(sframep, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window));
-
- tp->w_saved = 0; /* So process is allowed to execute. */
-
- err |= __put_user(signr, &sframep->sig_num);
- sig_address = NULL;
- sig_code = 0;
- if (SI_FROMKERNEL (info) && (info->si_code & __SI_MASK) == __SI_FAULT) {
- sig_address = info->si_addr;
- switch (signr) {
- case SIGSEGV:
- switch (info->si_code) {
- case SEGV_MAPERR: sig_code = SUBSIG_NOMAPPING; break;
- default: sig_code = SUBSIG_PROTECTION; break;
- }
- break;
- case SIGILL:
- switch (info->si_code) {
- case ILL_ILLOPC: sig_code = SUBSIG_ILLINST; break;
- case ILL_PRVOPC: sig_code = SUBSIG_PRIVINST; break;
- case ILL_ILLTRP: sig_code = SUBSIG_BADTRAP(info->si_trapno); break;
- default: sig_code = SUBSIG_STACK; break;
- }
- break;
- case SIGFPE:
- switch (info->si_code) {
- case FPE_INTDIV: sig_code = SUBSIG_IDIVZERO; break;
- case FPE_INTOVF: sig_code = SUBSIG_FPINTOVFL; break;
- case FPE_FLTDIV: sig_code = SUBSIG_FPDIVZERO; break;
- case FPE_FLTOVF: sig_code = SUBSIG_FPOVFLOW; break;
- case FPE_FLTUND: sig_code = SUBSIG_FPUNFLOW; break;
- case FPE_FLTRES: sig_code = SUBSIG_FPINEXACT; break;
- case FPE_FLTINV: sig_code = SUBSIG_FPOPERROR; break;
- default: sig_code = SUBSIG_FPERROR; break;
- }
- break;
- case SIGBUS:
- switch (info->si_code) {
- case BUS_ADRALN: sig_code = SUBSIG_ALIGNMENT; break;
- case BUS_ADRERR: sig_code = SUBSIG_MISCERROR; break;
- default: sig_code = SUBSIG_BUSTIMEOUT; break;
- }
- break;
- case SIGEMT:
- switch (info->si_code) {
- case EMT_TAGOVF: sig_code = SUBSIG_TAG; break;
- }
- break;
- case SIGSYS:
- if (info->si_code == (__SI_FAULT|0x100)) {
- sig_code = info->si_trapno;
- break;
- }
- default:
- sig_address = NULL;
- }
- }
- err |= __put_user((unsigned long)sig_address, &sframep->sig_address);
- err |= __put_user(sig_code, &sframep->sig_code);
- err |= __put_user(sc, &sframep->sig_scptr);
- if (err)
- goto sigsegv;
-
- regs->u_regs[UREG_FP] = (unsigned long) sframep;
- regs->pc = (unsigned long) sa->sa_handler;
- regs->npc = (regs->pc + 4);
- return;
-
-sigill_and_return:
- do_exit(SIGILL);
-sigsegv:
- force_sigsegv(signr, current);
-}
-
-
static inline int
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
{
@@ -508,21 +292,20 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
return err;
}
-static inline void
-new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
+static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
- struct new_signal_frame __user *sf;
+ struct signal_frame __user *sf;
int sigframe_size, err;
/* 1. Make sure everything is clean */
synchronize_user_stack();
- sigframe_size = NF_ALIGNEDSZ;
+ sigframe_size = SF_ALIGNEDSZ;
if (!used_math())
sigframe_size -= sizeof(__siginfo_fpu_t);
- sf = (struct new_signal_frame __user *)
+ sf = (struct signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size))
@@ -586,9 +369,8 @@ sigsegv:
force_sigsegv(signo, current);
}
-static inline void
-new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset, siginfo_t *info)
+static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
int sigframe_size;
@@ -674,11 +456,9 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
if (ka->sa.sa_flags & SA_SIGINFO)
- new_setup_rt_frame(ka, regs, signr, oldset, info);
- else if (current->thread.new_signal)
- new_setup_frame(ka, regs, signr, oldset);
+ setup_rt_frame(ka, regs, signr, oldset, info);
else
- setup_frame(&ka->sa, regs, signr, oldset, info);
+ setup_frame(ka, regs, signr, oldset);
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 42bf09db9a81..f188b5dc9fd0 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -1,5 +1,4 @@
-/* $Id: sys_sparc.c,v 1.70 2001/04/14 01:12:02 davem Exp $
- * linux/arch/sparc/kernel/sys_sparc.c
+/* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
* have a non-standard calling sequence on the Linux/sparc
@@ -395,10 +394,8 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act,
struct k_sigaction new_ka, old_ka;
int ret;
- if (sig < 0) {
- current->thread.new_signal = 1;
- sig = -sig;
- }
+ WARN_ON_ONCE(sig >= 0);
+ sig = -sig;
if (act) {
unsigned long mask;
@@ -446,11 +443,6 @@ sys_rt_sigaction(int sig,
if (sigsetsize != sizeof(sigset_t))
return -EINVAL;
- /* All tasks which use RT signals (effectively) use
- * new style signals.
- */
- current->thread.new_signal = 1;
-
if (act) {
new_ka.ka_restorer = restorer;
if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 8acc5cc38621..edbe71e3fab9 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -1,9 +1,5 @@
-# $Id: config.in,v 1.158 2002/01/24 22:14:44 davem Exp $
-# For a description of the syntax of this configuration file,
-# see the Configure script.
-#
-
-mainmenu "Linux/UltraSPARC Kernel Configuration"
+# sparc64 configuration
+mainmenu "Linux Kernel Configuration for 64-bit SPARC"
config SPARC
bool
@@ -17,12 +13,6 @@ config SPARC64
default y
select HAVE_IDE
select HAVE_LMB
- help
- SPARC is a family of RISC microprocessors designed and marketed by
- Sun Microsystems, incorporated. This port covers the newer 64-bit
- UltraSPARC. The UltraLinux project maintains both the SPARC32 and
- SPARC64 ports; its web page is available at
- <http://www.ultralinux.org/>.
config GENERIC_TIME
bool
@@ -97,7 +87,7 @@ config SPARC64_PAGE_SIZE_8KB
help
This lets you select the page size of the kernel.
- 8KB and 64KB work quite well, since Sparc ELF sections
+ 8KB and 64KB work quite well, since SPARC ELF sections
provide for up to 64KB alignment.
Therefore, 512KB and 4MB are for expert hackers only.
@@ -138,7 +128,7 @@ config HOTPLUG_CPU
bool "Support for hot-pluggable CPUs"
depends on SMP
select HOTPLUG
- ---help---
+ help
Say Y here to experiment with turning CPUs off and on. CPUs
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.
@@ -155,23 +145,16 @@ source "kernel/time/Kconfig"
config SMP
bool "Symmetric multi-processing support"
- ---help---
+ help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, say N. If you have a system with more than
one CPU, say Y.
If you say N here, the kernel will run on single and multiprocessor
machines, but will use only one CPU of a multiprocessor machine. If
- you say Y here, the kernel will run on many, but not all,
- singleprocessor machines. On a singleprocessor machine, the kernel
- will run faster if you say N here.
-
- People using multiprocessor machines who say Y here should also say
- Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
- Management" code will be disabled if you say Y here.
-
- See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
- available at <http://www.tldp.org/docs.html#howto>.
+ you say Y here, the kernel will run on single-processor machines.
+ On a single-processor machine, the kernel will run faster if you say
+ N here.
If you don't know what to do here, say N.
@@ -284,50 +267,19 @@ source "mm/Kconfig"
config ISA
bool
- help
- Find out whether you have ISA slots on your motherboard. ISA is the
- name of a bus system, i.e. the way the CPU talks to the other stuff
- inside your box. Other bus systems are PCI, EISA, MicroChannel
- (MCA) or VESA. ISA is an older system, now being displaced by PCI;
- newer boards don't support it. If you have ISA, say Y, otherwise N.
config ISAPNP
bool
- help
- Say Y here if you would like support for ISA Plug and Play devices.
- Some information is in <file:Documentation/isapnp.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called isapnp.
-
- If unsure, say Y.
config EISA
bool
- ---help---
- The Extended Industry Standard Architecture (EISA) bus was
- developed as an open alternative to the IBM MicroChannel bus.
-
- The EISA bus provided some of the features of the IBM MicroChannel
- bus while maintaining backward compatibility with cards made for
- the older ISA bus. The EISA bus saw limited use between 1988 and
- 1995 when it was made obsolete by the PCI bus.
-
- Say Y here if you are building a kernel for an EISA-based machine.
-
- Otherwise, say N.
config MCA
bool
- help
- MicroChannel Architecture is found in some IBM PS/2 machines and
- laptops. It is a bus system similar to PCI or ISA. See
- <file:Documentation/mca.txt> (and especially the web page given
- there) before attempting to build an MCA bus kernel.
config PCMCIA
tristate
- ---help---
+ help
Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
computer. These are credit-card size devices such as network cards,
modems or hard drives often used with laptops computers. There are
@@ -369,10 +321,10 @@ config PCI
bool "PCI support"
select ARCH_SUPPORTS_MSI
help
- Find out whether you have a PCI motherboard. PCI is the name of a
- bus system, i.e. the way the CPU talks to the other stuff inside
- your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
- VESA. If you have PCI, say Y, otherwise N.
+ Find out whether your system includes a PCI bus. PCI is the name of
+ a bus system, i.e. the way the CPU talks to the other stuff inside
+ your box. If you say Y here, the kernel will include drivers and
+ infrastructure code to support PCI bus devices.
config PCI_DOMAINS
def_bool PCI
@@ -396,15 +348,8 @@ menu "Executable file formats"
source "fs/Kconfig.binfmt"
-config SPARC32_COMPAT
- bool "Kernel support for Linux/Sparc 32bit binary compatibility"
- help
- This allows you to run 32-bit binaries on your Ultra.
- Everybody wants this; say Y.
-
config COMPAT
bool
- depends on SPARC32_COMPAT
default y
select COMPAT_BINFMT_ELF
@@ -421,8 +366,8 @@ config SCHED_SMT
default y
help
SMT scheduler support improves the CPU scheduler's decision making
- when dealing with UltraSPARC cpus at a cost of slightly increased
- overhead in some places. If unsure say N here.
+ when dealing with SPARC cpus at a cost of slightly increased overhead
+ in some places. If unsure say N here.
config SCHED_MC
bool "Multi-core scheduler support"
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 92f79680f70d..aff93c9d13f4 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25-numa
-# Wed Apr 23 04:49:08 2008
+# Linux kernel version: 2.6.25
+# Sat Apr 26 03:11:06 2008
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -152,7 +152,9 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_HUGETLB_PAGE_SIZE_4MB=y
# CONFIG_HUGETLB_PAGE_SIZE_512K is not set
# CONFIG_HUGETLB_PAGE_SIZE_64K is not set
-# CONFIG_NUMA is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=4
+CONFIG_NODES_SPAN_OTHER_NODES=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
@@ -162,12 +164,14 @@ CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
+CONFIG_NEED_MULTIPLE_NODES=y
CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=0
CONFIG_NR_QUICK=1
@@ -191,7 +195,6 @@ CONFIG_SUN_OPENPROMFS=m
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-CONFIG_SPARC32_COMPAT=y
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_SCHED_SMT=y
@@ -746,13 +749,7 @@ CONFIG_DEVPORT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
#
# I2C Hardware Bus support
@@ -780,6 +777,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
#
# Miscellaneous I2C Chip support
@@ -1026,6 +1024,7 @@ CONFIG_SND_ALI5451=m
# CONFIG_SND_AU8810 is not set
# CONFIG_SND_AU8820 is not set
# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
# CONFIG_SND_AZT3328 is not set
# CONFIG_SND_BT87X is not set
# CONFIG_SND_CA0106 is not set
@@ -1097,10 +1096,6 @@ CONFIG_SND_SUN_CS4231=m
# CONFIG_SND_SOC is not set
#
-# SoC Audio support for SuperH
-#
-
-#
# ALSA SoC audio for Freescale SOCs
#
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 63c6ae0dd273..2bd0340b743d 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -15,17 +15,17 @@ obj-y := process.o setup.o cpu.o idprom.o \
visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \
+obj-$(CONFIG_PCI) += ebus.o pci_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
obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
-obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
+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_KPROBES) += kprobes.o
obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
obj-$(CONFIG_AUDIT) += audit.o
-obj-$(CONFIG_AUDIT)$(CONFIG_SPARC32_COMPAT) += compat_audit.o
+obj-$(CONFIG_AUDIT)$(CONFIG_COMPAT) += compat_audit.o
obj-y += $(obj-yy)
diff --git a/arch/sparc64/kernel/audit.c b/arch/sparc64/kernel/audit.c
index 24d7f4b4178a..8fff0ac63d56 100644
--- a/arch/sparc64/kernel/audit.c
+++ b/arch/sparc64/kernel/audit.c
@@ -30,7 +30,7 @@ static unsigned signal_class[] = {
int audit_classify_arch(int arch)
{
-#ifdef CONFIG_SPARC32_COMPAT
+#ifdef CONFIG_COMPAT
if (arch == AUDIT_ARCH_SPARC)
return 1;
#endif
@@ -39,7 +39,7 @@ int audit_classify_arch(int arch)
int audit_classify_syscall(int abi, unsigned syscall)
{
-#ifdef CONFIG_SPARC32_COMPAT
+#ifdef CONFIG_COMPAT
extern int sparc32_classify_syscall(unsigned);
if (abi == AUDIT_ARCH_SPARC)
return sparc32_classify_syscall(syscall);
@@ -60,7 +60,7 @@ int audit_classify_syscall(int abi, unsigned syscall)
static int __init audit_classes_init(void)
{
-#ifdef CONFIG_SPARC32_COMPAT
+#ifdef CONFIG_COMPAT
extern __u32 sparc32_dir_class[];
extern __u32 sparc32_write_class[];
extern __u32 sparc32_read_class[];
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index eb88bd6e674e..b441a26b73b0 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,6 +1,6 @@
/* irq.c: UltraSparc IRQ handling/init/registry.
*
- * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 2007, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
@@ -308,6 +308,7 @@ static void sun4u_irq_enable(unsigned int virt_irq)
IMAP_AID_SAFARI | IMAP_NID_SAFARI);
val |= tid | IMAP_VALID;
upa_writeq(val, imap);
+ upa_writeq(ICLR_IDLE, data->iclr);
}
}
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
deleted file mode 100644
index a2af5ed784c9..000000000000
--- a/arch/sparc64/kernel/isa.c
+++ /dev/null
@@ -1,191 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/isa.h>
-
-struct sparc_isa_bridge *isa_chain;
-
-static void __init fatal_err(const char *reason)
-{
- prom_printf("ISA: fatal error, %s.\n", reason);
-}
-
-static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
-{
- if (child)
- printk(" (%s)", isa_dev->prom_node->name);
- else
- printk(" [%s", isa_dev->prom_node->name);
-}
-
-static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev)
-{
- struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
-
- memcpy(&isa_dev->resource, &op->resource[0], sizeof(struct resource));
-}
-
-static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev)
-{
- struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
-
- if (!op || !op->num_irqs) {
- isa_dev->irq = PCI_IRQ_NONE;
- } else {
- isa_dev->irq = op->irqs[0];
- }
-}
-
-static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
-{
- struct device_node *dp = parent_isa_dev->prom_node->child;
-
- if (!dp)
- return;
-
- printk(" ->");
- while (dp) {
- struct sparc_isa_device *isa_dev;
-
- isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
- if (!isa_dev) {
- fatal_err("cannot allocate child isa_dev");
- prom_halt();
- }
-
- /* Link it in to parent. */
- isa_dev->next = parent_isa_dev->child;
- parent_isa_dev->child = isa_dev;
-
- isa_dev->bus = parent_isa_dev->bus;
- isa_dev->prom_node = dp;
-
- isa_dev_get_resource(isa_dev);
- isa_dev_get_irq(isa_dev);
-
- report_dev(isa_dev, 1);
-
- dp = dp->sibling;
- }
-}
-
-static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
-{
- struct device_node *dp = isa_br->prom_node->child;
-
- while (dp) {
- struct sparc_isa_device *isa_dev;
- struct dev_archdata *sd;
-
- isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
- if (!isa_dev) {
- printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
- return;
- }
-
- sd = &isa_dev->ofdev.dev.archdata;
- sd->prom_node = dp;
- sd->op = &isa_dev->ofdev;
- sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu;
- sd->stc = isa_br->ofdev.dev.parent->archdata.stc;
- sd->numa_node = isa_br->ofdev.dev.parent->archdata.numa_node;
-
- isa_dev->ofdev.node = dp;
- isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
- isa_dev->ofdev.dev.bus = &isa_bus_type;
- sprintf(isa_dev->ofdev.dev.bus_id, "isa[%08x]", dp->node);
-
- /* Register with core */
- if (of_device_register(&isa_dev->ofdev) != 0) {
- printk(KERN_DEBUG "isa: device registration error for %s!\n",
- dp->path_component_name);
- kfree(isa_dev);
- goto next_sibling;
- }
-
- /* Link it in. */
- isa_dev->next = NULL;
- if (isa_br->devices == NULL) {
- isa_br->devices = isa_dev;
- } else {
- struct sparc_isa_device *tmp = isa_br->devices;
-
- while (tmp->next)
- tmp = tmp->next;
-
- tmp->next = isa_dev;
- }
-
- isa_dev->bus = isa_br;
- isa_dev->prom_node = dp;
-
- isa_dev_get_resource(isa_dev);
- isa_dev_get_irq(isa_dev);
-
- report_dev(isa_dev, 0);
-
- isa_fill_children(isa_dev);
-
- printk("]");
-
- next_sibling:
- dp = dp->sibling;
- }
-}
-
-void __init isa_init(void)
-{
- struct pci_dev *pdev;
- unsigned short vendor, device;
- int index = 0;
-
- vendor = PCI_VENDOR_ID_AL;
- device = PCI_DEVICE_ID_AL_M1533;
-
- pdev = NULL;
- while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) {
- struct sparc_isa_bridge *isa_br;
- struct device_node *dp;
-
- dp = pci_device_to_OF_node(pdev);
-
- isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL);
- if (!isa_br) {
- printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
- pci_dev_put(pdev);
- return;
- }
-
- isa_br->ofdev.node = dp;
- isa_br->ofdev.dev.parent = &pdev->dev;
- isa_br->ofdev.dev.bus = &isa_bus_type;
- sprintf(isa_br->ofdev.dev.bus_id, "isa%d", index);
-
- /* Register with core */
- if (of_device_register(&isa_br->ofdev) != 0) {
- printk(KERN_DEBUG "isa: device registration error for %s!\n",
- dp->path_component_name);
- kfree(isa_br);
- pci_dev_put(pdev);
- return;
- }
-
- /* Link it in. */
- isa_br->next = isa_chain;
- isa_chain = isa_br;
-
- isa_br->self = pdev;
- isa_br->index = index++;
- isa_br->prom_node = dp;
-
- printk("isa%d:", isa_br->index);
-
- isa_fill_devices(isa_br);
-
- printk("\n");
- }
-}
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 9e58e8cba1c3..d569f60c24b8 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -412,12 +412,6 @@ static int __init build_one_resource(struct device_node *parent,
static int __init use_1to1_mapping(struct device_node *pp)
{
- /* If this is on the PMU bus, don't try to translate it even
- * if a ranges property exists.
- */
- if (!strcmp(pp->name, "pmu"))
- return 1;
-
/* If we have a ranges property in the parent, use it. */
if (of_find_property(pp, "ranges", NULL) != NULL)
return 0;
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 49f912766519..dbf2fc2f4d87 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -23,7 +23,6 @@
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/ebus.h>
-#include <asm/isa.h>
#include <asm/prom.h>
#include <asm/apb.h>
@@ -885,7 +884,6 @@ static int __init pcibios_init(void)
pci_scan_each_controller_bus();
- isa_init();
ebus_init();
power_init();
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index acf8c5250aa9..056013749157 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,5 +1,4 @@
-/* $Id: process.c,v 1.131 2002/02/09 19:49:30 davem Exp $
- * arch/sparc64/kernel/process.c
+/* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
@@ -368,9 +367,6 @@ void flush_thread(void)
if (get_thread_current_ds() != ASI_AIUS)
set_fs(USER_DS);
-
- /* Init new signal delivery disposition. */
- clear_thread_flag(TIF_NEWSIGNALS);
}
/* It's a bit more tricky when 64-bit tasks are involved... */
@@ -595,6 +591,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
if (clone_flags & CLONE_SETTLS)
t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
+ /* We do not want to accidently trigger system call restart
+ * handling in the new thread. Therefore, clear out the trap
+ * type, which will make pt_regs_regs_is_syscall() return false.
+ */
+ pt_regs_clear_trap_type(t->kregs);
+
return 0;
}
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 77a3e8592cbc..f2d88d8f7a42 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -8,7 +8,7 @@
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#ifdef CONFIG_SPARC32_COMPAT
+#ifdef CONFIG_COMPAT
#include <linux/compat.h> /* for compat_old_sigset_t */
#endif
#include <linux/sched.h>
@@ -236,9 +236,6 @@ struct rt_signal_frame {
__siginfo_fpu_t fpu_state;
};
-/* Align macros */
-#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
-
static long _sigpause_common(old_sigset_t set)
{
set &= _BLOCKABLE;
@@ -400,7 +397,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = RT_ALIGNEDSZ;
+ sigframe_size = sizeof(struct rt_signal_frame);
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
@@ -516,11 +513,10 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
struct k_sigaction ka;
sigset_t *oldset;
siginfo_t info;
- int signr, tt;
+ int signr;
- tt = regs->magic & 0x1ff;
- if (tt == 0x110 || tt == 0x111 || tt == 0x16d) {
- regs->magic &= ~0x1ff;
+ if (pt_regs_is_syscall(regs)) {
+ pt_regs_clear_trap_type(regs);
cookie.restart_syscall = 1;
} else
cookie.restart_syscall = 0;
@@ -531,7 +527,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
else
oldset = &current->blocked;
-#ifdef CONFIG_SPARC32_COMPAT
+#ifdef CONFIG_COMPAT
if (test_thread_flag(TIF_32BIT)) {
extern void do_signal32(sigset_t *, struct pt_regs *,
struct signal_deliver_cookie *);
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 43cdec64d9c9..91f8d0826db1 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,5 +1,4 @@
-/* $Id: signal32.c,v 1.74 2002/02/09 19:49:30 davem Exp $
- * arch/sparc64/kernel/signal32.c
+/* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -31,30 +30,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-/* Signal frames: the original one (compatible with SunOS):
- *
- * Set up a signal frame... Make the stack look the way SunOS
- * expects it to look which is basically:
- *
- * ---------------------------------- <-- %sp at signal time
- * Struct sigcontext
- * Signal address
- * Ptr to sigcontext area above
- * Signal code
- * The signal number itself
- * One register window
- * ---------------------------------- <-- New %sp
- */
-struct signal_sframe32 {
- struct reg_window32 sig_window;
- int sig_num;
- int sig_code;
- /* struct sigcontext32 * */ u32 sig_scptr;
- int sig_address;
- struct sigcontext32 sig_context;
- unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
-};
-
/* This magic should be in g_upper[0] for all upper parts
* to be valid.
*/
@@ -65,12 +40,7 @@ typedef struct {
unsigned int asi;
} siginfo_extra_v8plus_t;
-/*
- * And the new one, intended to be used for Linux applications only
- * (we have enough in there to work with clone).
- * All the interesting bits are in the info field.
- */
-struct new_signal_frame32 {
+struct signal_frame32 {
struct sparc_stackf32 ss;
__siginfo32_t info;
/* __siginfo_fpu32_t * */ u32 fpu_save;
@@ -149,8 +119,7 @@ struct rt_signal_frame32 {
};
/* Align macros */
-#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe32) + 7) & (~7)))
-#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7)))
+#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7)))
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
@@ -241,17 +210,22 @@ static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu
return err;
}
-void do_new_sigreturn32(struct pt_regs *regs)
+void do_sigreturn32(struct pt_regs *regs)
{
- struct new_signal_frame32 __user *sf;
+ struct signal_frame32 __user *sf;
unsigned int psr;
unsigned pc, npc, fpu_save;
sigset_t set;
unsigned seta[_COMPAT_NSIG_WORDS];
int err, i;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ synchronize_user_stack();
+
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
- sf = (struct new_signal_frame32 __user *) regs->u_regs[UREG_FP];
+ sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
/* 1. Make sure we are not getting garbage from the user */
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
@@ -319,76 +293,6 @@ segv:
force_sig(SIGSEGV, current);
}
-asmlinkage void do_sigreturn32(struct pt_regs *regs)
-{
- struct sigcontext32 __user *scptr;
- unsigned int pc, npc, psr;
- sigset_t set;
- unsigned int seta[_COMPAT_NSIG_WORDS];
- int err;
-
- /* Always make any pending restarted system calls return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
- synchronize_user_stack();
- if (test_thread_flag(TIF_NEWSIGNALS)) {
- do_new_sigreturn32(regs);
- return;
- }
-
- scptr = (struct sigcontext32 __user *)
- (regs->u_regs[UREG_I0] & 0x00000000ffffffffUL);
- /* Check sanity of the user arg. */
- if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
- (((unsigned long) scptr) & 3))
- goto segv;
-
- err = __get_user(pc, &scptr->sigc_pc);
- err |= __get_user(npc, &scptr->sigc_npc);
-
- if ((pc | npc) & 3)
- goto segv; /* Nice try. */
-
- err |= __get_user(seta[0], &scptr->sigc_mask);
- /* Note that scptr + 1 points to extramask */
- err |= copy_from_user(seta+1, scptr + 1,
- (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
- if (err)
- goto segv;
- switch (_NSIG_WORDS) {
- case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
- case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);
- case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
- case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
- }
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- if (test_thread_flag(TIF_32BIT)) {
- pc &= 0xffffffff;
- npc &= 0xffffffff;
- }
- regs->tpc = pc;
- regs->tnpc = npc;
- err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
- err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);
- err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);
-
- /* User can only change condition codes in %tstate. */
- err |= __get_user(psr, &scptr->sigc_psr);
- if (err)
- goto segv;
- regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
- regs->tstate |= psr_to_tstate_icc(psr);
- return;
-
-segv:
- force_sig(SIGSEGV, current);
-}
-
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
{
struct rt_signal_frame32 __user *sf;
@@ -504,145 +408,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
return (void __user *)(sp - framesize);
}
-static void
-setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *oldset, siginfo_t *info)
-{
- struct signal_sframe32 __user *sframep;
- struct sigcontext32 __user *sc;
- unsigned int seta[_COMPAT_NSIG_WORDS];
- int err = 0;
- void __user *sig_address;
- int sig_code;
- unsigned long pc = regs->tpc;
- unsigned long npc = regs->tnpc;
- unsigned int psr;
-
- if (test_thread_flag(TIF_32BIT)) {
- pc &= 0xffffffff;
- npc &= 0xffffffff;
- }
-
- synchronize_user_stack();
- save_and_clear_fpu();
-
- sframep = (struct signal_sframe32 __user *)
- get_sigframe(sa, regs, SF_ALIGNEDSZ);
- if (invalid_frame_pointer(sframep, sizeof(*sframep))){
- /* Don't change signal code and address, so that
- * post mortem debuggers can have a look.
- */
- do_exit(SIGILL);
- }
-
- sc = &sframep->sig_context;
-
- /* We've already made sure frame pointer isn't in kernel space... */
- err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK),
- &sc->sigc_onstack);
-
- switch (_NSIG_WORDS) {
- case 4: seta[7] = (oldset->sig[3] >> 32);
- seta[6] = oldset->sig[3];
- case 3: seta[5] = (oldset->sig[2] >> 32);
- seta[4] = oldset->sig[2];
- case 2: seta[3] = (oldset->sig[1] >> 32);
- seta[2] = oldset->sig[1];
- case 1: seta[1] = (oldset->sig[0] >> 32);
- seta[0] = oldset->sig[0];
- }
- err |= __put_user(seta[0], &sc->sigc_mask);
- err |= __copy_to_user(sframep->extramask, seta + 1,
- (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
- err |= __put_user(pc, &sc->sigc_pc);
- err |= __put_user(npc, &sc->sigc_npc);
- psr = tstate_to_psr(regs->tstate);
- if (current_thread_info()->fpsaved[0] & FPRS_FEF)
- psr |= PSR_EF;
- err |= __put_user(psr, &sc->sigc_psr);
- err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
- err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
- err |= __put_user(get_thread_wsaved(), &sc->sigc_oswins);
-
- err |= copy_in_user((u32 __user *)sframep,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
-
- set_thread_wsaved(0); /* So process is allowed to execute. */
- err |= __put_user(signr, &sframep->sig_num);
- sig_address = NULL;
- sig_code = 0;
- if (SI_FROMKERNEL (info) && (info->si_code & __SI_MASK) == __SI_FAULT) {
- sig_address = info->si_addr;
- switch (signr) {
- case SIGSEGV:
- switch (info->si_code) {
- case SEGV_MAPERR: sig_code = SUBSIG_NOMAPPING; break;
- default: sig_code = SUBSIG_PROTECTION; break;
- }
- break;
- case SIGILL:
- switch (info->si_code) {
- case ILL_ILLOPC: sig_code = SUBSIG_ILLINST; break;
- case ILL_PRVOPC: sig_code = SUBSIG_PRIVINST; break;
- case ILL_ILLTRP: sig_code = SUBSIG_BADTRAP(info->si_trapno); break;
- default: sig_code = SUBSIG_STACK; break;
- }
- break;
- case SIGFPE:
- switch (info->si_code) {
- case FPE_INTDIV: sig_code = SUBSIG_IDIVZERO; break;
- case FPE_INTOVF: sig_code = SUBSIG_FPINTOVFL; break;
- case FPE_FLTDIV: sig_code = SUBSIG_FPDIVZERO; break;
- case FPE_FLTOVF: sig_code = SUBSIG_FPOVFLOW; break;
- case FPE_FLTUND: sig_code = SUBSIG_FPUNFLOW; break;
- case FPE_FLTRES: sig_code = SUBSIG_FPINEXACT; break;
- case FPE_FLTINV: sig_code = SUBSIG_FPOPERROR; break;
- default: sig_code = SUBSIG_FPERROR; break;
- }
- break;
- case SIGBUS:
- switch (info->si_code) {
- case BUS_ADRALN: sig_code = SUBSIG_ALIGNMENT; break;
- case BUS_ADRERR: sig_code = SUBSIG_MISCERROR; break;
- default: sig_code = SUBSIG_BUSTIMEOUT; break;
- }
- break;
- case SIGEMT:
- switch (info->si_code) {
- case EMT_TAGOVF: sig_code = SUBSIG_TAG; break;
- }
- break;
- case SIGSYS:
- if (info->si_code == (__SI_FAULT|0x100)) {
- /* See sys_sunos32.c */
- sig_code = info->si_trapno;
- break;
- }
- default:
- sig_address = NULL;
- }
- }
- err |= __put_user(ptr_to_compat(sig_address), &sframep->sig_address);
- err |= __put_user(sig_code, &sframep->sig_code);
- err |= __put_user(ptr_to_compat(sc), &sframep->sig_scptr);
- if (err)
- goto sigsegv;
-
- regs->u_regs[UREG_FP] = (unsigned long) sframep;
- regs->tpc = (unsigned long) sa->sa_handler;
- regs->tnpc = (regs->tpc + 4);
- if (test_thread_flag(TIF_32BIT)) {
- regs->tpc &= 0xffffffff;
- regs->tnpc &= 0xffffffff;
- }
- return;
-
-sigsegv:
- force_sigsegv(signr, current);
-}
-
-
static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
{
unsigned long *fpregs = current_thread_info()->fpregs;
@@ -663,10 +428,10 @@ static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
return err;
}
-static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
+static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
- struct new_signal_frame32 __user *sf;
+ struct signal_frame32 __user *sf;
int sigframe_size;
u32 psr;
int i, err;
@@ -676,11 +441,11 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = NF_ALIGNEDSZ;
+ sigframe_size = SF_ALIGNEDSZ;
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
- sf = (struct new_signal_frame32 __user *)
+ sf = (struct signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size))
@@ -944,10 +709,9 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
{
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame32(ka, regs, signr, oldset, info);
- else if (test_thread_flag(TIF_NEWSIGNALS))
- new_setup_frame32(ka, regs, signr, oldset);
else
- setup_frame32(&ka->sa, regs, signr, oldset, info);
+ setup_frame32(ka, regs, signr, oldset);
+
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NOMASK))
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 524b88920947..409dd71f2738 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -866,14 +866,21 @@ void smp_call_function_client(int irq, struct pt_regs *regs)
void *info = call_data->info;
clear_softint(1 << irq);
+
+ irq_enter();
+
+ if (!call_data->wait) {
+ /* let initiator proceed after getting data */
+ atomic_inc(&call_data->finished);
+ }
+
+ func(info);
+
+ irq_exit();
+
if (call_data->wait) {
/* let initiator proceed only after completion */
- func(info);
atomic_inc(&call_data->finished);
- } else {
- /* let initiator proceed after getting data */
- atomic_inc(&call_data->finished);
- func(info);
}
}
@@ -1032,7 +1039,9 @@ void smp_receive_signal(int cpu)
void smp_receive_signal_client(int irq, struct pt_regs *regs)
{
+ irq_enter();
clear_softint(1 << irq);
+ irq_exit();
}
void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
@@ -1040,6 +1049,8 @@ void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
struct mm_struct *mm;
unsigned long flags;
+ irq_enter();
+
clear_softint(1 << irq);
/* See if we need to allocate a new TLB context because
@@ -1059,6 +1070,8 @@ void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
load_secondary_context(mm);
__flush_tlb_mm(CTX_HWBITS(mm->context),
SECONDARY_CONTEXT);
+
+ irq_exit();
}
void smp_new_mmu_context_version(void)
@@ -1217,6 +1230,8 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
+ irq_enter();
+
preempt_disable();
__asm__ __volatile__("flushw");
@@ -1229,6 +1244,8 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
prom_world(0);
preempt_enable();
+
+ irq_exit();
}
/* /proc/profile writes can call this, don't __init it please. */
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 66336590e830..8ac0b99f2c55 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -49,7 +49,6 @@
#endif
#ifdef CONFIG_PCI
#include <asm/ebus.h>
-#include <asm/isa.h>
#endif
#include <asm/ns87303.h>
#include <asm/timer.h>
@@ -187,7 +186,6 @@ EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(ebus_chain);
-EXPORT_SYMBOL(isa_chain);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
EXPORT_SYMBOL(pci_map_single);
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 73ed01ba40dc..8d4761f15fa9 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -454,8 +454,8 @@ asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second,
err = sys_semget(first, (int)second, (int)third);
goto out;
case SEMCTL: {
- err = sys_semctl(first, third,
- (int)second | IPC_64,
+ err = sys_semctl(first, second,
+ (int)third | IPC_64,
(union semun) ptr);
goto out;
}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index c1a61e98899a..161ce4710fe7 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -554,10 +554,8 @@ asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act
struct k_sigaction new_ka, old_ka;
int ret;
- if (sig < 0) {
- set_thread_flag(TIF_NEWSIGNALS);
- sig = -sig;
- }
+ WARN_ON_ONCE(sig >= 0);
+ sig = -sig;
if (act) {
compat_old_sigset_t mask;
@@ -601,11 +599,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL;
- /* All tasks which use RT signals (effectively) use
- * new style signals.
- */
- set_thread_flag(TIF_NEWSIGNALS);
-
if (act) {
u32 u_handler, u_restorer;
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 177d8aaeec42..8c2b50e8abc6 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1699,9 +1699,21 @@ void __init paging_init(void)
* functions like clear_dcache_dirty_cpu use the cpu mask
* in 13-bit signed-immediate instruction fields.
*/
- BUILD_BUG_ON(FLAGS_RESERVED != 32);
+
+ /*
+ * Page flags must not reach into upper 32 bits that are used
+ * for the cpu number
+ */
+ BUILD_BUG_ON(NR_PAGEFLAGS > 32);
+
+ /*
+ * The bit fields placed in the high range must not reach below
+ * the 32 bit boundary. Otherwise we cannot place the cpu field
+ * at the 32 bit boundary.
+ */
BUILD_BUG_ON(SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH +
- ilog2(roundup_pow_of_two(NR_CPUS)) > FLAGS_RESERVED);
+ ilog2(roundup_pow_of_two(NR_CPUS)) > 32);
+
BUILD_BUG_ON(NR_CPUS > 4096);
kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64
index 3fbe69e359ed..5696e7b374b3 100644
--- a/arch/um/Kconfig.x86_64
+++ b/arch/um/Kconfig.x86_64
@@ -1,3 +1,10 @@
+
+menu "Host processor type and features"
+
+source "arch/x86/Kconfig.cpu"
+
+endmenu
+
config UML_X86
bool
default y
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index db3082b4da46..6e51424745ab 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -125,7 +125,7 @@ static int open_one_chan(struct chan *chan)
return 0;
}
-int open_chan(struct list_head *chans)
+static int open_chan(struct list_head *chans)
{
struct list_head *ele;
struct chan *chan;
@@ -583,19 +583,6 @@ int parse_chan_pair(char *str, struct line *line, int device,
return 0;
}
-int chan_out_fd(struct list_head *chans)
-{
- struct list_head *ele;
- struct chan *chan;
-
- list_for_each(ele, chans) {
- chan = list_entry(ele, struct chan, list);
- if (chan->primary && chan->output)
- return chan->fd;
- }
- return -1;
-}
-
void chan_interrupt(struct list_head *chans, struct delayed_work *task,
struct tty_struct *tty, int irq)
{
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 2c898c4d6b6a..10b86e1cc659 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -304,7 +304,7 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
break;
if (i == ARRAY_SIZE(tty_ioctls)) {
printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
- __FUNCTION__, tty->name, cmd);
+ __func__, tty->name, cmd);
}
ret = -ENOIOCTLCMD;
break;
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index 822092f149be..8c4378a76d63 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -58,7 +58,7 @@ static const struct net_kern_info mcast_kern_info = {
.write = mcast_write,
};
-int mcast_setup(char *str, char **mac_out, void *data)
+static int mcast_setup(char *str, char **mac_out, void *data)
{
struct mcast_init *init = data;
char *port_str = NULL, *ttl_str = NULL, *remain;
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 13af2f03ed84..f8cf4c8bedef 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -39,7 +39,7 @@ static struct mconsole_command commands[] = {
/* Initialized in mconsole_init, which is an initcall */
char mconsole_socket_name[256];
-int mconsole_reply_v0(struct mc_request *req, char *reply)
+static int mconsole_reply_v0(struct mc_request *req, char *reply)
{
struct iovec iov;
struct msghdr msg;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 1d43bdfc20c4..5b4ca8d93682 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -116,7 +116,7 @@ static void uml_dev_close(struct work_struct *work)
dev_close(lp->dev);
}
-irqreturn_t uml_net_interrupt(int irq, void *dev_id)
+static irqreturn_t uml_net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct uml_net_private *lp = dev->priv;
@@ -296,7 +296,7 @@ static struct ethtool_ops uml_net_ethtool_ops = {
.get_link = ethtool_op_get_link,
};
-void uml_net_user_timer_expire(unsigned long _conn)
+static void uml_net_user_timer_expire(unsigned long _conn)
{
#ifdef undef
struct connection *conn = (struct connection *)_conn;
@@ -786,7 +786,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
}
/* uml_net_init shouldn't be called twice on two CPUs at the same time */
-struct notifier_block uml_inetaddr_notifier = {
+static struct notifier_block uml_inetaddr_notifier = {
.notifier_call = uml_inetaddr_event,
};
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index addd75902656..d269ca387f10 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -153,7 +153,7 @@ struct port_pre_exec_data {
int pipe_fd;
};
-void port_pre_exec(void *arg)
+static void port_pre_exec(void *arg)
{
struct port_pre_exec_data *data = arg;
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index 6b4a0f9e38de..d19faec7046e 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -13,7 +13,7 @@ struct slip_init {
char *gate_addr;
};
-void slip_init(struct net_device *dev, void *data)
+static void slip_init(struct net_device *dev, void *data)
{
struct uml_net_private *private;
struct slip_data *spri;
@@ -57,7 +57,7 @@ static int slip_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
(struct slip_data *) &lp->user);
}
-const struct net_kern_info slip_kern_info = {
+static const struct net_kern_info slip_kern_info = {
.init = slip_init,
.protocol = slip_protocol,
.read = slip_read,
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index cec0c33cdd39..49266f6108c4 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -34,7 +34,7 @@
static struct tty_driver *console_driver;
-void stdio_announce(char *dev_name, int dev)
+static void stdio_announce(char *dev_name, int dev)
{
printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
dev_name);
@@ -158,7 +158,7 @@ static struct console stdiocons = {
.index = -1,
};
-int stdio_init(void)
+static int stdio_init(void)
{
char *new_title;
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index be3a2797dac4..5e45e39a8a8d 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -72,18 +72,6 @@ struct io_thread_req {
int error;
};
-extern int open_ubd_file(char *file, struct openflags *openflags, int shared,
- char **backing_file_out, int *bitmap_offset_out,
- unsigned long *bitmap_len_out, int *data_offset_out,
- int *create_cow_out);
-extern int create_cow_file(char *cow_file, char *backing_file,
- struct openflags flags, int sectorsize,
- int alignment, int *bitmap_offset_out,
- unsigned long *bitmap_len_out,
- int *data_offset_out);
-extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
-extern void do_io(struct io_thread_req *req);
-
static inline int ubd_test_bit(__u64 bit, unsigned char *data)
{
__u64 n;
@@ -200,7 +188,7 @@ struct ubd {
}
/* Protected by ubd_lock */
-struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
+static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD };
/* Only changed by fake_ide_setup which is a setup */
static int fake_ide = 0;
@@ -463,7 +451,7 @@ __uml_help(udb_setup,
static void do_ubd_request(struct request_queue * q);
/* Only changed by ubd_init, which is an initcall. */
-int thread_fd = -1;
+static int thread_fd = -1;
static void ubd_end_request(struct request *req, int bytes, int error)
{
@@ -531,7 +519,7 @@ static irqreturn_t ubd_intr(int irq, void *dev)
/* Only changed by ubd_init, which is an initcall. */
static int io_pid = -1;
-void kill_io_thread(void)
+static void kill_io_thread(void)
{
if(io_pid != -1)
os_kill_process(io_pid, 1);
@@ -547,6 +535,192 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
return os_file_size(file, size_out);
}
+static int read_cow_bitmap(int fd, void *buf, int offset, int len)
+{
+ int err;
+
+ err = os_seek_file(fd, offset);
+ if (err < 0)
+ return err;
+
+ err = os_read_file(fd, buf, len);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
+{
+ unsigned long modtime;
+ unsigned long long actual;
+ int err;
+
+ err = os_file_modtime(file, &modtime);
+ if (err < 0) {
+ printk(KERN_ERR "Failed to get modification time of backing "
+ "file \"%s\", err = %d\n", file, -err);
+ return err;
+ }
+
+ err = os_file_size(file, &actual);
+ if (err < 0) {
+ printk(KERN_ERR "Failed to get size of backing file \"%s\", "
+ "err = %d\n", file, -err);
+ return err;
+ }
+
+ if (actual != size) {
+ /*__u64 can be a long on AMD64 and with %lu GCC complains; so
+ * the typecast.*/
+ printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header "
+ "vs backing file\n", (unsigned long long) size, actual);
+ return -EINVAL;
+ }
+ if (modtime != mtime) {
+ printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs "
+ "backing file\n", mtime, modtime);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
+{
+ struct uml_stat buf1, buf2;
+ int err;
+
+ if (from_cmdline == NULL)
+ return 0;
+ if (!strcmp(from_cmdline, from_cow))
+ return 0;
+
+ err = os_stat_file(from_cmdline, &buf1);
+ if (err < 0) {
+ printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline,
+ -err);
+ return 0;
+ }
+ err = os_stat_file(from_cow, &buf2);
+ if (err < 0) {
+ printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow,
+ -err);
+ return 1;
+ }
+ if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
+ return 0;
+
+ printk(KERN_ERR "Backing file mismatch - \"%s\" requested, "
+ "\"%s\" specified in COW header of \"%s\"\n",
+ from_cmdline, from_cow, cow);
+ return 1;
+}
+
+static int open_ubd_file(char *file, struct openflags *openflags, int shared,
+ char **backing_file_out, int *bitmap_offset_out,
+ unsigned long *bitmap_len_out, int *data_offset_out,
+ int *create_cow_out)
+{
+ time_t mtime;
+ unsigned long long size;
+ __u32 version, align;
+ char *backing_file;
+ int fd, err, sectorsize, asked_switch, mode = 0644;
+
+ fd = os_open_file(file, *openflags, mode);
+ if (fd < 0) {
+ if ((fd == -ENOENT) && (create_cow_out != NULL))
+ *create_cow_out = 1;
+ if (!openflags->w ||
+ ((fd != -EROFS) && (fd != -EACCES)))
+ return fd;
+ openflags->w = 0;
+ fd = os_open_file(file, *openflags, mode);
+ if (fd < 0)
+ return fd;
+ }
+
+ if (shared)
+ printk(KERN_INFO "Not locking \"%s\" on the host\n", file);
+ else {
+ err = os_lock_file(fd, openflags->w);
+ if (err < 0) {
+ printk(KERN_ERR "Failed to lock '%s', err = %d\n",
+ file, -err);
+ goto out_close;
+ }
+ }
+
+ /* Successful return case! */
+ if (backing_file_out == NULL)
+ return fd;
+
+ err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
+ &size, &sectorsize, &align, bitmap_offset_out);
+ if (err && (*backing_file_out != NULL)) {
+ printk(KERN_ERR "Failed to read COW header from COW file "
+ "\"%s\", errno = %d\n", file, -err);
+ goto out_close;
+ }
+ if (err)
+ return fd;
+
+ asked_switch = path_requires_switch(*backing_file_out, backing_file,
+ file);
+
+ /* Allow switching only if no mismatch. */
+ if (asked_switch && !backing_file_mismatch(*backing_file_out, size,
+ mtime)) {
+ printk(KERN_ERR "Switching backing file to '%s'\n",
+ *backing_file_out);
+ err = write_cow_header(file, fd, *backing_file_out,
+ sectorsize, align, &size);
+ if (err) {
+ printk(KERN_ERR "Switch failed, errno = %d\n", -err);
+ goto out_close;
+ }
+ } else {
+ *backing_file_out = backing_file;
+ err = backing_file_mismatch(*backing_file_out, size, mtime);
+ if (err)
+ goto out_close;
+ }
+
+ cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
+ bitmap_len_out, data_offset_out);
+
+ return fd;
+ out_close:
+ os_close_file(fd);
+ return err;
+}
+
+static int create_cow_file(char *cow_file, char *backing_file,
+ struct openflags flags,
+ int sectorsize, int alignment, int *bitmap_offset_out,
+ unsigned long *bitmap_len_out, int *data_offset_out)
+{
+ int err, fd;
+
+ flags.c = 1;
+ fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
+ if (fd < 0) {
+ err = fd;
+ printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n",
+ cow_file, -err);
+ goto out;
+ }
+
+ err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
+ bitmap_offset_out, bitmap_len_out,
+ data_offset_out);
+ if (!err)
+ return fd;
+ os_close_file(fd);
+ out:
+ return err;
+}
+
static void ubd_close_dev(struct ubd *ubd_dev)
{
os_close_file(ubd_dev->fd);
@@ -1166,185 +1340,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
return -EINVAL;
}
-static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
-{
- struct uml_stat buf1, buf2;
- int err;
-
- if(from_cmdline == NULL)
- return 0;
- if(!strcmp(from_cmdline, from_cow))
- return 0;
-
- err = os_stat_file(from_cmdline, &buf1);
- if(err < 0){
- printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
- return 0;
- }
- err = os_stat_file(from_cow, &buf2);
- if(err < 0){
- printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
- return 1;
- }
- if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
- return 0;
-
- printk("Backing file mismatch - \"%s\" requested,\n"
- "\"%s\" specified in COW header of \"%s\"\n",
- from_cmdline, from_cow, cow);
- return 1;
-}
-
-static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
-{
- unsigned long modtime;
- unsigned long long actual;
- int err;
-
- err = os_file_modtime(file, &modtime);
- if(err < 0){
- printk("Failed to get modification time of backing file "
- "\"%s\", err = %d\n", file, -err);
- return err;
- }
-
- err = os_file_size(file, &actual);
- if(err < 0){
- printk("Failed to get size of backing file \"%s\", "
- "err = %d\n", file, -err);
- return err;
- }
-
- if(actual != size){
- /*__u64 can be a long on AMD64 and with %lu GCC complains; so
- * the typecast.*/
- printk("Size mismatch (%llu vs %llu) of COW header vs backing "
- "file\n", (unsigned long long) size, actual);
- return -EINVAL;
- }
- if(modtime != mtime){
- printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
- "file\n", mtime, modtime);
- return -EINVAL;
- }
- return 0;
-}
-
-int read_cow_bitmap(int fd, void *buf, int offset, int len)
-{
- int err;
-
- err = os_seek_file(fd, offset);
- if(err < 0)
- return err;
-
- err = os_read_file(fd, buf, len);
- if(err < 0)
- return err;
-
- return 0;
-}
-
-int open_ubd_file(char *file, struct openflags *openflags, int shared,
- char **backing_file_out, int *bitmap_offset_out,
- unsigned long *bitmap_len_out, int *data_offset_out,
- int *create_cow_out)
-{
- time_t mtime;
- unsigned long long size;
- __u32 version, align;
- char *backing_file;
- int fd, err, sectorsize, asked_switch, mode = 0644;
-
- fd = os_open_file(file, *openflags, mode);
- if (fd < 0) {
- if ((fd == -ENOENT) && (create_cow_out != NULL))
- *create_cow_out = 1;
- if (!openflags->w ||
- ((fd != -EROFS) && (fd != -EACCES)))
- return fd;
- openflags->w = 0;
- fd = os_open_file(file, *openflags, mode);
- if (fd < 0)
- return fd;
- }
-
- if(shared)
- printk("Not locking \"%s\" on the host\n", file);
- else {
- err = os_lock_file(fd, openflags->w);
- if(err < 0){
- printk("Failed to lock '%s', err = %d\n", file, -err);
- goto out_close;
- }
- }
-
- /* Successful return case! */
- if(backing_file_out == NULL)
- return fd;
-
- err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
- &size, &sectorsize, &align, bitmap_offset_out);
- if(err && (*backing_file_out != NULL)){
- printk("Failed to read COW header from COW file \"%s\", "
- "errno = %d\n", file, -err);
- goto out_close;
- }
- if(err)
- return fd;
-
- asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
-
- /* Allow switching only if no mismatch. */
- if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {
- printk("Switching backing file to '%s'\n", *backing_file_out);
- err = write_cow_header(file, fd, *backing_file_out,
- sectorsize, align, &size);
- if (err) {
- printk("Switch failed, errno = %d\n", -err);
- goto out_close;
- }
- } else {
- *backing_file_out = backing_file;
- err = backing_file_mismatch(*backing_file_out, size, mtime);
- if (err)
- goto out_close;
- }
-
- cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
- bitmap_len_out, data_offset_out);
-
- return fd;
- out_close:
- os_close_file(fd);
- return err;
-}
-
-int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
- int sectorsize, int alignment, int *bitmap_offset_out,
- unsigned long *bitmap_len_out, int *data_offset_out)
-{
- int err, fd;
-
- flags.c = 1;
- fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);
- if(fd < 0){
- err = fd;
- printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
- -err);
- goto out;
- }
-
- err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
- bitmap_offset_out, bitmap_len_out,
- data_offset_out);
- if(!err)
- return fd;
- os_close_file(fd);
- out:
- return err;
-}
-
static int update_bitmap(struct io_thread_req *req)
{
int n;
@@ -1369,7 +1364,7 @@ static int update_bitmap(struct io_thread_req *req)
return 0;
}
-void do_io(struct io_thread_req *req)
+static void do_io(struct io_thread_req *req)
{
char *buf;
unsigned long len;
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
index 624b5100a3cd..1e651457e049 100644
--- a/arch/um/include/chan_kern.h
+++ b/arch/um/include/chan_kern.h
@@ -31,7 +31,6 @@ extern void chan_interrupt(struct list_head *chans, struct delayed_work *task,
struct tty_struct *tty, int irq);
extern int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts, char **error_out);
-extern int open_chan(struct list_head *chans);
extern int write_chan(struct list_head *chans, const char *buf, int len,
int write_irq);
extern int console_write_chan(struct list_head *chans, const char *buf,
@@ -45,7 +44,6 @@ extern void close_chan(struct list_head *chans, int delay_free_irq);
extern int chan_window_size(struct list_head *chans,
unsigned short *rows_out,
unsigned short *cols_out);
-extern int chan_out_fd(struct list_head *chans);
extern int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out);
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index a6c1dd1cf5a1..56deed623446 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -115,7 +115,7 @@ static int have_root __initdata = 0;
/* Set in uml_mem_setup and modified in linux_main */
long long physmem_size = 32 * 1024 * 1024;
-static char *usage_string =
+static const char *usage_string =
"User Mode Linux v%s\n"
" available at http://user-mode-linux.sourceforge.net/\n\n";
@@ -202,7 +202,7 @@ static void __init uml_checksetup(char *line, int *add)
p = &__uml_setup_start;
while (p < &__uml_setup_end) {
- int n;
+ size_t n;
n = strlen(p->str);
if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
@@ -258,7 +258,8 @@ int __init linux_main(int argc, char **argv)
{
unsigned long avail, diff;
unsigned long virtmem_size, max_physmem;
- unsigned int i, add;
+ unsigned int i;
+ int add;
char * mode;
for (i = 1; i < argc; i++) {
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index f4bd349d4412..f25c29a12d00 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -14,6 +14,7 @@
#include "os.h"
#include "um_malloc.h"
#include "user.h"
+#include <linux/limits.h>
struct helper_data {
void (*pre_exec)(void*);
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index b616e15638fb..997d01944f91 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -25,15 +25,15 @@
#include "registers.h"
#include "skas_ptrace.h"
-static int ptrace_child(void)
+static void ptrace_child(void)
{
int ret;
/* Calling os_getpid because some libcs cached getpid incorrectly */
int pid = os_getpid(), ppid = getppid();
int sc_result;
- change_sig(SIGWINCH, 0);
- if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
+ if (change_sig(SIGWINCH, 0) < 0 ||
+ ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
perror("ptrace");
kill(pid, SIGKILL);
}
@@ -75,9 +75,8 @@ static void fatal(char *fmt, ...)
va_list list;
va_start(list, fmt);
- vprintf(fmt, list);
+ vfprintf(stderr, fmt, list);
va_end(list);
- fflush(stdout);
exit(1);
}
@@ -87,9 +86,8 @@ static void non_fatal(char *fmt, ...)
va_list list;
va_start(list, fmt);
- vprintf(fmt, list);
+ vfprintf(stderr, fmt, list);
va_end(list);
- fflush(stdout);
}
static int start_ptraced_child(void)
@@ -495,7 +493,7 @@ int __init parse_iomem(char *str, int *add)
driver = str;
file = strchr(str,',');
if (file == NULL) {
- printf("parse_iomem : failed to parse iomem\n");
+ fprintf(stderr, "parse_iomem : failed to parse iomem\n");
goto out;
}
*file = '\0';
diff --git a/arch/um/os-Linux/sys-i386/task_size.c b/arch/um/os-Linux/sys-i386/task_size.c
index 48d211b3d9a1..ccb49b0aff59 100644
--- a/arch/um/os-Linux/sys-i386/task_size.c
+++ b/arch/um/os-Linux/sys-i386/task_size.c
@@ -88,7 +88,10 @@ unsigned long os_get_task_size(void)
sa.sa_handler = segfault;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NODEFER;
- sigaction(SIGSEGV, &sa, &old);
+ if (sigaction(SIGSEGV, &sa, &old)) {
+ perror("os_get_task_size");
+ exit(1);
+ }
if (!page_ok(bottom)) {
fprintf(stderr, "Address 0x%x no good?\n",
@@ -110,11 +113,12 @@ unsigned long os_get_task_size(void)
out:
/* Restore the old SIGSEGV handling */
- sigaction(SIGSEGV, &old, NULL);
-
+ if (sigaction(SIGSEGV, &old, NULL)) {
+ perror("os_get_task_size");
+ exit(1);
+ }
top <<= UM_KERN_PAGE_SHIFT;
printf("0x%x\n", top);
- fflush(stdout);
return top;
}
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 964dc1a04c37..598b5c1903af 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -6,7 +6,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \
sys_call_table.o tls.o
-subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o
+subarch-obj-y = lib/semaphore_32.o lib/string_32.o
subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 3c22de532088..c8b4cce9cfe1 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -10,7 +10,7 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
obj-$(CONFIG_MODULES) += um_module.o
-subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
+subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o
ldt-y = ../sys-i386/ldt.o
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 4d350b5cbc71..a12dbb2b93f3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -86,9 +86,6 @@ config GENERIC_GPIO
config ARCH_MAY_HAVE_PC_FDC
def_bool y
-config DMI
- def_bool y
-
config RWSEM_GENERIC_SPINLOCK
def_bool !X86_XADD
@@ -114,6 +111,9 @@ config GENERIC_TIME_VSYSCALL
config ARCH_HAS_CPU_RELAX
def_bool y
+config ARCH_HAS_CACHE_LINE_SIZE
+ def_bool y
+
config HAVE_SETUP_PER_CPU_AREA
def_bool X86_64 || (X86_SMP && !X86_VOYAGER)
@@ -142,6 +142,9 @@ config AUDIT_ARCH
config ARCH_SUPPORTS_AOUT
def_bool y
+config ARCH_SUPPORTS_OPTIMIZED_INLINING
+ def_bool y
+
# Use the generic interrupt handling code in kernel/irq/:
config GENERIC_HARDIRQS
bool
@@ -370,6 +373,25 @@ config VMI
at the moment), by linking the kernel to a GPL-ed ROM module
provided by the hypervisor.
+config KVM_CLOCK
+ bool "KVM paravirtualized clock"
+ select PARAVIRT
+ depends on !(X86_VISWS || X86_VOYAGER)
+ help
+ Turning on this option will allow you to run a paravirtualized clock
+ when running over the KVM hypervisor. Instead of relying on a PIT
+ (or probably other) emulation by the underlying device model, the host
+ provides the guest with timing infrastructure such as time of day, and
+ system time
+
+config KVM_GUEST
+ bool "KVM Guest support"
+ select PARAVIRT
+ depends on !(X86_VISWS || X86_VOYAGER)
+ help
+ This option enables various optimizations for running under the KVM
+ hypervisor.
+
source "arch/x86/lguest/Kconfig"
config PARAVIRT
@@ -460,6 +482,15 @@ config HPET_EMULATE_RTC
# Mark as embedded because too many people got it wrong.
# The code disables itself when not needed.
+config DMI
+ default y
+ bool "Enable DMI scanning" if EMBEDDED
+ help
+ Enabled scanning of DMI to identify machine quirks. Say Y
+ here unless you have verified that your setup is not
+ affected by entries in the DMI blacklist. Required by PNP
+ BIOS code.
+
config GART_IOMMU
bool "GART IOMMU support" if EMBEDDED
default y
@@ -1049,9 +1080,9 @@ config MTRR
See <file:Documentation/mtrr.txt> for more information.
config X86_PAT
- def_bool y
+ bool
prompt "x86 PAT support"
- depends on MTRR && NONPROMISC_DEVMEM
+ depends on MTRR
help
Use PAT attributes to setup page level cache control.
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 57072f2716f9..7ef18b01f0bc 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -21,8 +21,8 @@ config M386
Here are the settings recommended for greatest speed:
- "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
- 486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels
- will run on a 386 class machine.
+ 486DLC/DLC2, and UMC 486SX-S. Only "386" kernels will run on a 386
+ class machine.
- "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S.
- "586" for generic Pentium CPUs lacking the TSC
@@ -278,6 +278,11 @@ config GENERIC_CPU
endchoice
+config X86_CPU
+ def_bool y
+ select GENERIC_FIND_FIRST_BIT
+ select GENERIC_FIND_NEXT_BIT
+
config X86_GENERIC
bool "Generic x86 support"
depends on X86_32
@@ -398,7 +403,7 @@ config X86_TSC
# generates cmov.
config X86_CMOV
def_bool y
- depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7)
+ depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64)
config X86_MINIMUM_CPU_FAMILY
int
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 610aaecc19f8..5b1979a45a1e 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -5,6 +5,17 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
+config NONPROMISC_DEVMEM
+ bool "Disable promiscuous /dev/mem"
+ help
+ The /dev/mem file by default only allows userspace access to PCI
+ space and the BIOS code and data regions. This is sufficient for
+ dosemu and X and all common users of /dev/mem. With this config
+ option, you allow userspace access to all of memory, including
+ kernel and userspace memory. Accidental access to this is
+ obviously disasterous, but specific access can be used by people
+ debugging the kernel.
+
config EARLY_PRINTK
bool "Early printk" if EMBEDDED
default y
@@ -246,3 +257,16 @@ config CPA_DEBUG
Do change_page_attr() self-tests every 30 seconds.
endmenu
+
+config OPTIMIZE_INLINING
+ bool "Allow gcc to uninline functions marked 'inline'"
+ default y
+ help
+ This option determines if the kernel forces gcc to inline the functions
+ developers have marked 'inline'. Doing so takes away freedom from gcc to
+ do what it thinks is best, which is desirable for the gcc 3.x series of
+ compilers. The gcc 4.x series have a rewritten inlining algorithm and
+ disabling this option will generate a smaller kernel there. Hopefully
+ this algorithm is so good that allowing gcc4 to make the decision can
+ become the default in the future, until then this option is there to
+ test gcc for this.
diff --git a/arch/x86/boot/.gitignore b/arch/x86/boot/.gitignore
index b1bdc4c6f9f2..172cf8a98bdd 100644
--- a/arch/x86/boot/.gitignore
+++ b/arch/x86/boot/.gitignore
@@ -1,7 +1,8 @@
bootsect
bzImage
+cpustr.h
+mkcpustr
+offsets.h
setup
setup.bin
setup.elf
-cpustr.h
-mkcpustr
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 6d2df8d61c54..af86e431acfa 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -120,7 +120,7 @@ _start:
# Part 2 of the header, from the old setup.S
.ascii "HdrS" # header signature
- .word 0x0208 # header version number (>= 0x0105)
+ .word 0x0209 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -227,6 +227,10 @@ hardware_subarch_data: .quad 0
payload_offset: .long input_data
payload_length: .long input_data_end-input_data
+setup_data: .quad 0 # 64-bit physical pointer to
+ # single linked list of
+ # struct setup_data
+
# End of setup header #####################################################
.section ".inittext", "ax"
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 3df340b54e57..ad7ddaaff588 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -1421,6 +1421,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
+CONFIG_OPTIMIZE_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index eef98cb00c62..2d6f5b2809d2 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -1346,6 +1346,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
+CONFIG_OPTIMIZE_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 05e155d3fb6c..bbed3a26ce55 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -499,11 +499,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
regs->cs = __USER32_CS;
regs->ss = __USER32_DS;
- set_fs(USER_DS);
- regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF);
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#if DEBUG_SIG
printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
current->comm, current->pid, frame, regs->ip, frame->pretcode);
@@ -599,11 +594,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->cs = __USER32_CS;
regs->ss = __USER32_DS;
- set_fs(USER_DS);
- regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF);
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
#if DEBUG_SIG
printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
current->comm, current->pid, frame, regs->ip, frame->pretcode);
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index ae7158bce4d6..b5e329da166c 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -430,7 +430,7 @@ ia32_sys_call_table:
.quad sys_setuid16
.quad sys_getuid16
.quad compat_sys_stime /* stime */ /* 25 */
- .quad sys32_ptrace /* ptrace */
+ .quad compat_sys_ptrace /* ptrace */
.quad sys_alarm
.quad sys_fstat /* (old)fstat */
.quad sys_pause
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 90e092d0af0c..fa19c3819540 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -80,6 +80,8 @@ obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o
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
ifdef CONFIG_INPUT_PCSPKR
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 057ccf1d5ad4..977ed5cdeaa3 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -697,10 +697,6 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
#define HPET_RESOURCE_NAME_SIZE 9
hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
- if (!hpet_res)
- return 0;
-
- memset(hpet_res, 0, sizeof(*hpet_res));
hpet_res->name = (void *)&hpet_res[1];
hpet_res->flags = IORESOURCE_MEM;
snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
diff --git a/arch/x86/kernel/acpi/realmode/.gitignore b/arch/x86/kernel/acpi/realmode/.gitignore
new file mode 100644
index 000000000000..58f1f48a58f8
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/.gitignore
@@ -0,0 +1,3 @@
+wakeup.bin
+wakeup.elf
+wakeup.lds
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index df4099dc1c68..65c7857a90dd 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -511,31 +511,30 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
unsigned long flags;
char *vaddr;
int nr_pages = 2;
+ struct page *pages[2];
+ int i;
- BUG_ON(len > sizeof(long));
- BUG_ON((((long)addr + len - 1) & ~(sizeof(long) - 1))
- - ((long)addr & ~(sizeof(long) - 1)));
- if (kernel_text_address((unsigned long)addr)) {
- struct page *pages[2] = { virt_to_page(addr),
- virt_to_page(addr + PAGE_SIZE) };
- if (!pages[1])
- nr_pages = 1;
- vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
- BUG_ON(!vaddr);
- local_irq_save(flags);
- memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
- local_irq_restore(flags);
- vunmap(vaddr);
+ if (!core_kernel_text((unsigned long)addr)) {
+ pages[0] = vmalloc_to_page(addr);
+ pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
} else {
- /*
- * modules are in vmalloc'ed memory, always writable.
- */
- local_irq_save(flags);
- memcpy(addr, opcode, len);
- local_irq_restore(flags);
+ pages[0] = virt_to_page(addr);
+ WARN_ON(!PageReserved(pages[0]));
+ pages[1] = virt_to_page(addr + PAGE_SIZE);
}
+ BUG_ON(!pages[0]);
+ if (!pages[1])
+ nr_pages = 1;
+ vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
+ BUG_ON(!vaddr);
+ local_irq_save(flags);
+ memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
+ local_irq_restore(flags);
+ vunmap(vaddr);
sync_core();
/* Could also do a CLFLUSH here to speed up CPU recovery; but
that causes hangs on some VIA CPUs. */
+ for (i = 0; i < len; i++)
+ BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]);
return addr;
}
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 8317401170b8..4b99b1bdeb6c 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -451,7 +451,8 @@ void __init setup_boot_APIC_clock(void)
}
/* Calculate the scaled math multiplication factor */
- lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, 32);
+ lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS,
+ lapic_clockevent.shift);
lapic_clockevent.max_delta_ns =
clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
lapic_clockevent.min_delta_ns =
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index bf83157337e4..5910020c3f24 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -360,7 +360,8 @@ static void __init calibrate_APIC_clock(void)
result / 1000 / 1000, result / 1000 % 1000);
/* Calculate the scaled math multiplication factor */
- lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
+ lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC,
+ lapic_clockevent.shift);
lapic_clockevent.max_delta_ns =
clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
lapic_clockevent.min_delta_ns =
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index f0030a0999c7..bf9290e29013 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -904,6 +904,7 @@ recalc:
original_pm_idle();
else
default_idle();
+ local_irq_disable();
jiffies_since_last_check = jiffies - last_jiffies;
if (jiffies_since_last_check > idle_period)
goto recalc;
@@ -911,6 +912,8 @@ recalc:
if (apm_idle_done)
apm_do_busy();
+
+ local_irq_enable();
}
/**
@@ -1189,19 +1192,6 @@ static int suspend(int vetoable)
int err;
struct apm_user *as;
- if (pm_send_all(PM_SUSPEND, (void *)3)) {
- /* Vetoed */
- if (vetoable) {
- if (apm_info.connection_version > 0x100)
- set_system_power_state(APM_STATE_REJECT);
- err = -EBUSY;
- ignore_sys_suspend = 0;
- printk(KERN_WARNING "apm: suspend was vetoed.\n");
- goto out;
- }
- printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
- }
-
device_suspend(PMSG_SUSPEND);
local_irq_disable();
device_power_down(PMSG_SUSPEND);
@@ -1224,9 +1214,7 @@ static int suspend(int vetoable)
device_power_up();
local_irq_enable();
device_resume();
- pm_send_all(PM_RESUME, (void *)0);
queue_event(APM_NORMAL_RESUME, NULL);
- out:
spin_lock(&user_list_lock);
for (as = user_list; as != NULL; as = as->next) {
as->suspend_wait = 0;
@@ -1337,7 +1325,6 @@ static void check_events(void)
if ((event != APM_NORMAL_RESUME)
|| (ignore_normal_resume == 0)) {
device_resume();
- pm_send_all(PM_RESUME, (void *)0);
queue_event(event, NULL);
}
ignore_normal_resume = 0;
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index ee7c45235e54..a0c6f8190887 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_X86_32) += cyrix.o
obj-$(CONFIG_X86_32) += centaur.o
obj-$(CONFIG_X86_32) += transmeta.o
obj-$(CONFIG_X86_32) += intel.o
-obj-$(CONFIG_X86_32) += nexgen.o
obj-$(CONFIG_X86_32) += umc.o
obj-$(CONFIG_X86_MCE) += mcheck/
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 0173065dc3b7..245866828294 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -343,10 +343,4 @@ static struct cpu_dev amd_cpu_dev __cpuinitdata = {
.c_size_cache = amd_size_cache,
};
-int __init amd_init_cpu(void)
-{
- cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev;
- return 0;
-}
-
cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index e2d870de837c..8db8f73503b3 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -339,6 +339,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
{
struct acpi_cpufreq_data *data = per_cpu(drv_data, cpu);
unsigned int freq;
+ unsigned int cached_freq;
dprintk("get_cur_freq_on_cpu (%d)\n", cpu);
@@ -347,7 +348,16 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
return 0;
}
+ cached_freq = data->freq_table[data->acpi_data->state].frequency;
freq = extract_freq(get_cur_val(&cpumask_of_cpu(cpu)), data);
+ if (freq != cached_freq) {
+ /*
+ * The dreaded BIOS frequency change behind our back.
+ * Force set the frequency on next target call.
+ */
+ data->resume = 1;
+ }
+
dprintk("cur freq = %u\n", freq);
return freq;
diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c
index 9a699ed03598..e07e8c068ae0 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_64.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_64.c
@@ -49,7 +49,7 @@ static int banks;
static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
static unsigned long notify_user;
static int rip_msr;
-static int mce_bootlog = 1;
+static int mce_bootlog = -1;
static atomic_t mce_events;
static char trigger[128];
@@ -471,13 +471,15 @@ static void mce_init(void *dummy)
static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
{
/* This should be disabled by the BIOS, but isn't always */
- if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) {
- /* disable GART TBL walk error reporting, which trips off
- incorrectly with the IOMMU & 3ware & Cerberus. */
- clear_bit(10, &bank[4]);
- /* Lots of broken BIOS around that don't clear them
- by default and leave crap in there. Don't log. */
- mce_bootlog = 0;
+ if (c->x86_vendor == X86_VENDOR_AMD) {
+ if(c->x86 == 15)
+ /* disable GART TBL walk error reporting, which trips off
+ incorrectly with the IOMMU & 3ware & Cerberus. */
+ clear_bit(10, &bank[4]);
+ if(c->x86 <= 17 && mce_bootlog < 0)
+ /* Lots of broken BIOS around that don't clear them
+ by default and leave crap in there. Don't log. */
+ mce_bootlog = 0;
}
}
diff --git a/arch/x86/kernel/cpu/nexgen.c b/arch/x86/kernel/cpu/nexgen.c
deleted file mode 100644
index 5d5e1c134123..000000000000
--- a/arch/x86/kernel/cpu/nexgen.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <asm/processor.h>
-
-#include "cpu.h"
-
-/*
- * Detect a NexGen CPU running without BIOS hypercode new enough
- * to have CPUID. (Thanks to Herbert Oppmann)
- */
-
-static int __cpuinit deep_magic_nexgen_probe(void)
-{
- int ret;
-
- __asm__ __volatile__ (
- " movw $0x5555, %%ax\n"
- " xorw %%dx,%%dx\n"
- " movw $2, %%cx\n"
- " divw %%cx\n"
- " movl $0, %%eax\n"
- " jnz 1f\n"
- " movl $1, %%eax\n"
- "1:\n"
- : "=a" (ret) : : "cx", "dx");
- return ret;
-}
-
-static void __cpuinit init_nexgen(struct cpuinfo_x86 *c)
-{
- c->x86_cache_size = 256; /* A few had 1 MB... */
-}
-
-static void __cpuinit nexgen_identify(struct cpuinfo_x86 *c)
-{
- /* Detect NexGen with old hypercode */
- if (deep_magic_nexgen_probe())
- strcpy(c->x86_vendor_id, "NexGenDriven");
-}
-
-static struct cpu_dev nexgen_cpu_dev __cpuinitdata = {
- .c_vendor = "Nexgen",
- .c_ident = { "NexGenDriven" },
- .c_models = {
- { .vendor = X86_VENDOR_NEXGEN,
- .family = 5,
- .model_names = { [1] = "Nx586" }
- },
- },
- .c_init = init_nexgen,
- .c_identify = nexgen_identify,
-};
-
-int __init nexgen_init_cpu(void)
-{
- cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev;
- return 0;
-}
diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c
index b943e10ad814..f9ae93adffe5 100644
--- a/arch/x86/kernel/cpu/perfctr-watchdog.c
+++ b/arch/x86/kernel/cpu/perfctr-watchdog.c
@@ -614,16 +614,6 @@ static struct wd_ops intel_arch_wd_ops __read_mostly = {
.evntsel = MSR_ARCH_PERFMON_EVENTSEL1,
};
-static struct wd_ops coreduo_wd_ops = {
- .reserve = single_msr_reserve,
- .unreserve = single_msr_unreserve,
- .setup = setup_intel_arch_watchdog,
- .rearm = p6_rearm,
- .stop = single_msr_stop_watchdog,
- .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
- .evntsel = MSR_ARCH_PERFMON_EVENTSEL0,
-};
-
static void probe_nmi_watchdog(void)
{
switch (boot_cpu_data.x86_vendor) {
@@ -637,8 +627,8 @@ static void probe_nmi_watchdog(void)
/* Work around Core Duo (Yonah) errata AE49 where perfctr1
doesn't have a working enable bit. */
if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 14) {
- wd_ops = &coreduo_wd_ops;
- break;
+ intel_arch_wd_ops.perfctr = MSR_ARCH_PERFMON_PERFCTR0;
+ intel_arch_wd_ops.evntsel = MSR_ARCH_PERFMON_EVENTSEL0;
}
if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
wd_ops = &intel_arch_wd_ops;
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 2251d0ae9570..268553817909 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -25,6 +25,7 @@
#include <asm/hpet.h>
#include <linux/kdebug.h>
#include <asm/smp.h>
+#include <asm/reboot.h>
#include <mach_ipi.h>
@@ -117,7 +118,7 @@ static void nmi_shootdown_cpus(void)
}
#endif
-void machine_crash_shutdown(struct pt_regs *regs)
+void native_machine_crash_shutdown(struct pt_regs *regs)
{
/* This function is only called after the system
* has panicked or is otherwise in a critical state.
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
index cbd42e51cb08..645ee5e32a27 100644
--- a/arch/x86/kernel/e820_64.c
+++ b/arch/x86/kernel/e820_64.c
@@ -84,14 +84,41 @@ void __init reserve_early(unsigned long start, unsigned long end, char *name)
strncpy(r->name, name, sizeof(r->name) - 1);
}
-void __init early_res_to_bootmem(void)
+void __init free_early(unsigned long start, unsigned long end)
+{
+ struct early_res *r;
+ int i, j;
+
+ for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+ r = &early_res[i];
+ if (start == r->start && end == r->end)
+ break;
+ }
+ if (i >= MAX_EARLY_RES || !early_res[i].end)
+ panic("free_early on not reserved area: %lx-%lx!", start, end);
+
+ for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++)
+ ;
+
+ memcpy(&early_res[i], &early_res[i + 1],
+ (j - 1 - i) * sizeof(struct early_res));
+
+ early_res[j - 1].end = 0;
+}
+
+void __init early_res_to_bootmem(unsigned long start, unsigned long end)
{
int i;
+ unsigned long final_start, final_end;
for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
struct early_res *r = &early_res[i];
- printk(KERN_INFO "early res: %d [%lx-%lx] %s\n", i,
- r->start, r->end - 1, r->name);
- reserve_bootmem_generic(r->start, r->end - r->start);
+ final_start = max(start, r->start);
+ final_end = min(end, r->end);
+ if (final_start >= final_end)
+ continue;
+ printk(KERN_INFO " early res: %d [%lx-%lx] %s\n", i,
+ final_start, final_end - 1, r->name);
+ reserve_bootmem_generic(final_start, final_end - final_start);
}
}
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index f0f8934fc303..2a609dc3271c 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -409,7 +409,7 @@ restore_nocheck_notrace:
irq_return:
INTERRUPT_RETURN
.section .fixup,"ax"
-iret_exc:
+ENTRY(iret_exc)
pushl $0 # no error code
pushl $do_iret_error
jmp error_code
@@ -1017,6 +1017,13 @@ ENTRY(kernel_thread_helper)
ENDPROC(kernel_thread_helper)
#ifdef CONFIG_XEN
+/* Xen doesn't set %esp to be precisely what the normal sysenter
+ entrypoint expects, so fix it up before using the normal path. */
+ENTRY(xen_sysenter_target)
+ RING0_INT_FRAME
+ addl $5*4, %esp /* remove xen-provided frame */
+ jmp sysenter_past_esp
+
ENTRY(xen_hypervisor_callback)
CFI_STARTPROC
pushl $0
@@ -1035,8 +1042,9 @@ ENTRY(xen_hypervisor_callback)
cmpl $xen_iret_end_crit,%eax
jae 1f
- call xen_iret_crit_fixup
+ jmp xen_iret_crit_fixup
+ENTRY(xen_do_upcall)
1: mov %esp, %eax
call xen_evtchn_do_upcall
jmp ret_from_intr
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c
index 9546ef408b92..021624c83583 100644
--- a/arch/x86/kernel/genapic_64.c
+++ b/arch/x86/kernel/genapic_64.c
@@ -51,7 +51,7 @@ void __init setup_apic_routing(void)
else
#endif
- if (cpus_weight(cpu_possible_map) <= 8)
+ if (num_possible_cpus() <= 8)
genapic = &apic_flat;
else
genapic = &apic_physflat;
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 993c76773256..e25c57b8aa84 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -11,6 +11,7 @@
#include <linux/string.h>
#include <linux/percpu.h>
#include <linux/start_kernel.h>
+#include <linux/io.h>
#include <asm/processor.h>
#include <asm/proto.h>
@@ -22,6 +23,7 @@
#include <asm/sections.h>
#include <asm/kdebug.h>
#include <asm/e820.h>
+#include <asm/bios_ebda.h>
static void __init zap_identity_mappings(void)
{
@@ -49,7 +51,6 @@ static void __init copy_bootdata(char *real_mode_data)
}
}
-#define BIOS_EBDA_SEGMENT 0x40E
#define BIOS_LOWMEM_KILOBYTES 0x413
/*
@@ -80,8 +81,7 @@ static void __init reserve_ebda_region(void)
lowmem <<= 10;
/* start of EBDA area */
- ebda_addr = *(unsigned short *)__va(BIOS_EBDA_SEGMENT);
- ebda_addr <<= 4;
+ ebda_addr = get_bios_ebda();
/* Fixup: bios puts an EBDA in the top 64K segment */
/* of conventional memory, but does not adjust lowmem. */
@@ -101,6 +101,24 @@ static void __init reserve_ebda_region(void)
reserve_early(lowmem, 0x100000, "BIOS reserved");
}
+static void __init reserve_setup_data(void)
+{
+ struct setup_data *data;
+ unsigned long pa_data;
+ char buf[32];
+
+ if (boot_params.hdr.version < 0x0209)
+ return;
+ pa_data = boot_params.hdr.setup_data;
+ while (pa_data) {
+ data = early_ioremap(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;
+ early_iounmap(data, sizeof(*data));
+ }
+}
+
void __init x86_64_start_kernel(char * real_mode_data)
{
int i;
@@ -157,6 +175,7 @@ void __init x86_64_start_kernel(char * real_mode_data)
#endif
reserve_ebda_region();
+ reserve_setup_data();
/*
* At this point everything still needed from the boot loader
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 36652ea1a265..9007f9ea64ee 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -218,7 +218,7 @@ static void hpet_legacy_clockevent_register(void)
hpet_freq = 1000000000000000ULL;
do_div(hpet_freq, hpet_period);
hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
- NSEC_PER_SEC, 32);
+ NSEC_PER_SEC, hpet_clockevent.shift);
/* Calculate the min / max delta */
hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
&hpet_clockevent);
diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c
index 8540abe86ade..c1b5e3ece1f2 100644
--- a/arch/x86/kernel/i8253.c
+++ b/arch/x86/kernel/i8253.c
@@ -115,7 +115,8 @@ void __init setup_pit_timer(void)
* IO_APIC has been initialized.
*/
pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
- pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
+ pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
+ pit_clockevent.shift);
pit_clockevent.max_delta_ns =
clockevent_delta2ns(0x7FFF, &pit_clockevent);
pit_clockevent.min_delta_ns =
@@ -224,7 +225,8 @@ static int __init init_pit_clocksource(void)
pit_clockevent.mode != CLOCK_EVT_MODE_PERIODIC)
return 0;
- clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
+ clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
+ clocksource_pit.shift);
return clocksource_register(&clocksource_pit);
}
arch_initcall(init_pit_clocksource);
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c
index 2e2f42074e18..a40d54fc1fdd 100644
--- a/arch/x86/kernel/io_apic_32.c
+++ b/arch/x86/kernel/io_apic_32.c
@@ -2068,7 +2068,7 @@ static void __init setup_nmi(void)
* cycles as some i82489DX-based boards have glue logic that keeps the
* 8259A interrupt line asserted until INTA. --macro
*/
-static inline void unlock_ExtINT_logic(void)
+static inline void __init unlock_ExtINT_logic(void)
{
int apic, pin, i;
struct IO_APIC_route_entry entry0, entry1;
@@ -2444,6 +2444,7 @@ void destroy_irq(unsigned int irq)
dynamic_irq_cleanup(irq);
spin_lock_irqsave(&vector_lock, flags);
+ clear_bit(irq_vector[irq], used_vectors);
irq_vector[irq] = 0;
spin_unlock_irqrestore(&vector_lock, flags);
}
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index 9ba11d07920f..ef1a8dfcc529 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -1599,7 +1599,7 @@ static void __init setup_nmi(void)
* cycles as some i82489DX-based boards have glue logic that keeps the
* 8259A interrupt line asserted until INTA. --macro
*/
-static inline void unlock_ExtINT_logic(void)
+static inline void __init unlock_ExtINT_logic(void)
{
int apic, pin, i;
struct IO_APIC_route_entry entry0, entry1;
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 6ea67b76a214..00bda7bcda63 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -134,7 +134,7 @@ unsigned int do_IRQ(struct pt_regs *regs)
: "=a" (arg1), "=d" (arg2), "=b" (bx)
: "0" (irq), "1" (desc), "2" (isp),
"D" (desc->handle_irq)
- : "memory", "cc"
+ : "memory", "cc", "ecx"
);
} else
#endif
diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c
index 73354302fda7..c03205991718 100644
--- a/arch/x86/kernel/kdebugfs.c
+++ b/arch/x86/kernel/kdebugfs.c
@@ -6,23 +6,171 @@
*
* This file is released under the GPLv2.
*/
-
#include <linux/debugfs.h>
+#include <linux/uaccess.h>
#include <linux/stat.h>
#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mm.h>
#include <asm/setup.h>
#ifdef CONFIG_DEBUG_BOOT_PARAMS
+struct setup_data_node {
+ u64 paddr;
+ u32 type;
+ u32 len;
+};
+
+static ssize_t
+setup_data_read(struct file *file, char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct setup_data_node *node = file->private_data;
+ unsigned long remain;
+ loff_t pos = *ppos;
+ struct page *pg;
+ void *p;
+ u64 pa;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= node->len)
+ return 0;
+
+ if (count > node->len - pos)
+ count = node->len - pos;
+ pa = node->paddr + sizeof(struct setup_data) + pos;
+ pg = pfn_to_page((pa + count - 1) >> PAGE_SHIFT);
+ if (PageHighMem(pg)) {
+ p = ioremap_cache(pa, count);
+ if (!p)
+ return -ENXIO;
+ } else {
+ p = __va(pa);
+ }
+
+ remain = copy_to_user(user_buf, p, count);
+
+ if (PageHighMem(pg))
+ iounmap(p);
+
+ if (remain)
+ return -EFAULT;
+
+ *ppos = pos + count;
+
+ return count;
+}
+
+static int setup_data_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations fops_setup_data = {
+ .read = setup_data_read,
+ .open = setup_data_open,
+};
+
+static int __init
+create_setup_data_node(struct dentry *parent, int no,
+ struct setup_data_node *node)
+{
+ struct dentry *d, *type, *data;
+ char buf[16];
+ int error;
+
+ sprintf(buf, "%d", no);
+ d = debugfs_create_dir(buf, parent);
+ if (!d) {
+ error = -ENOMEM;
+ goto err_return;
+ }
+ type = debugfs_create_x32("type", S_IRUGO, d, &node->type);
+ if (!type) {
+ error = -ENOMEM;
+ goto err_dir;
+ }
+ data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
+ if (!data) {
+ error = -ENOMEM;
+ goto err_type;
+ }
+ return 0;
+
+err_type:
+ debugfs_remove(type);
+err_dir:
+ debugfs_remove(d);
+err_return:
+ return error;
+}
+
+static int __init create_setup_data_nodes(struct dentry *parent)
+{
+ struct setup_data_node *node;
+ struct setup_data *data;
+ int error, no = 0;
+ struct dentry *d;
+ struct page *pg;
+ u64 pa_data;
+
+ d = debugfs_create_dir("setup_data", parent);
+ if (!d) {
+ error = -ENOMEM;
+ goto err_return;
+ }
+
+ pa_data = boot_params.hdr.setup_data;
+
+ while (pa_data) {
+ node = kmalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ error = -ENOMEM;
+ goto err_dir;
+ }
+ pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT);
+ if (PageHighMem(pg)) {
+ data = ioremap_cache(pa_data, sizeof(*data));
+ if (!data) {
+ error = -ENXIO;
+ goto err_dir;
+ }
+ } else {
+ data = __va(pa_data);
+ }
+
+ node->paddr = pa_data;
+ node->type = data->type;
+ node->len = data->len;
+ error = create_setup_data_node(d, no, node);
+ pa_data = data->next;
+
+ if (PageHighMem(pg))
+ iounmap(data);
+ if (error)
+ goto err_dir;
+ no++;
+ }
+ return 0;
+
+err_dir:
+ debugfs_remove(d);
+err_return:
+ return error;
+}
+
static struct debugfs_blob_wrapper boot_params_blob = {
- .data = &boot_params,
- .size = sizeof(boot_params),
+ .data = &boot_params,
+ .size = sizeof(boot_params),
};
static int __init boot_params_kdebugfs_init(void)
{
- int error;
struct dentry *dbp, *version, *data;
+ int error;
dbp = debugfs_create_dir("boot_params", NULL);
if (!dbp) {
@@ -41,7 +189,13 @@ static int __init boot_params_kdebugfs_init(void)
error = -ENOMEM;
goto err_version;
}
+ error = create_setup_data_nodes(dbp);
+ if (error)
+ goto err_data;
return 0;
+
+err_data:
+ debugfs_remove(data);
err_version:
debugfs_remove(version);
err_dir:
@@ -61,5 +215,4 @@ static int __init arch_kdebugfs_init(void)
return error;
}
-
arch_initcall(arch_kdebugfs_init);
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
new file mode 100644
index 000000000000..8b7a3cf37d2b
--- /dev/null
+++ b/arch/x86/kernel/kvm.c
@@ -0,0 +1,248 @@
+/*
+ * KVM paravirt_ops implementation
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) 2007, Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright IBM Corporation, 2007
+ * Authors: Anthony Liguori <aliguori@us.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kvm_para.h>
+#include <linux/cpu.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/hardirq.h>
+
+#define MMU_QUEUE_SIZE 1024
+
+struct kvm_para_state {
+ u8 mmu_queue[MMU_QUEUE_SIZE];
+ int mmu_queue_len;
+ enum paravirt_lazy_mode mode;
+};
+
+static DEFINE_PER_CPU(struct kvm_para_state, para_state);
+
+static struct kvm_para_state *kvm_para_state(void)
+{
+ return &per_cpu(para_state, raw_smp_processor_id());
+}
+
+/*
+ * No need for any "IO delay" on KVM
+ */
+static void kvm_io_delay(void)
+{
+}
+
+static void kvm_mmu_op(void *buffer, unsigned len)
+{
+ int r;
+ unsigned long a1, a2;
+
+ do {
+ a1 = __pa(buffer);
+ a2 = 0; /* on i386 __pa() always returns <4G */
+ r = kvm_hypercall3(KVM_HC_MMU_OP, len, a1, a2);
+ buffer += r;
+ len -= r;
+ } while (len);
+}
+
+static void mmu_queue_flush(struct kvm_para_state *state)
+{
+ if (state->mmu_queue_len) {
+ kvm_mmu_op(state->mmu_queue, state->mmu_queue_len);
+ state->mmu_queue_len = 0;
+ }
+}
+
+static void kvm_deferred_mmu_op(void *buffer, int len)
+{
+ struct kvm_para_state *state = kvm_para_state();
+
+ if (state->mode != PARAVIRT_LAZY_MMU) {
+ kvm_mmu_op(buffer, len);
+ return;
+ }
+ if (state->mmu_queue_len + len > sizeof state->mmu_queue)
+ mmu_queue_flush(state);
+ memcpy(state->mmu_queue + state->mmu_queue_len, buffer, len);
+ state->mmu_queue_len += len;
+}
+
+static void kvm_mmu_write(void *dest, u64 val)
+{
+ __u64 pte_phys;
+ struct kvm_mmu_op_write_pte wpte;
+
+#ifdef CONFIG_HIGHPTE
+ struct page *page;
+ unsigned long dst = (unsigned long) dest;
+
+ page = kmap_atomic_to_page(dest);
+ pte_phys = page_to_pfn(page);
+ pte_phys <<= PAGE_SHIFT;
+ pte_phys += (dst & ~(PAGE_MASK));
+#else
+ pte_phys = (unsigned long)__pa(dest);
+#endif
+ wpte.header.op = KVM_MMU_OP_WRITE_PTE;
+ wpte.pte_val = val;
+ wpte.pte_phys = pte_phys;
+
+ kvm_deferred_mmu_op(&wpte, sizeof wpte);
+}
+
+/*
+ * We only need to hook operations that are MMU writes. We hook these so that
+ * we can use lazy MMU mode to batch these operations. We could probably
+ * improve the performance of the host code if we used some of the information
+ * here to simplify processing of batched writes.
+ */
+static void kvm_set_pte(pte_t *ptep, pte_t pte)
+{
+ kvm_mmu_write(ptep, pte_val(pte));
+}
+
+static void kvm_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ kvm_mmu_write(ptep, pte_val(pte));
+}
+
+static void kvm_set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+ kvm_mmu_write(pmdp, pmd_val(pmd));
+}
+
+#if PAGETABLE_LEVELS >= 3
+#ifdef CONFIG_X86_PAE
+static void kvm_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+ kvm_mmu_write(ptep, pte_val(pte));
+}
+
+static void kvm_set_pte_present(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ kvm_mmu_write(ptep, pte_val(pte));
+}
+
+static void kvm_pte_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ kvm_mmu_write(ptep, 0);
+}
+
+static void kvm_pmd_clear(pmd_t *pmdp)
+{
+ kvm_mmu_write(pmdp, 0);
+}
+#endif
+
+static void kvm_set_pud(pud_t *pudp, pud_t pud)
+{
+ kvm_mmu_write(pudp, pud_val(pud));
+}
+
+#if PAGETABLE_LEVELS == 4
+static void kvm_set_pgd(pgd_t *pgdp, pgd_t pgd)
+{
+ kvm_mmu_write(pgdp, pgd_val(pgd));
+}
+#endif
+#endif /* PAGETABLE_LEVELS >= 3 */
+
+static void kvm_flush_tlb(void)
+{
+ struct kvm_mmu_op_flush_tlb ftlb = {
+ .header.op = KVM_MMU_OP_FLUSH_TLB,
+ };
+
+ kvm_deferred_mmu_op(&ftlb, sizeof ftlb);
+}
+
+static void kvm_release_pt(u32 pfn)
+{
+ struct kvm_mmu_op_release_pt rpt = {
+ .header.op = KVM_MMU_OP_RELEASE_PT,
+ .pt_phys = (u64)pfn << PAGE_SHIFT,
+ };
+
+ kvm_mmu_op(&rpt, sizeof rpt);
+}
+
+static void kvm_enter_lazy_mmu(void)
+{
+ struct kvm_para_state *state = kvm_para_state();
+
+ paravirt_enter_lazy_mmu();
+ state->mode = paravirt_get_lazy_mode();
+}
+
+static void kvm_leave_lazy_mmu(void)
+{
+ struct kvm_para_state *state = kvm_para_state();
+
+ mmu_queue_flush(state);
+ paravirt_leave_lazy(paravirt_get_lazy_mode());
+ state->mode = paravirt_get_lazy_mode();
+}
+
+static void paravirt_ops_setup(void)
+{
+ pv_info.name = "KVM";
+ pv_info.paravirt_enabled = 1;
+
+ if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY))
+ pv_cpu_ops.io_delay = kvm_io_delay;
+
+ if (kvm_para_has_feature(KVM_FEATURE_MMU_OP)) {
+ pv_mmu_ops.set_pte = kvm_set_pte;
+ pv_mmu_ops.set_pte_at = kvm_set_pte_at;
+ pv_mmu_ops.set_pmd = kvm_set_pmd;
+#if PAGETABLE_LEVELS >= 3
+#ifdef CONFIG_X86_PAE
+ pv_mmu_ops.set_pte_atomic = kvm_set_pte_atomic;
+ pv_mmu_ops.set_pte_present = kvm_set_pte_present;
+ pv_mmu_ops.pte_clear = kvm_pte_clear;
+ pv_mmu_ops.pmd_clear = kvm_pmd_clear;
+#endif
+ pv_mmu_ops.set_pud = kvm_set_pud;
+#if PAGETABLE_LEVELS == 4
+ pv_mmu_ops.set_pgd = kvm_set_pgd;
+#endif
+#endif
+ pv_mmu_ops.flush_tlb_user = kvm_flush_tlb;
+ pv_mmu_ops.release_pte = kvm_release_pt;
+ pv_mmu_ops.release_pmd = kvm_release_pt;
+ pv_mmu_ops.release_pud = kvm_release_pt;
+
+ pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu;
+ pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu;
+ }
+}
+
+void __init kvm_guest_init(void)
+{
+ if (!kvm_para_available())
+ return;
+
+ paravirt_ops_setup();
+}
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
new file mode 100644
index 000000000000..ddee04043aeb
--- /dev/null
+++ b/arch/x86/kernel/kvmclock.c
@@ -0,0 +1,187 @@
+/* KVM paravirtual clock driver. A clocksource implementation
+ Copyright (C) 2008 Glauber de Oliveira Costa, Red Hat Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <linux/clocksource.h>
+#include <linux/kvm_para.h>
+#include <asm/arch_hooks.h>
+#include <asm/msr.h>
+#include <asm/apic.h>
+#include <linux/percpu.h>
+#include <asm/reboot.h>
+
+#define KVM_SCALE 22
+
+static int kvmclock = 1;
+
+static int parse_no_kvmclock(char *arg)
+{
+ kvmclock = 0;
+ return 0;
+}
+early_param("no-kvmclock", parse_no_kvmclock);
+
+/* The hypervisor will put information about time periodically here */
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct kvm_vcpu_time_info, hv_clock);
+#define get_clock(cpu, field) per_cpu(hv_clock, cpu).field
+
+static inline u64 kvm_get_delta(u64 last_tsc)
+{
+ int cpu = smp_processor_id();
+ u64 delta = native_read_tsc() - last_tsc;
+ return (delta * get_clock(cpu, tsc_to_system_mul)) >> KVM_SCALE;
+}
+
+static struct kvm_wall_clock wall_clock;
+static cycle_t kvm_clock_read(void);
+/*
+ * The wallclock is the time of day when we booted. Since then, some time may
+ * have elapsed since the hypervisor wrote the data. So we try to account for
+ * that with system time
+ */
+unsigned long kvm_get_wallclock(void)
+{
+ u32 wc_sec, wc_nsec;
+ u64 delta;
+ struct timespec ts;
+ int version, nsec;
+ int low, high;
+
+ low = (int)__pa(&wall_clock);
+ high = ((u64)__pa(&wall_clock) >> 32);
+
+ delta = kvm_clock_read();
+
+ native_write_msr(MSR_KVM_WALL_CLOCK, low, high);
+ do {
+ version = wall_clock.wc_version;
+ rmb();
+ wc_sec = wall_clock.wc_sec;
+ wc_nsec = wall_clock.wc_nsec;
+ rmb();
+ } while ((wall_clock.wc_version != version) || (version & 1));
+
+ delta = kvm_clock_read() - delta;
+ delta += wc_nsec;
+ nsec = do_div(delta, NSEC_PER_SEC);
+ set_normalized_timespec(&ts, wc_sec + delta, nsec);
+ /*
+ * Of all mechanisms of time adjustment I've tested, this one
+ * was the champion!
+ */
+ return ts.tv_sec + 1;
+}
+
+int kvm_set_wallclock(unsigned long now)
+{
+ return 0;
+}
+
+/*
+ * This is our read_clock function. The host puts an tsc timestamp each time
+ * it updates a new time. Without the tsc adjustment, we can have a situation
+ * in which a vcpu starts to run earlier (smaller system_time), but probes
+ * time later (compared to another vcpu), leading to backwards time
+ */
+static cycle_t kvm_clock_read(void)
+{
+ u64 last_tsc, now;
+ int cpu;
+
+ preempt_disable();
+ cpu = smp_processor_id();
+
+ last_tsc = get_clock(cpu, tsc_timestamp);
+ now = get_clock(cpu, system_time);
+
+ now += kvm_get_delta(last_tsc);
+ preempt_enable();
+
+ return now;
+}
+static struct clocksource kvm_clock = {
+ .name = "kvm-clock",
+ .read = kvm_clock_read,
+ .rating = 400,
+ .mask = CLOCKSOURCE_MASK(64),
+ .mult = 1 << KVM_SCALE,
+ .shift = KVM_SCALE,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int kvm_register_clock(void)
+{
+ int cpu = smp_processor_id();
+ int low, high;
+ low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1;
+ high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
+
+ return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high);
+}
+
+static void kvm_setup_secondary_clock(void)
+{
+ /*
+ * Now that the first cpu already had this clocksource initialized,
+ * we shouldn't fail.
+ */
+ WARN_ON(kvm_register_clock());
+ /* ok, done with our trickery, call native */
+ setup_secondary_APIC_clock();
+}
+
+/*
+ * After the clock is registered, the host will keep writing to the
+ * registered memory location. If the guest happens to shutdown, this memory
+ * won't be valid. In cases like kexec, in which you install a new kernel, this
+ * means a random memory location will be kept being written. So before any
+ * kind of shutdown from our side, we unregister the clock by writting anything
+ * that does not have the 'enable' bit set in the msr
+ */
+#ifdef CONFIG_KEXEC
+static void kvm_crash_shutdown(struct pt_regs *regs)
+{
+ native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0);
+ native_machine_crash_shutdown(regs);
+}
+#endif
+
+static void kvm_shutdown(void)
+{
+ native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0);
+ native_machine_shutdown();
+}
+
+void __init kvmclock_init(void)
+{
+ if (!kvm_para_available())
+ return;
+
+ if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
+ if (kvm_register_clock())
+ return;
+ pv_time_ops.get_wallclock = kvm_get_wallclock;
+ pv_time_ops.set_wallclock = kvm_set_wallclock;
+ pv_time_ops.sched_clock = kvm_clock_read;
+ pv_apic_ops.setup_secondary_clock = kvm_setup_secondary_clock;
+ machine_ops.shutdown = kvm_shutdown;
+#ifdef CONFIG_KEXEC
+ machine_ops.crash_shutdown = kvm_crash_shutdown;
+#endif
+ clocksource_register(&kvm_clock);
+ }
+}
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c
index b402c0f3f192..3cad17fe026b 100644
--- a/arch/x86/kernel/mfgpt_32.c
+++ b/arch/x86/kernel/mfgpt_32.c
@@ -63,7 +63,7 @@ static int __init mfgpt_fix(char *s)
/* The following udocumented bit resets the MFGPT timers */
val = 0xFF; dummy = 0;
- wrmsr(0x5140002B, val, dummy);
+ wrmsr(MSR_MFGPT_SETUP, val, dummy);
return 1;
}
__setup("mfgptfix", mfgpt_fix);
@@ -127,17 +127,17 @@ int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
* 6; that is, resets for 7 and 8 will be ignored. Is this
* a problem? -dilinger
*/
- msr = MFGPT_NR_MSR;
+ msr = MSR_MFGPT_NR;
mask = 1 << (timer + 24);
break;
case MFGPT_EVENT_NMI:
- msr = MFGPT_NR_MSR;
+ msr = MSR_MFGPT_NR;
mask = 1 << (timer + shift);
break;
case MFGPT_EVENT_IRQ:
- msr = MFGPT_IRQ_MSR;
+ msr = MSR_MFGPT_IRQ;
mask = 1 << (timer + shift);
break;
@@ -364,7 +364,8 @@ int __init mfgpt_timer_setup(void)
geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
/* Set up the clock event */
- mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
+ mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC,
+ mfgpt_clockevent.shift);
mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
&mfgpt_clockevent);
mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 70744e344fa1..3e2c54dc8b29 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -686,13 +686,11 @@ void __init get_smp_config(void)
static int __init smp_scan_config(unsigned long base, unsigned long length,
unsigned reserve)
{
- extern void __bad_mpf_size(void);
unsigned int *bp = phys_to_virt(base);
struct intel_mp_floating *mpf;
Dprintk("Scan SMP from %p for %ld bytes.\n", bp, length);
- if (sizeof(*mpf) != 16)
- __bad_mpf_size();
+ BUILD_BUG_ON(sizeof(*mpf) != 16);
while (length > 0) {
mpf = (struct intel_mp_floating *)bp;
@@ -801,7 +799,6 @@ void __init find_smp_config(void)
#ifdef CONFIG_X86_IO_APIC
#define MP_ISA_BUS 0
-#define MP_MAX_IOAPIC_PIN 127
extern struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];
@@ -820,7 +817,7 @@ static int mp_find_ioapic(int gsi)
return -1;
}
-static u8 uniq_ioapic_id(u8 id)
+static u8 __init uniq_ioapic_id(u8 id)
{
#ifdef CONFIG_X86_32
if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
@@ -909,14 +906,7 @@ void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* APIC ID */
intsrc.mpc_dstirq = pin; /* INTIN# */
- Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n",
- intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
- (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
- intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
-
- mp_irqs[mp_irq_entries] = intsrc;
- if (++mp_irq_entries == MAX_IRQ_SOURCES)
- panic("Max # of irq sources exceeded!\n");
+ MP_intsrc_info(&intsrc);
}
int es7000_plat;
@@ -985,23 +975,14 @@ void __init mp_config_acpi_legacy_irqs(void)
intsrc.mpc_srcbusirq = i; /* Identity mapped */
intsrc.mpc_dstirq = i;
- Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, "
- "%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
- (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
- intsrc.mpc_srcbusirq, intsrc.mpc_dstapic,
- intsrc.mpc_dstirq);
-
- mp_irqs[mp_irq_entries] = intsrc;
- if (++mp_irq_entries == MAX_IRQ_SOURCES)
- panic("Max # of irq sources exceeded!\n");
+ MP_intsrc_info(&intsrc);
}
}
int mp_register_gsi(u32 gsi, int triggering, int polarity)
{
- int ioapic = -1;
- int ioapic_pin = 0;
- int idx, bit = 0;
+ int ioapic;
+ int ioapic_pin;
#ifdef CONFIG_X86_32
#define MAX_GSI_NUM 4096
#define IRQ_COMPRESSION_START 64
@@ -1041,15 +1022,13 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
* with redundant pin->gsi mappings (but unique PCI devices);
* we only program the IOAPIC on the first.
*/
- bit = ioapic_pin % 32;
- idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
- if (idx > 3) {
+ if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
return gsi;
}
- if ((1 << bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+ if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
#ifdef CONFIG_X86_32
@@ -1059,7 +1038,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
#endif
}
- mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1 << bit);
+ set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed);
#ifdef CONFIG_X86_32
/*
* For GSI >= 64, use IRQ compression
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 3733412d1357..74f0c5ea2a03 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -366,11 +366,13 @@ struct pv_mmu_ops pv_mmu_ops = {
.flush_tlb_single = native_flush_tlb_single,
.flush_tlb_others = native_flush_tlb_others,
- .alloc_pt = paravirt_nop,
- .alloc_pd = paravirt_nop,
- .alloc_pd_clone = paravirt_nop,
- .release_pt = paravirt_nop,
- .release_pd = paravirt_nop,
+ .alloc_pte = paravirt_nop,
+ .alloc_pmd = paravirt_nop,
+ .alloc_pmd_clone = paravirt_nop,
+ .alloc_pud = paravirt_nop,
+ .release_pte = paravirt_nop,
+ .release_pmd = paravirt_nop,
+ .release_pud = paravirt_nop,
.set_pte = native_set_pte,
.set_pte_at = native_set_pte_at,
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 2edee22e9c30..e28ec497e142 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -43,6 +43,7 @@
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/rio.h>
+#include <asm/bios_ebda.h>
#ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT
int use_calgary __read_mostly = 1;
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 3004d716539d..67e9b4a1e89d 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -4,6 +4,8 @@
#include <linux/smp.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/pm.h>
struct kmem_cache *task_xstate_cachep;
@@ -42,3 +44,118 @@ void arch_task_cache_init(void)
__alignof__(union thread_xstate),
SLAB_PANIC, NULL);
}
+
+static void do_nothing(void *unused)
+{
+}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
+ * pm_idle and update to new pm_idle value. Required while changing pm_idle
+ * handler on SMP systems.
+ *
+ * Caller must have changed pm_idle to the new value before the call. Old
+ * pm_idle value will not be used by any CPU after the return of this function.
+ */
+void cpu_idle_wait(void)
+{
+ smp_mb();
+ /* kick all the CPUs so that they exit out of pm_idle */
+ smp_call_function(do_nothing, NULL, 0, 1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
+/*
+ * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
+ * which can obviate IPI to trigger checking of need_resched.
+ * We execute MONITOR against need_resched and enter optimized wait state
+ * through MWAIT. Whenever someone changes need_resched, we would be woken
+ * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
+ */
+void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
+{
+ if (!need_resched()) {
+ __monitor((void *)&current_thread_info()->flags, 0, 0);
+ smp_mb();
+ if (!need_resched())
+ __mwait(ax, cx);
+ }
+}
+
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+ if (!need_resched()) {
+ __monitor((void *)&current_thread_info()->flags, 0, 0);
+ smp_mb();
+ if (!need_resched())
+ __sti_mwait(0, 0);
+ else
+ local_irq_enable();
+ } else
+ local_irq_enable();
+}
+
+
+static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
+{
+ if (force_mwait)
+ return 1;
+ /* Any C1 states supported? */
+ return c->cpuid_level >= 5 && ((cpuid_edx(5) >> 4) & 0xf) > 0;
+}
+
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle(void)
+{
+ local_irq_enable();
+ cpu_relax();
+}
+
+void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
+{
+ static int selected;
+
+ if (selected)
+ return;
+#ifdef CONFIG_X86_SMP
+ if (pm_idle == poll_idle && smp_num_siblings > 1) {
+ printk(KERN_WARNING "WARNING: polling idle and HT enabled,"
+ " performance may degrade.\n");
+ }
+#endif
+ if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) {
+ /*
+ * Skip, if setup has overridden idle.
+ * One CPU supports mwait => All CPUs supports mwait
+ */
+ if (!pm_idle) {
+ printk(KERN_INFO "using mwait in idle threads.\n");
+ pm_idle = mwait_idle;
+ }
+ }
+ selected = 1;
+}
+
+static int __init idle_setup(char *str)
+{
+ if (!strcmp(str, "poll")) {
+ printk("using polling idle threads.\n");
+ pm_idle = poll_idle;
+ } else if (!strcmp(str, "mwait"))
+ force_mwait = 1;
+ else
+ return -1;
+
+ boot_option_idle_override = 1;
+ return 0;
+}
+early_param("idle", idle_setup);
+
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 77de848bd1fb..f8476dfbb60d 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -111,12 +111,10 @@ void default_idle(void)
*/
smp_mb();
- local_irq_disable();
- if (!need_resched()) {
+ if (!need_resched())
safe_halt(); /* enables interrupts racelessly */
- local_irq_disable();
- }
- local_irq_enable();
+ else
+ local_irq_enable();
current_thread_info()->status |= TS_POLLING;
} else {
local_irq_enable();
@@ -128,17 +126,6 @@ void default_idle(void)
EXPORT_SYMBOL(default_idle);
#endif
-/*
- * On SMP it's slightly faster (but much more power-consuming!)
- * to poll the ->work.need_resched flag instead of waiting for the
- * cross-CPU IPI to arrive. Use this option with caution.
- */
-static void poll_idle(void)
-{
- local_irq_enable();
- cpu_relax();
-}
-
#ifdef CONFIG_HOTPLUG_CPU
#include <asm/nmi.h>
/* We don't actually take CPU down, just spin without interrupts. */
@@ -196,6 +183,7 @@ void cpu_idle(void)
if (cpu_is_offline(cpu))
play_dead();
+ local_irq_disable();
__get_cpu_var(irq_stat).idle_timestamp = jiffies;
idle();
}
@@ -206,104 +194,6 @@ void cpu_idle(void)
}
}
-static void do_nothing(void *unused)
-{
-}
-
-/*
- * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
- * pm_idle and update to new pm_idle value. Required while changing pm_idle
- * handler on SMP systems.
- *
- * Caller must have changed pm_idle to the new value before the call. Old
- * pm_idle value will not be used by any CPU after the return of this function.
- */
-void cpu_idle_wait(void)
-{
- smp_mb();
- /* kick all the CPUs so that they exit out of pm_idle */
- smp_call_function(do_nothing, NULL, 0, 1);
-}
-EXPORT_SYMBOL_GPL(cpu_idle_wait);
-
-/*
- * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
- * which can obviate IPI to trigger checking of need_resched.
- * We execute MONITOR against need_resched and enter optimized wait state
- * through MWAIT. Whenever someone changes need_resched, we would be woken
- * up from MWAIT (without an IPI).
- *
- * New with Core Duo processors, MWAIT can take some hints based on CPU
- * capability.
- */
-void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
-{
- if (!need_resched()) {
- __monitor((void *)&current_thread_info()->flags, 0, 0);
- smp_mb();
- if (!need_resched())
- __sti_mwait(ax, cx);
- else
- local_irq_enable();
- } else
- local_irq_enable();
-}
-
-/* Default MONITOR/MWAIT with no hints, used for default C1 state */
-static void mwait_idle(void)
-{
- local_irq_enable();
- mwait_idle_with_hints(0, 0);
-}
-
-static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
-{
- if (force_mwait)
- return 1;
- /* Any C1 states supported? */
- return c->cpuid_level >= 5 && ((cpuid_edx(5) >> 4) & 0xf) > 0;
-}
-
-void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
-{
- static int selected;
-
- if (selected)
- return;
-#ifdef CONFIG_X86_SMP
- if (pm_idle == poll_idle && smp_num_siblings > 1) {
- printk(KERN_WARNING "WARNING: polling idle and HT enabled,"
- " performance may degrade.\n");
- }
-#endif
- if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) {
- /*
- * Skip, if setup has overridden idle.
- * One CPU supports mwait => All CPUs supports mwait
- */
- if (!pm_idle) {
- printk(KERN_INFO "using mwait in idle threads.\n");
- pm_idle = mwait_idle;
- }
- }
- selected = 1;
-}
-
-static int __init idle_setup(char *str)
-{
- if (!strcmp(str, "poll")) {
- printk("using polling idle threads.\n");
- pm_idle = poll_idle;
- } else if (!strcmp(str, "mwait"))
- force_mwait = 1;
- else
- return -1;
-
- boot_option_idle_override = 1;
- return 0;
-}
-early_param("idle", idle_setup);
-
void __show_registers(struct pt_regs *regs, int all)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 131c2ee7ac56..e2319f39988b 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -106,26 +106,13 @@ void default_idle(void)
* test NEED_RESCHED:
*/
smp_mb();
- local_irq_disable();
- if (!need_resched()) {
+ if (!need_resched())
safe_halt(); /* enables interrupts racelessly */
- local_irq_disable();
- }
- local_irq_enable();
+ else
+ local_irq_enable();
current_thread_info()->status |= TS_POLLING;
}
-/*
- * On SMP it's slightly faster (but much more power-consuming!)
- * to poll the ->need_resched flag instead of waiting for the
- * cross-CPU IPI to arrive. Use this option with caution.
- */
-static void poll_idle(void)
-{
- local_irq_enable();
- cpu_relax();
-}
-
#ifdef CONFIG_HOTPLUG_CPU
DECLARE_PER_CPU(int, cpu_state);
@@ -192,110 +179,6 @@ void cpu_idle(void)
}
}
-static void do_nothing(void *unused)
-{
-}
-
-/*
- * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
- * pm_idle and update to new pm_idle value. Required while changing pm_idle
- * handler on SMP systems.
- *
- * Caller must have changed pm_idle to the new value before the call. Old
- * pm_idle value will not be used by any CPU after the return of this function.
- */
-void cpu_idle_wait(void)
-{
- smp_mb();
- /* kick all the CPUs so that they exit out of pm_idle */
- smp_call_function(do_nothing, NULL, 0, 1);
-}
-EXPORT_SYMBOL_GPL(cpu_idle_wait);
-
-/*
- * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
- * which can obviate IPI to trigger checking of need_resched.
- * We execute MONITOR against need_resched and enter optimized wait state
- * through MWAIT. Whenever someone changes need_resched, we would be woken
- * up from MWAIT (without an IPI).
- *
- * New with Core Duo processors, MWAIT can take some hints based on CPU
- * capability.
- */
-void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
-{
- if (!need_resched()) {
- __monitor((void *)&current_thread_info()->flags, 0, 0);
- smp_mb();
- if (!need_resched())
- __mwait(ax, cx);
- }
-}
-
-/* Default MONITOR/MWAIT with no hints, used for default C1 state */
-static void mwait_idle(void)
-{
- if (!need_resched()) {
- __monitor((void *)&current_thread_info()->flags, 0, 0);
- smp_mb();
- if (!need_resched())
- __sti_mwait(0, 0);
- else
- local_irq_enable();
- } else {
- local_irq_enable();
- }
-}
-
-
-static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
-{
- if (force_mwait)
- return 1;
- /* Any C1 states supported? */
- return c->cpuid_level >= 5 && ((cpuid_edx(5) >> 4) & 0xf) > 0;
-}
-
-void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
-{
- static int selected;
-
- if (selected)
- return;
-#ifdef CONFIG_X86_SMP
- if (pm_idle == poll_idle && smp_num_siblings > 1) {
- printk(KERN_WARNING "WARNING: polling idle and HT enabled,"
- " performance may degrade.\n");
- }
-#endif
- if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) {
- /*
- * Skip, if setup has overridden idle.
- * One CPU supports mwait => All CPUs supports mwait
- */
- if (!pm_idle) {
- printk(KERN_INFO "using mwait in idle threads.\n");
- pm_idle = mwait_idle;
- }
- }
- selected = 1;
-}
-
-static int __init idle_setup(char *str)
-{
- if (!strcmp(str, "poll")) {
- printk("using polling idle threads.\n");
- pm_idle = poll_idle;
- } else if (!strcmp(str, "mwait"))
- force_mwait = 1;
- else
- return -1;
-
- boot_option_idle_override = 1;
- return 0;
-}
-early_param("idle", idle_setup);
-
/* Prints also some state that isn't saved in the pt_regs */
void __show_regs(struct pt_regs * regs)
{
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 559c1b027417..fb03ef380f0e 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1207,97 +1207,16 @@ static int genregs32_set(struct task_struct *target,
return ret;
}
-static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
{
- siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
- compat_siginfo_t __user *si32 = compat_ptr(data);
- siginfo_t ssi;
- int ret;
-
- if (request == PTRACE_SETSIGINFO) {
- memset(&ssi, 0, sizeof(siginfo_t));
- ret = copy_siginfo_from_user32(&ssi, si32);
- if (ret)
- return ret;
- if (copy_to_user(si, &ssi, sizeof(siginfo_t)))
- return -EFAULT;
- }
- ret = sys_ptrace(request, pid, addr, (unsigned long)si);
- if (ret)
- return ret;
- if (request == PTRACE_GETSIGINFO) {
- if (copy_from_user(&ssi, si, sizeof(siginfo_t)))
- return -EFAULT;
- ret = copy_siginfo_to_user32(si32, &ssi);
- }
- return ret;
-}
-
-asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
-{
- struct task_struct *child;
- struct pt_regs *childregs;
+ unsigned long addr = caddr;
+ unsigned long data = cdata;
void __user *datap = compat_ptr(data);
int ret;
__u32 val;
switch (request) {
- case PTRACE_TRACEME:
- case PTRACE_ATTACH:
- case PTRACE_KILL:
- case PTRACE_CONT:
- case PTRACE_SINGLESTEP:
- case PTRACE_SINGLEBLOCK:
- case PTRACE_DETACH:
- case PTRACE_SYSCALL:
- case PTRACE_OLDSETOPTIONS:
- case PTRACE_SETOPTIONS:
- case PTRACE_SET_THREAD_AREA:
- case PTRACE_GET_THREAD_AREA:
-#ifdef X86_BTS
- case PTRACE_BTS_CONFIG:
- case PTRACE_BTS_STATUS:
- case PTRACE_BTS_SIZE:
- case PTRACE_BTS_GET:
- case PTRACE_BTS_CLEAR:
- case PTRACE_BTS_DRAIN:
-#endif
- return sys_ptrace(request, pid, addr, data);
-
- default:
- return -EINVAL;
-
- case PTRACE_PEEKTEXT:
- case PTRACE_PEEKDATA:
- case PTRACE_POKEDATA:
- case PTRACE_POKETEXT:
- case PTRACE_POKEUSR:
- case PTRACE_PEEKUSR:
- case PTRACE_GETREGS:
- case PTRACE_SETREGS:
- case PTRACE_SETFPREGS:
- case PTRACE_GETFPREGS:
- case PTRACE_SETFPXREGS:
- case PTRACE_GETFPXREGS:
- case PTRACE_GETEVENTMSG:
- break;
-
- case PTRACE_SETSIGINFO:
- case PTRACE_GETSIGINFO:
- return ptrace32_siginfo(request, pid, addr, data);
- }
-
- child = ptrace_get_task_struct(pid);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- ret = ptrace_check_attach(child, request == PTRACE_KILL);
- if (ret < 0)
- goto out;
-
- childregs = task_pt_regs(child);
-
- switch (request) {
case PTRACE_PEEKUSR:
ret = getreg32(child, addr, &val);
if (ret == 0)
@@ -1343,12 +1262,14 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
sizeof(struct user32_fxsr_struct),
datap);
+ case PTRACE_GET_THREAD_AREA:
+ case PTRACE_SET_THREAD_AREA:
+ return arch_ptrace(child, request, addr, data);
+
default:
return compat_ptrace_request(child, request, addr, data);
}
- out:
- put_task_struct(child);
return ret;
}
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 19c9386ac118..a4a838306b2c 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -8,6 +8,7 @@
#include <asm/apic.h>
#include <asm/desc.h>
#include <asm/hpet.h>
+#include <asm/pgtable.h>
#include <asm/reboot_fixups.h>
#include <asm/reboot.h>
@@ -15,7 +16,6 @@
# include <linux/dmi.h>
# include <linux/ctype.h>
# include <linux/mc146818rtc.h>
-# include <asm/pgtable.h>
#else
# include <asm/iommu.h>
#endif
@@ -275,7 +275,7 @@ void machine_real_restart(unsigned char *code, int length)
/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment. This assumes the kernel segment starts at
virtual address PAGE_OFFSET. */
- memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
/*
@@ -399,7 +399,7 @@ static void native_machine_emergency_restart(void)
}
}
-static void native_machine_shutdown(void)
+void native_machine_shutdown(void)
{
/* Stop the cpus and apics */
#ifdef CONFIG_SMP
@@ -470,7 +470,10 @@ struct machine_ops machine_ops = {
.shutdown = native_machine_shutdown,
.emergency_restart = native_machine_emergency_restart,
.restart = native_machine_restart,
- .halt = native_machine_halt
+ .halt = native_machine_halt,
+#ifdef CONFIG_KEXEC
+ .crash_shutdown = native_machine_crash_shutdown,
+#endif
};
void machine_power_off(void)
@@ -498,3 +501,9 @@ void machine_halt(void)
machine_ops.halt();
}
+#ifdef CONFIG_KEXEC
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ machine_ops.crash_shutdown(regs);
+}
+#endif
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index 455d3c80960b..2283422af794 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -47,6 +47,7 @@
#include <linux/pfn.h>
#include <linux/pci.h>
#include <linux/init_ohci1394_dma.h>
+#include <linux/kvm_para.h>
#include <video/edid.h>
@@ -389,7 +390,6 @@ unsigned long __init find_max_low_pfn(void)
return max_low_pfn;
}
-#define BIOS_EBDA_SEGMENT 0x40E
#define BIOS_LOWMEM_KILOBYTES 0x413
/*
@@ -420,8 +420,7 @@ static void __init reserve_ebda_region(void)
lowmem <<= 10;
/* start of EBDA area */
- ebda_addr = *(unsigned short *)__va(BIOS_EBDA_SEGMENT);
- ebda_addr <<= 4;
+ ebda_addr = get_bios_ebda();
/* Fixup: bios puts an EBDA in the top 64K segment */
/* of conventional memory, but does not adjust lowmem. */
@@ -822,6 +821,10 @@ void __init setup_arch(char **cmdline_p)
max_low_pfn = setup_memory();
+#ifdef CONFIG_KVM_CLOCK
+ kvmclock_init();
+#endif
+
#ifdef CONFIG_VMI
/*
* Must be after max_low_pfn is determined, and before kernel
@@ -829,6 +832,7 @@ void __init setup_arch(char **cmdline_p)
*/
vmi_init();
#endif
+ kvm_guest_init();
/*
* NOTE: before this point _nobody_ is allowed to allocate
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index c2ec3dcb6b99..a94fb959a87a 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -42,6 +42,7 @@
#include <linux/ctype.h>
#include <linux/uaccess.h>
#include <linux/init_ohci1394_dma.h>
+#include <linux/kvm_para.h>
#include <asm/mtrr.h>
#include <asm/uaccess.h>
@@ -116,7 +117,7 @@ extern int root_mountflags;
char __initdata command_line[COMMAND_LINE_SIZE];
-struct resource standard_io_resources[] = {
+static struct resource standard_io_resources[] = {
{ .name = "dma1", .start = 0x00, .end = 0x1f,
.flags = IORESOURCE_BUSY | IORESOURCE_IO },
{ .name = "pic1", .start = 0x20, .end = 0x21,
@@ -190,6 +191,7 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
e820_register_active_regions(0, start_pfn, end_pfn);
free_bootmem_with_active_regions(0, end_pfn);
+ early_res_to_bootmem(0, end_pfn<<PAGE_SHIFT);
reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT);
}
#endif
@@ -264,6 +266,28 @@ void __attribute__((weak)) __init memory_setup(void)
machine_specific_memory_setup();
}
+static void __init parse_setup_data(void)
+{
+ struct setup_data *data;
+ unsigned long pa_data;
+
+ if (boot_params.hdr.version < 0x0209)
+ return;
+ pa_data = boot_params.hdr.setup_data;
+ while (pa_data) {
+ data = early_ioremap(pa_data, PAGE_SIZE);
+ switch (data->type) {
+ default:
+ break;
+ }
+#ifndef CONFIG_DEBUG_BOOT_PARAMS
+ free_early(pa_data, pa_data+sizeof(*data)+data->len);
+#endif
+ pa_data = data->next;
+ early_iounmap(data, PAGE_SIZE);
+ }
+}
+
/*
* setup_arch - architecture-specific boot-time initializations
*
@@ -316,6 +340,8 @@ void __init setup_arch(char **cmdline_p)
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
+ parse_setup_data();
+
parse_early_param();
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
@@ -359,6 +385,10 @@ void __init setup_arch(char **cmdline_p)
io_delay_init();
+#ifdef CONFIG_KVM_CLOCK
+ kvmclock_init();
+#endif
+
#ifdef CONFIG_SMP
/* setup to use the early static init tables during kernel startup */
x86_cpu_to_apicid_early_ptr = (void *)x86_cpu_to_apicid_init;
@@ -397,8 +427,6 @@ void __init setup_arch(char **cmdline_p)
contig_initmem_init(0, end_pfn);
#endif
- early_res_to_bootmem();
-
dma32_reserve_bootmem();
#ifdef CONFIG_ACPI_SLEEP
@@ -465,6 +493,8 @@ void __init setup_arch(char **cmdline_p)
init_apic_mappings();
ioapic_init_mappings();
+ kvm_guest_init();
+
/*
* We trust e820 completely. No explicit ROM probing in memory.
*/
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index f1b117930837..8e05e7f7bd40 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -413,16 +413,6 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
regs->ss = __USER_DS;
regs->cs = __USER_CS;
- /*
- * 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 | X86_EFLAGS_DF);
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
return 0;
give_sigsegv:
@@ -501,16 +491,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->ss = __USER_DS;
regs->cs = __USER_CS;
- /*
- * 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 | X86_EFLAGS_DF);
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
return 0;
give_sigsegv:
@@ -566,6 +546,21 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
if (ret)
return ret;
+ /*
+ * Clear the direction flag as per the ABI for function entry.
+ */
+ regs->flags &= ~X86_EFLAGS_DF;
+
+ /*
+ * 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;
+ if (test_thread_flag(TIF_SINGLESTEP))
+ ptrace_notify(SIGTRAP);
+
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 827179c5b32a..ccb2a4560c2d 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -285,14 +285,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
even if the handler happens to be interrupting 32-bit code. */
regs->cs = __USER_CS;
- /* This, by contrast, has nothing to do with segment registers -
- see include/asm-x86_64/uaccess.h for details. */
- set_fs(USER_DS);
-
- regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF);
- if (test_thread_flag(TIF_SINGLESTEP))
- ptrace_notify(SIGTRAP);
-
return 0;
give_sigsegv:
@@ -380,6 +372,28 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
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);
+
+ /*
+ * Clear the direction flag as per the ABI for function entry.
+ */
+ regs->flags &= ~X86_EFLAGS_DF;
+
+ /*
+ * 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;
+ if (test_thread_flag(TIF_SINGLESTEP))
+ ptrace_notify(SIGTRAP);
+
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index ade371f9663a..04c662ba18f1 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1039,8 +1039,8 @@ int __cpuinit native_cpu_up(unsigned int cpu)
#ifdef CONFIG_X86_32
/* init low mem mapping */
- clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY));
flush_tlb_all();
#endif
@@ -1058,7 +1058,7 @@ int __cpuinit native_cpu_up(unsigned int cpu)
check_tsc_sync_source(cpu);
local_irq_restore(flags);
- while (!cpu_isset(cpu, cpu_online_map)) {
+ while (!cpu_online(cpu)) {
cpu_relax();
touch_nmi_watchdog();
}
@@ -1168,7 +1168,7 @@ static void __init smp_cpu_index_default(void)
int i;
struct cpuinfo_x86 *c;
- for_each_cpu_mask(i, cpu_possible_map) {
+ for_each_possible_cpu(i) {
c = &cpu_data(i);
/* mark all to hotplug */
c->cpu_index = NR_CPUS;
diff --git a/arch/x86/kernel/summit_32.c b/arch/x86/kernel/summit_32.c
index 6878a9c2df5d..ae751094eba9 100644
--- a/arch/x86/kernel/summit_32.c
+++ b/arch/x86/kernel/summit_32.c
@@ -29,6 +29,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/io.h>
+#include <asm/bios_ebda.h>
#include <asm/mach-summit/mach_mpparse.h>
static struct rio_table_hdr *rio_table_hdr __initdata;
@@ -140,8 +141,8 @@ void __init setup_summit(void)
int i, next_wpeg, next_bus = 0;
/* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */
- ptr = *(unsigned short *)phys_to_virt(0x40Eul);
- ptr = (unsigned long)phys_to_virt(ptr << 4);
+ ptr = get_bios_ebda();
+ ptr = (unsigned long)phys_to_virt(ptr);
rio_table_hdr = NULL;
offset = 0x180;
diff --git a/arch/x86/kernel/tlb_64.c b/arch/x86/kernel/tlb_64.c
index df224a8774cb..a1f07d793202 100644
--- a/arch/x86/kernel/tlb_64.c
+++ b/arch/x86/kernel/tlb_64.c
@@ -195,9 +195,9 @@ static int __cpuinit init_smp_flush(void)
{
int i;
- for_each_cpu_mask(i, cpu_possible_map) {
+ for_each_possible_cpu(i)
spin_lock_init(&per_cpu(flush_state, i).tlbstate_lock);
- }
+
return 0;
}
core_initcall(init_smp_flush);
diff --git a/arch/x86/kernel/trampoline_32.S b/arch/x86/kernel/trampoline_32.S
index 64580679861e..d8ccc3c6552f 100644
--- a/arch/x86/kernel/trampoline_32.S
+++ b/arch/x86/kernel/trampoline_32.S
@@ -33,7 +33,7 @@
/* We can free up trampoline after bootup if cpu hotplug is not supported. */
#ifndef CONFIG_HOTPLUG_CPU
-.section ".init.data","aw",@progbits
+.section ".cpuinit.data","aw",@progbits
#else
.section .rodata,"a",@progbits
#endif
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index 471e694d6713..bde6f63e15d5 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -602,7 +602,7 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
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, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1)
+DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
void __kprobes do_general_protection(struct pt_regs *regs, long error_code)
{
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c
index 12affe1f9bce..956f38927aa7 100644
--- a/arch/x86/kernel/vmi_32.c
+++ b/arch/x86/kernel/vmi_32.c
@@ -320,7 +320,7 @@ static void check_zeroed_page(u32 pfn, int type, struct page *page)
* pdes need to be zeroed.
*/
if (type & VMI_PAGE_CLONE)
- limit = USER_PTRS_PER_PGD;
+ limit = KERNEL_PGD_BOUNDARY;
for (i = 0; i < limit; i++)
BUG_ON(ptr[i]);
}
@@ -392,13 +392,13 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
}
#endif
-static void vmi_allocate_pt(struct mm_struct *mm, u32 pfn)
+static void vmi_allocate_pte(struct mm_struct *mm, u32 pfn)
{
vmi_set_page_type(pfn, VMI_PAGE_L1);
vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
}
-static void vmi_allocate_pd(struct mm_struct *mm, u32 pfn)
+static void vmi_allocate_pmd(struct mm_struct *mm, u32 pfn)
{
/*
* This call comes in very early, before mem_map is setup.
@@ -409,20 +409,20 @@ static void vmi_allocate_pd(struct mm_struct *mm, u32 pfn)
vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0);
}
-static void vmi_allocate_pd_clone(u32 pfn, u32 clonepfn, u32 start, u32 count)
+static void vmi_allocate_pmd_clone(u32 pfn, u32 clonepfn, u32 start, u32 count)
{
vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE);
vmi_check_page_type(clonepfn, VMI_PAGE_L2);
vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count);
}
-static void vmi_release_pt(u32 pfn)
+static void vmi_release_pte(u32 pfn)
{
vmi_ops.release_page(pfn, VMI_PAGE_L1);
vmi_set_page_type(pfn, VMI_PAGE_NORMAL);
}
-static void vmi_release_pd(u32 pfn)
+static void vmi_release_pmd(u32 pfn)
{
vmi_ops.release_page(pfn, VMI_PAGE_L2);
vmi_set_page_type(pfn, VMI_PAGE_NORMAL);
@@ -871,15 +871,15 @@ static inline int __init activate_vmi(void)
vmi_ops.allocate_page = vmi_get_function(VMI_CALL_AllocatePage);
if (vmi_ops.allocate_page) {
- pv_mmu_ops.alloc_pt = vmi_allocate_pt;
- pv_mmu_ops.alloc_pd = vmi_allocate_pd;
- pv_mmu_ops.alloc_pd_clone = vmi_allocate_pd_clone;
+ pv_mmu_ops.alloc_pte = vmi_allocate_pte;
+ pv_mmu_ops.alloc_pmd = vmi_allocate_pmd;
+ pv_mmu_ops.alloc_pmd_clone = vmi_allocate_pmd_clone;
}
vmi_ops.release_page = vmi_get_function(VMI_CALL_ReleasePage);
if (vmi_ops.release_page) {
- pv_mmu_ops.release_pt = vmi_release_pt;
- pv_mmu_ops.release_pd = vmi_release_pd;
+ pv_mmu_ops.release_pte = vmi_release_pte;
+ pv_mmu_ops.release_pmd = vmi_release_pmd;
}
/* Set linear is needed in all cases */
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index b7ab3c335fae..fad3674b06a5 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -209,12 +209,6 @@ SECTIONS
EXIT_DATA
}
-/* vdso blob that is mapped into user space */
- vdso_start = . ;
- .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) }
- . = ALIGN(PAGE_SIZE);
- vdso_end = .;
-
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(PAGE_SIZE);
__initramfs_start = .;
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 41962e793c0f..8d45fabc5f3b 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -19,7 +19,7 @@ if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
- depends on HAVE_KVM && EXPERIMENTAL
+ depends on HAVE_KVM
select PREEMPT_NOTIFIERS
select ANON_INODES
---help---
@@ -50,6 +50,17 @@ config KVM_AMD
Provides support for KVM on AMD processors equipped with the AMD-V
(SVM) extensions.
+config KVM_TRACE
+ bool "KVM trace support"
+ depends on KVM && MARKERS && SYSFS
+ select RELAY
+ select DEBUG_FS
+ default n
+ ---help---
+ This option allows reading a trace of kvm-related events through
+ relayfs. Note the ABI is not considered stable and will be
+ modified in future updates.
+
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
source drivers/lguest/Kconfig
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index ffdd0b310784..c97d35c218db 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -3,10 +3,14 @@
#
common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o)
+ifeq ($(CONFIG_KVM_TRACE),y)
+common-objs += $(addprefix ../../../virt/kvm/, kvm_trace.o)
+endif
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
-kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o
+kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
+ i8254.o
obj-$(CONFIG_KVM) += kvm.o
kvm-intel-objs = vmx.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
new file mode 100644
index 000000000000..361e31611276
--- /dev/null
+++ b/arch/x86/kvm/i8254.c
@@ -0,0 +1,611 @@
+/*
+ * 8253/8254 interval timer emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2006 Intel Corporation
+ * Copyright (c) 2007 Keir Fraser, XenSource Inc
+ * Copyright (c) 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE 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.
+ *
+ * Authors:
+ * Sheng Yang <sheng.yang@intel.com>
+ * Based on QEMU and Xen.
+ */
+
+#include <linux/kvm_host.h>
+
+#include "irq.h"
+#include "i8254.h"
+
+#ifndef CONFIG_X86_64
+#define mod_64(x, y) ((x) - (y) * div64_64(x, y))
+#else
+#define mod_64(x, y) ((x) % (y))
+#endif
+
+#define RW_STATE_LSB 1
+#define RW_STATE_MSB 2
+#define RW_STATE_WORD0 3
+#define RW_STATE_WORD1 4
+
+/* Compute with 96 bit intermediate result: (a*b)/c */
+static u64 muldiv64(u64 a, u32 b, u32 c)
+{
+ union {
+ u64 ll;
+ struct {
+ u32 low, high;
+ } l;
+ } u, res;
+ u64 rl, rh;
+
+ u.ll = a;
+ rl = (u64)u.l.low * (u64)b;
+ rh = (u64)u.l.high * (u64)b;
+ rh += (rl >> 32);
+ res.l.high = div64_64(rh, c);
+ res.l.low = div64_64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
+ return res.ll;
+}
+
+static void pit_set_gate(struct kvm *kvm, int channel, u32 val)
+{
+ struct kvm_kpit_channel_state *c =
+ &kvm->arch.vpit->pit_state.channels[channel];
+
+ WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
+
+ switch (c->mode) {
+ default:
+ case 0:
+ case 4:
+ /* XXX: just disable/enable counting */
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ /* Restart counting on rising edge. */
+ if (c->gate < val)
+ c->count_load_time = ktime_get();
+ break;
+ }
+
+ c->gate = val;
+}
+
+int pit_get_gate(struct kvm *kvm, int channel)
+{
+ WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
+
+ return kvm->arch.vpit->pit_state.channels[channel].gate;
+}
+
+static int pit_get_count(struct kvm *kvm, int channel)
+{
+ struct kvm_kpit_channel_state *c =
+ &kvm->arch.vpit->pit_state.channels[channel];
+ s64 d, t;
+ int counter;
+
+ WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
+
+ t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+ d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC);
+
+ switch (c->mode) {
+ case 0:
+ case 1:
+ case 4:
+ case 5:
+ counter = (c->count - d) & 0xffff;
+ break;
+ case 3:
+ /* XXX: may be incorrect for odd counts */
+ counter = c->count - (mod_64((2 * d), c->count));
+ break;
+ default:
+ counter = c->count - mod_64(d, c->count);
+ break;
+ }
+ return counter;
+}
+
+static int pit_get_out(struct kvm *kvm, int channel)
+{
+ struct kvm_kpit_channel_state *c =
+ &kvm->arch.vpit->pit_state.channels[channel];
+ s64 d, t;
+ int out;
+
+ WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
+
+ t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+ d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC);
+
+ switch (c->mode) {
+ default:
+ case 0:
+ out = (d >= c->count);
+ break;
+ case 1:
+ out = (d < c->count);
+ break;
+ case 2:
+ out = ((mod_64(d, c->count) == 0) && (d != 0));
+ break;
+ case 3:
+ out = (mod_64(d, c->count) < ((c->count + 1) >> 1));
+ break;
+ case 4:
+ case 5:
+ out = (d == c->count);
+ break;
+ }
+
+ return out;
+}
+
+static void pit_latch_count(struct kvm *kvm, int channel)
+{
+ struct kvm_kpit_channel_state *c =
+ &kvm->arch.vpit->pit_state.channels[channel];
+
+ WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
+
+ if (!c->count_latched) {
+ c->latched_count = pit_get_count(kvm, channel);
+ c->count_latched = c->rw_mode;
+ }
+}
+
+static void pit_latch_status(struct kvm *kvm, int channel)
+{
+ struct kvm_kpit_channel_state *c =
+ &kvm->arch.vpit->pit_state.channels[channel];
+
+ WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
+
+ if (!c->status_latched) {
+ /* TODO: Return NULL COUNT (bit 6). */
+ c->status = ((pit_get_out(kvm, channel) << 7) |
+ (c->rw_mode << 4) |
+ (c->mode << 1) |
+ c->bcd);
+ c->status_latched = 1;
+ }
+}
+
+int __pit_timer_fn(struct kvm_kpit_state *ps)
+{
+ struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0];
+ struct kvm_kpit_timer *pt = &ps->pit_timer;
+
+ atomic_inc(&pt->pending);
+ smp_mb__after_atomic_inc();
+ /* FIXME: handle case where the guest is in guest mode */
+ if (vcpu0 && waitqueue_active(&vcpu0->wq)) {
+ vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+ wake_up_interruptible(&vcpu0->wq);
+ }
+
+ pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
+ pt->scheduled = ktime_to_ns(pt->timer.expires);
+
+ return (pt->period == 0 ? 0 : 1);
+}
+
+int pit_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pit *pit = vcpu->kvm->arch.vpit;
+
+ if (pit && vcpu->vcpu_id == 0)
+ return atomic_read(&pit->pit_state.pit_timer.pending);
+
+ return 0;
+}
+
+static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
+{
+ struct kvm_kpit_state *ps;
+ int restart_timer = 0;
+
+ ps = container_of(data, struct kvm_kpit_state, pit_timer.timer);
+
+ restart_timer = __pit_timer_fn(ps);
+
+ if (restart_timer)
+ return HRTIMER_RESTART;
+ else
+ return HRTIMER_NORESTART;
+}
+
+static void destroy_pit_timer(struct kvm_kpit_timer *pt)
+{
+ pr_debug("pit: execute del timer!\n");
+ hrtimer_cancel(&pt->timer);
+}
+
+static void create_pit_timer(struct kvm_kpit_timer *pt, u32 val, int is_period)
+{
+ s64 interval;
+
+ interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);
+
+ pr_debug("pit: create pit timer, interval is %llu nsec\n", interval);
+
+ /* TODO The new value only affected after the retriggered */
+ hrtimer_cancel(&pt->timer);
+ pt->period = (is_period == 0) ? 0 : interval;
+ pt->timer.function = pit_timer_fn;
+ atomic_set(&pt->pending, 0);
+
+ hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval),
+ HRTIMER_MODE_ABS);
+}
+
+static void pit_load_count(struct kvm *kvm, int channel, u32 val)
+{
+ struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
+
+ WARN_ON(!mutex_is_locked(&ps->lock));
+
+ pr_debug("pit: load_count val is %d, channel is %d\n", val, channel);
+
+ /*
+ * Though spec said the state of 8254 is undefined after power-up,
+ * seems some tricky OS like Windows XP depends on IRQ0 interrupt
+ * when booting up.
+ * So here setting initialize rate for it, and not a specific number
+ */
+ if (val == 0)
+ val = 0x10000;
+
+ ps->channels[channel].count_load_time = ktime_get();
+ ps->channels[channel].count = val;
+
+ if (channel != 0)
+ return;
+
+ /* Two types of timer
+ * mode 1 is one shot, mode 2 is period, otherwise del timer */
+ switch (ps->channels[0].mode) {
+ case 1:
+ create_pit_timer(&ps->pit_timer, val, 0);
+ break;
+ case 2:
+ create_pit_timer(&ps->pit_timer, val, 1);
+ break;
+ default:
+ destroy_pit_timer(&ps->pit_timer);
+ }
+}
+
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val)
+{
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
+ pit_load_count(kvm, channel, val);
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+}
+
+static void pit_ioport_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *data)
+{
+ struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_kpit_state *pit_state = &pit->pit_state;
+ struct kvm *kvm = pit->kvm;
+ int channel, access;
+ struct kvm_kpit_channel_state *s;
+ u32 val = *(u32 *) data;
+
+ val &= 0xff;
+ addr &= KVM_PIT_CHANNEL_MASK;
+
+ mutex_lock(&pit_state->lock);
+
+ if (val != 0)
+ pr_debug("pit: write addr is 0x%x, len is %d, val is 0x%x\n",
+ (unsigned int)addr, len, val);
+
+ if (addr == 3) {
+ channel = val >> 6;
+ if (channel == 3) {
+ /* Read-Back Command. */
+ for (channel = 0; channel < 3; channel++) {
+ s = &pit_state->channels[channel];
+ if (val & (2 << channel)) {
+ if (!(val & 0x20))
+ pit_latch_count(kvm, channel);
+ if (!(val & 0x10))
+ pit_latch_status(kvm, channel);
+ }
+ }
+ } else {
+ /* Select Counter <channel>. */
+ s = &pit_state->channels[channel];
+ access = (val >> 4) & KVM_PIT_CHANNEL_MASK;
+ if (access == 0) {
+ pit_latch_count(kvm, channel);
+ } else {
+ s->rw_mode = access;
+ s->read_state = access;
+ s->write_state = access;
+ s->mode = (val >> 1) & 7;
+ if (s->mode > 5)
+ s->mode -= 4;
+ s->bcd = val & 1;
+ }
+ }
+ } else {
+ /* Write Count. */
+ s = &pit_state->channels[addr];
+ switch (s->write_state) {
+ default:
+ case RW_STATE_LSB:
+ pit_load_count(kvm, addr, val);
+ break;
+ case RW_STATE_MSB:
+ pit_load_count(kvm, addr, val << 8);
+ break;
+ case RW_STATE_WORD0:
+ s->write_latch = val;
+ s->write_state = RW_STATE_WORD1;
+ break;
+ case RW_STATE_WORD1:
+ pit_load_count(kvm, addr, s->write_latch | (val << 8));
+ s->write_state = RW_STATE_WORD0;
+ break;
+ }
+ }
+
+ mutex_unlock(&pit_state->lock);
+}
+
+static void pit_ioport_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *data)
+{
+ struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_kpit_state *pit_state = &pit->pit_state;
+ struct kvm *kvm = pit->kvm;
+ int ret, count;
+ struct kvm_kpit_channel_state *s;
+
+ addr &= KVM_PIT_CHANNEL_MASK;
+ s = &pit_state->channels[addr];
+
+ mutex_lock(&pit_state->lock);
+
+ if (s->status_latched) {
+ s->status_latched = 0;
+ ret = s->status;
+ } else if (s->count_latched) {
+ switch (s->count_latched) {
+ default:
+ case RW_STATE_LSB:
+ ret = s->latched_count & 0xff;
+ s->count_latched = 0;
+ break;
+ case RW_STATE_MSB:
+ ret = s->latched_count >> 8;
+ s->count_latched = 0;
+ break;
+ case RW_STATE_WORD0:
+ ret = s->latched_count & 0xff;
+ s->count_latched = RW_STATE_MSB;
+ break;
+ }
+ } else {
+ switch (s->read_state) {
+ default:
+ case RW_STATE_LSB:
+ count = pit_get_count(kvm, addr);
+ ret = count & 0xff;
+ break;
+ case RW_STATE_MSB:
+ count = pit_get_count(kvm, addr);
+ ret = (count >> 8) & 0xff;
+ break;
+ case RW_STATE_WORD0:
+ count = pit_get_count(kvm, addr);
+ ret = count & 0xff;
+ s->read_state = RW_STATE_WORD1;
+ break;
+ case RW_STATE_WORD1:
+ count = pit_get_count(kvm, addr);
+ ret = (count >> 8) & 0xff;
+ s->read_state = RW_STATE_WORD0;
+ break;
+ }
+ }
+
+ if (len > sizeof(ret))
+ len = sizeof(ret);
+ memcpy(data, (char *)&ret, len);
+
+ mutex_unlock(&pit_state->lock);
+}
+
+static int pit_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+ return ((addr >= KVM_PIT_BASE_ADDRESS) &&
+ (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
+}
+
+static void speaker_ioport_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *data)
+{
+ struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_kpit_state *pit_state = &pit->pit_state;
+ struct kvm *kvm = pit->kvm;
+ u32 val = *(u32 *) data;
+
+ mutex_lock(&pit_state->lock);
+ pit_state->speaker_data_on = (val >> 1) & 1;
+ pit_set_gate(kvm, 2, val & 1);
+ mutex_unlock(&pit_state->lock);
+}
+
+static void speaker_ioport_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *data)
+{
+ struct kvm_pit *pit = (struct kvm_pit *)this->private;
+ struct kvm_kpit_state *pit_state = &pit->pit_state;
+ struct kvm *kvm = pit->kvm;
+ unsigned int refresh_clock;
+ int ret;
+
+ /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
+ refresh_clock = ((unsigned int)ktime_to_ns(ktime_get()) >> 14) & 1;
+
+ mutex_lock(&pit_state->lock);
+ ret = ((pit_state->speaker_data_on << 1) | pit_get_gate(kvm, 2) |
+ (pit_get_out(kvm, 2) << 5) | (refresh_clock << 4));
+ if (len > sizeof(ret))
+ len = sizeof(ret);
+ memcpy(data, (char *)&ret, len);
+ mutex_unlock(&pit_state->lock);
+}
+
+static int speaker_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+ return (addr == KVM_SPEAKER_BASE_ADDRESS);
+}
+
+void kvm_pit_reset(struct kvm_pit *pit)
+{
+ int i;
+ struct kvm_kpit_channel_state *c;
+
+ mutex_lock(&pit->pit_state.lock);
+ for (i = 0; i < 3; i++) {
+ c = &pit->pit_state.channels[i];
+ c->mode = 0xff;
+ c->gate = (i != 2);
+ pit_load_count(pit->kvm, i, 0);
+ }
+ mutex_unlock(&pit->pit_state.lock);
+
+ atomic_set(&pit->pit_state.pit_timer.pending, 0);
+ pit->pit_state.inject_pending = 1;
+}
+
+struct kvm_pit *kvm_create_pit(struct kvm *kvm)
+{
+ struct kvm_pit *pit;
+ struct kvm_kpit_state *pit_state;
+
+ pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
+ if (!pit)
+ return NULL;
+
+ mutex_init(&pit->pit_state.lock);
+ mutex_lock(&pit->pit_state.lock);
+
+ /* Initialize PIO device */
+ pit->dev.read = pit_ioport_read;
+ pit->dev.write = pit_ioport_write;
+ pit->dev.in_range = pit_in_range;
+ pit->dev.private = pit;
+ kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+
+ pit->speaker_dev.read = speaker_ioport_read;
+ pit->speaker_dev.write = speaker_ioport_write;
+ pit->speaker_dev.in_range = speaker_in_range;
+ pit->speaker_dev.private = pit;
+ kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev);
+
+ kvm->arch.vpit = pit;
+ pit->kvm = kvm;
+
+ pit_state = &pit->pit_state;
+ pit_state->pit = pit;
+ hrtimer_init(&pit_state->pit_timer.timer,
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ mutex_unlock(&pit->pit_state.lock);
+
+ kvm_pit_reset(pit);
+
+ return pit;
+}
+
+void kvm_free_pit(struct kvm *kvm)
+{
+ struct hrtimer *timer;
+
+ if (kvm->arch.vpit) {
+ mutex_lock(&kvm->arch.vpit->pit_state.lock);
+ timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
+ hrtimer_cancel(timer);
+ mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+ kfree(kvm->arch.vpit);
+ }
+}
+
+void __inject_pit_timer_intr(struct kvm *kvm)
+{
+ mutex_lock(&kvm->lock);
+ kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1);
+ kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 0);
+ kvm_pic_set_irq(pic_irqchip(kvm), 0, 1);
+ kvm_pic_set_irq(pic_irqchip(kvm), 0, 0);
+ mutex_unlock(&kvm->lock);
+}
+
+void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pit *pit = vcpu->kvm->arch.vpit;
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_kpit_state *ps;
+
+ if (vcpu && pit) {
+ ps = &pit->pit_state;
+
+ /* Try to inject pending interrupts when:
+ * 1. Pending exists
+ * 2. Last interrupt was accepted or waited for too long time*/
+ if (atomic_read(&ps->pit_timer.pending) &&
+ (ps->inject_pending ||
+ (jiffies - ps->last_injected_time
+ >= KVM_MAX_PIT_INTR_INTERVAL))) {
+ ps->inject_pending = 0;
+ __inject_pit_timer_intr(kvm);
+ ps->last_injected_time = jiffies;
+ }
+ }
+}
+
+void kvm_pit_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+ struct kvm_arch *arch = &vcpu->kvm->arch;
+ struct kvm_kpit_state *ps;
+
+ if (vcpu && arch->vpit) {
+ ps = &arch->vpit->pit_state;
+ if (atomic_read(&ps->pit_timer.pending) &&
+ (((arch->vpic->pics[0].imr & 1) == 0 &&
+ arch->vpic->pics[0].irq_base == vec) ||
+ (arch->vioapic->redirtbl[0].fields.vector == vec &&
+ arch->vioapic->redirtbl[0].fields.mask != 1))) {
+ ps->inject_pending = 1;
+ atomic_dec(&ps->pit_timer.pending);
+ ps->channels[0].count_load_time = ktime_get();
+ }
+ }
+}
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
new file mode 100644
index 000000000000..db25c2a6c8c4
--- /dev/null
+++ b/arch/x86/kvm/i8254.h
@@ -0,0 +1,63 @@
+#ifndef __I8254_H
+#define __I8254_H
+
+#include "iodev.h"
+
+struct kvm_kpit_timer {
+ struct hrtimer timer;
+ int irq;
+ s64 period; /* unit: ns */
+ s64 scheduled;
+ ktime_t last_update;
+ atomic_t pending;
+};
+
+struct kvm_kpit_channel_state {
+ u32 count; /* can be 65536 */
+ u16 latched_count;
+ u8 count_latched;
+ u8 status_latched;
+ u8 status;
+ u8 read_state;
+ u8 write_state;
+ u8 write_latch;
+ u8 rw_mode;
+ u8 mode;
+ u8 bcd; /* not supported */
+ u8 gate; /* timer start */
+ ktime_t count_load_time;
+};
+
+struct kvm_kpit_state {
+ struct kvm_kpit_channel_state channels[3];
+ struct kvm_kpit_timer pit_timer;
+ u32 speaker_data_on;
+ struct mutex lock;
+ struct kvm_pit *pit;
+ bool inject_pending; /* if inject pending interrupts */
+ unsigned long last_injected_time;
+};
+
+struct kvm_pit {
+ unsigned long base_addresss;
+ struct kvm_io_device dev;
+ struct kvm_io_device speaker_dev;
+ struct kvm *kvm;
+ struct kvm_kpit_state pit_state;
+};
+
+#define KVM_PIT_BASE_ADDRESS 0x40
+#define KVM_SPEAKER_BASE_ADDRESS 0x61
+#define KVM_PIT_MEM_LENGTH 4
+#define KVM_PIT_FREQ 1193181
+#define KVM_MAX_PIT_INTR_INTERVAL HZ / 100
+#define KVM_PIT_CHANNEL_MASK 0x3
+
+void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_pit_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val);
+struct kvm_pit *kvm_create_pit(struct kvm *kvm);
+void kvm_free_pit(struct kvm *kvm);
+void kvm_pit_reset(struct kvm_pit *pit);
+
+#endif
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index e5714759e97f..ce1f583459b1 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -23,6 +23,22 @@
#include <linux/kvm_host.h>
#include "irq.h"
+#include "i8254.h"
+
+/*
+ * check if there are pending timer events
+ * to be processed.
+ */
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ int ret;
+
+ ret = pit_has_pending_timer(vcpu);
+ ret |= apic_has_pending_timer(vcpu);
+
+ return ret;
+}
+EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
/*
* check if there is pending interrupt without
@@ -66,6 +82,7 @@ EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
{
kvm_inject_apic_timer_irqs(vcpu);
+ kvm_inject_pit_timer_irqs(vcpu);
/* TODO: PIT, RTC etc. */
}
EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
@@ -73,6 +90,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
{
kvm_apic_timer_intr_post(vcpu, vec);
+ kvm_pit_timer_intr_post(vcpu, vec);
/* TODO: PIT, RTC etc. */
}
EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index fa5ed5d59b5d..1802134b836f 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -85,4 +85,7 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
+int pit_has_pending_timer(struct kvm_vcpu *vcpu);
+int apic_has_pending_timer(struct kvm_vcpu *vcpu);
+
#endif
diff --git a/arch/x86/kvm/kvm_svm.h b/arch/x86/kvm/kvm_svm.h
index ecdfe97e4635..65ef0fc2c036 100644
--- a/arch/x86/kvm/kvm_svm.h
+++ b/arch/x86/kvm/kvm_svm.h
@@ -39,6 +39,8 @@ struct vcpu_svm {
unsigned long host_db_regs[NUM_DB_REGS];
unsigned long host_dr6;
unsigned long host_dr7;
+
+ u32 *msrpm;
};
#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 68a6b1511934..57ac4e4c556a 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -338,10 +338,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
} else
apic_clear_vector(vector, apic->regs + APIC_TMR);
- if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE)
+ if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
kvm_vcpu_kick(vcpu);
- else if (vcpu->arch.mp_state == VCPU_MP_STATE_HALTED) {
- vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE;
+ else if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED) {
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
if (waitqueue_active(&vcpu->wq))
wake_up_interruptible(&vcpu->wq);
}
@@ -362,11 +362,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
case APIC_DM_INIT:
if (level) {
- if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE)
+ if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
printk(KERN_DEBUG
"INIT on a runnable vcpu %d\n",
vcpu->vcpu_id);
- vcpu->arch.mp_state = VCPU_MP_STATE_INIT_RECEIVED;
+ vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
kvm_vcpu_kick(vcpu);
} else {
printk(KERN_DEBUG
@@ -379,9 +379,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
case APIC_DM_STARTUP:
printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n",
vcpu->vcpu_id, vector);
- if (vcpu->arch.mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
+ if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
vcpu->arch.sipi_vector = vector;
- vcpu->arch.mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
+ vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED;
if (waitqueue_active(&vcpu->wq))
wake_up_interruptible(&vcpu->wq);
}
@@ -658,7 +658,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
PRIx64 ", "
"timer initial count 0x%x, period %lldns, "
- "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__,
+ "expire @ 0x%016" PRIx64 ".\n", __func__,
APIC_BUS_CYCLE_NS, ktime_to_ns(now),
apic_get_reg(apic, APIC_TMICT),
apic->timer.period,
@@ -691,7 +691,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
/* too common printing */
if (offset != APIC_EOI)
apic_debug("%s: offset 0x%x with length 0x%x, and value is "
- "0x%x\n", __FUNCTION__, offset, len, val);
+ "0x%x\n", __func__, offset, len, val);
offset &= 0xff0;
@@ -822,6 +822,7 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
| (apic_get_reg(apic, APIC_TASKPRI) & 4));
}
+EXPORT_SYMBOL_GPL(kvm_lapic_set_tpr);
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
{
@@ -869,7 +870,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
struct kvm_lapic *apic;
int i;
- apic_debug("%s\n", __FUNCTION__);
+ apic_debug("%s\n", __func__);
ASSERT(vcpu);
apic = vcpu->arch.apic;
@@ -907,7 +908,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
apic_update_ppr(apic);
apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
- "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__,
+ "0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__,
vcpu, kvm_apic_id(apic),
vcpu->arch.apic_base, apic->base_address);
}
@@ -940,7 +941,7 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
atomic_inc(&apic->timer.pending);
if (waitqueue_active(q)) {
- apic->vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE;
+ apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
wake_up_interruptible(q);
}
if (apic_lvtt_period(apic)) {
@@ -952,6 +953,16 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
return result;
}
+int apic_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *lapic = vcpu->arch.apic;
+
+ if (lapic)
+ return atomic_read(&lapic->timer.pending);
+
+ return 0;
+}
+
static int __inject_apic_timer_irq(struct kvm_lapic *apic)
{
int vector;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index e55af12e11b7..2ad6f5481671 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -27,11 +27,22 @@
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/swap.h>
+#include <linux/hugetlb.h>
+#include <linux/compiler.h>
#include <asm/page.h>
#include <asm/cmpxchg.h>
#include <asm/io.h>
+/*
+ * When setting this variable to true it enables Two-Dimensional-Paging
+ * where the hardware walks 2 page tables:
+ * 1. the guest-virtual to guest-physical
+ * 2. while doing 1. it walks guest-physical to host-physical
+ * If the hardware supports that we don't need to do shadow paging.
+ */
+bool tdp_enabled = false;
+
#undef MMU_DEBUG
#undef AUDIT
@@ -101,8 +112,6 @@ static int dbg = 1;
#define PT_FIRST_AVAIL_BITS_SHIFT 9
#define PT64_SECOND_AVAIL_BITS_SHIFT 52
-#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
-
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
#define PT64_LEVEL_BITS 9
@@ -159,6 +168,13 @@ static int dbg = 1;
#define ACC_USER_MASK PT_USER_MASK
#define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK)
+struct kvm_pv_mmu_op_buffer {
+ void *ptr;
+ unsigned len;
+ unsigned processed;
+ char buf[512] __aligned(sizeof(long));
+};
+
struct kvm_rmap_desc {
u64 *shadow_ptes[RMAP_EXT];
struct kvm_rmap_desc *more;
@@ -200,11 +216,15 @@ static int is_present_pte(unsigned long pte)
static int is_shadow_present_pte(u64 pte)
{
- pte &= ~PT_SHADOW_IO_MARK;
return pte != shadow_trap_nonpresent_pte
&& pte != shadow_notrap_nonpresent_pte;
}
+static int is_large_pte(u64 pte)
+{
+ return pte & PT_PAGE_SIZE_MASK;
+}
+
static int is_writeble_pte(unsigned long pte)
{
return pte & PT_WRITABLE_MASK;
@@ -215,14 +235,14 @@ static int is_dirty_pte(unsigned long pte)
return pte & PT_DIRTY_MASK;
}
-static int is_io_pte(unsigned long pte)
+static int is_rmap_pte(u64 pte)
{
- return pte & PT_SHADOW_IO_MARK;
+ return is_shadow_present_pte(pte);
}
-static int is_rmap_pte(u64 pte)
+static pfn_t spte_to_pfn(u64 pte)
{
- return is_shadow_present_pte(pte);
+ return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
}
static gfn_t pse36_gfn_delta(u32 gpte)
@@ -349,16 +369,100 @@ static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
}
/*
+ * Return the pointer to the largepage write count for a given
+ * gfn, handling slots that are not large page aligned.
+ */
+static int *slot_largepage_idx(gfn_t gfn, struct kvm_memory_slot *slot)
+{
+ unsigned long idx;
+
+ idx = (gfn / KVM_PAGES_PER_HPAGE) -
+ (slot->base_gfn / KVM_PAGES_PER_HPAGE);
+ return &slot->lpage_info[idx].write_count;
+}
+
+static void account_shadowed(struct kvm *kvm, gfn_t gfn)
+{
+ int *write_count;
+
+ write_count = slot_largepage_idx(gfn, gfn_to_memslot(kvm, gfn));
+ *write_count += 1;
+ WARN_ON(*write_count > KVM_PAGES_PER_HPAGE);
+}
+
+static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn)
+{
+ int *write_count;
+
+ write_count = slot_largepage_idx(gfn, gfn_to_memslot(kvm, gfn));
+ *write_count -= 1;
+ WARN_ON(*write_count < 0);
+}
+
+static int has_wrprotected_page(struct kvm *kvm, gfn_t gfn)
+{
+ struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
+ int *largepage_idx;
+
+ if (slot) {
+ largepage_idx = slot_largepage_idx(gfn, slot);
+ return *largepage_idx;
+ }
+
+ return 1;
+}
+
+static int host_largepage_backed(struct kvm *kvm, gfn_t gfn)
+{
+ struct vm_area_struct *vma;
+ unsigned long addr;
+
+ addr = gfn_to_hva(kvm, gfn);
+ if (kvm_is_error_hva(addr))
+ return 0;
+
+ vma = find_vma(current->mm, addr);
+ if (vma && is_vm_hugetlb_page(vma))
+ return 1;
+
+ return 0;
+}
+
+static int is_largepage_backed(struct kvm_vcpu *vcpu, gfn_t large_gfn)
+{
+ struct kvm_memory_slot *slot;
+
+ if (has_wrprotected_page(vcpu->kvm, large_gfn))
+ return 0;
+
+ if (!host_largepage_backed(vcpu->kvm, large_gfn))
+ return 0;
+
+ slot = gfn_to_memslot(vcpu->kvm, large_gfn);
+ if (slot && slot->dirty_bitmap)
+ return 0;
+
+ return 1;
+}
+
+/*
* Take gfn and return the reverse mapping to it.
* Note: gfn must be unaliased before this function get called
*/
-static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn)
+static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int lpage)
{
struct kvm_memory_slot *slot;
+ unsigned long idx;
slot = gfn_to_memslot(kvm, gfn);
- return &slot->rmap[gfn - slot->base_gfn];
+ if (!lpage)
+ return &slot->rmap[gfn - slot->base_gfn];
+
+ idx = (gfn / KVM_PAGES_PER_HPAGE) -
+ (slot->base_gfn / KVM_PAGES_PER_HPAGE);
+
+ return &slot->lpage_info[idx].rmap_pde;
}
/*
@@ -370,7 +474,7 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn)
* If rmapp bit zero is one, (then rmap & ~1) points to a struct kvm_rmap_desc
* containing more mappings.
*/
-static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
+static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage)
{
struct kvm_mmu_page *sp;
struct kvm_rmap_desc *desc;
@@ -382,7 +486,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
gfn = unalias_gfn(vcpu->kvm, gfn);
sp = page_header(__pa(spte));
sp->gfns[spte - sp->spt] = gfn;
- rmapp = gfn_to_rmap(vcpu->kvm, gfn);
+ rmapp = gfn_to_rmap(vcpu->kvm, gfn, lpage);
if (!*rmapp) {
rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
*rmapp = (unsigned long)spte;
@@ -435,20 +539,21 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
struct kvm_rmap_desc *desc;
struct kvm_rmap_desc *prev_desc;
struct kvm_mmu_page *sp;
- struct page *page;
+ pfn_t pfn;
unsigned long *rmapp;
int i;
if (!is_rmap_pte(*spte))
return;
sp = page_header(__pa(spte));
- page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
- mark_page_accessed(page);
+ pfn = spte_to_pfn(*spte);
+ if (*spte & PT_ACCESSED_MASK)
+ kvm_set_pfn_accessed(pfn);
if (is_writeble_pte(*spte))
- kvm_release_page_dirty(page);
+ kvm_release_pfn_dirty(pfn);
else
- kvm_release_page_clean(page);
- rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt]);
+ kvm_release_pfn_clean(pfn);
+ rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], is_large_pte(*spte));
if (!*rmapp) {
printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
BUG();
@@ -514,7 +619,7 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn)
int write_protected = 0;
gfn = unalias_gfn(kvm, gfn);
- rmapp = gfn_to_rmap(kvm, gfn);
+ rmapp = gfn_to_rmap(kvm, gfn, 0);
spte = rmap_next(kvm, rmapp, NULL);
while (spte) {
@@ -527,8 +632,35 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn)
}
spte = rmap_next(kvm, rmapp, spte);
}
+ if (write_protected) {
+ pfn_t pfn;
+
+ spte = rmap_next(kvm, rmapp, NULL);
+ pfn = spte_to_pfn(*spte);
+ kvm_set_pfn_dirty(pfn);
+ }
+
+ /* check for huge page mappings */
+ rmapp = gfn_to_rmap(kvm, gfn, 1);
+ spte = rmap_next(kvm, rmapp, NULL);
+ while (spte) {
+ BUG_ON(!spte);
+ BUG_ON(!(*spte & PT_PRESENT_MASK));
+ BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK));
+ pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn);
+ if (is_writeble_pte(*spte)) {
+ rmap_remove(kvm, spte);
+ --kvm->stat.lpages;
+ set_shadow_pte(spte, shadow_trap_nonpresent_pte);
+ write_protected = 1;
+ }
+ spte = rmap_next(kvm, rmapp, spte);
+ }
+
if (write_protected)
kvm_flush_remote_tlbs(kvm);
+
+ account_shadowed(kvm, gfn);
}
#ifdef MMU_DEBUG
@@ -538,8 +670,8 @@ static int is_empty_shadow_page(u64 *spt)
u64 *end;
for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++)
- if ((*pos & ~PT_SHADOW_IO_MARK) != shadow_trap_nonpresent_pte) {
- printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__,
+ if (*pos != shadow_trap_nonpresent_pte) {
+ printk(KERN_ERR "%s: %p %llx\n", __func__,
pos, *pos);
return 0;
}
@@ -559,7 +691,7 @@ static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
static unsigned kvm_page_table_hashfn(gfn_t gfn)
{
- return gfn;
+ return gfn & ((1 << KVM_MMU_HASH_SHIFT) - 1);
}
static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
@@ -662,13 +794,14 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn)
struct kvm_mmu_page *sp;
struct hlist_node *node;
- pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn);
- index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
+ index = kvm_page_table_hashfn(gfn);
bucket = &kvm->arch.mmu_page_hash[index];
hlist_for_each_entry(sp, node, bucket, hash_link)
- if (sp->gfn == gfn && !sp->role.metaphysical) {
+ if (sp->gfn == gfn && !sp->role.metaphysical
+ && !sp->role.invalid) {
pgprintk("%s: found role %x\n",
- __FUNCTION__, sp->role.word);
+ __func__, sp->role.word);
return sp;
}
return NULL;
@@ -699,27 +832,27 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
role.quadrant = quadrant;
}
- pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__,
+ pgprintk("%s: looking gfn %lx role %x\n", __func__,
gfn, role.word);
- index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ index = kvm_page_table_hashfn(gfn);
bucket = &vcpu->kvm->arch.mmu_page_hash[index];
hlist_for_each_entry(sp, node, bucket, hash_link)
if (sp->gfn == gfn && sp->role.word == role.word) {
mmu_page_add_parent_pte(vcpu, sp, parent_pte);
- pgprintk("%s: found\n", __FUNCTION__);
+ pgprintk("%s: found\n", __func__);
return sp;
}
++vcpu->kvm->stat.mmu_cache_miss;
sp = kvm_mmu_alloc_page(vcpu, parent_pte);
if (!sp)
return sp;
- pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word);
+ pgprintk("%s: adding gfn %lx role %x\n", __func__, gfn, role.word);
sp->gfn = gfn;
sp->role = role;
hlist_add_head(&sp->hash_link, bucket);
- vcpu->arch.mmu.prefetch_page(vcpu, sp);
if (!metaphysical)
rmap_write_protect(vcpu->kvm, gfn);
+ vcpu->arch.mmu.prefetch_page(vcpu, sp);
return sp;
}
@@ -745,11 +878,17 @@ static void kvm_mmu_page_unlink_children(struct kvm *kvm,
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
ent = pt[i];
+ if (is_shadow_present_pte(ent)) {
+ if (!is_large_pte(ent)) {
+ ent &= PT64_BASE_ADDR_MASK;
+ mmu_page_remove_parent_pte(page_header(ent),
+ &pt[i]);
+ } else {
+ --kvm->stat.lpages;
+ rmap_remove(kvm, &pt[i]);
+ }
+ }
pt[i] = shadow_trap_nonpresent_pte;
- if (!is_shadow_present_pte(ent))
- continue;
- ent &= PT64_BASE_ADDR_MASK;
- mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
}
kvm_flush_remote_tlbs(kvm);
}
@@ -789,10 +928,15 @@ static void kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
}
kvm_mmu_page_unlink_children(kvm, sp);
if (!sp->root_count) {
+ if (!sp->role.metaphysical)
+ unaccount_shadowed(kvm, sp->gfn);
hlist_del(&sp->hash_link);
kvm_mmu_free_page(kvm, sp);
- } else
+ } else {
list_move(&sp->link, &kvm->arch.active_mmu_pages);
+ sp->role.invalid = 1;
+ kvm_reload_remote_mmus(kvm);
+ }
kvm_mmu_reset_last_pte_updated(kvm);
}
@@ -838,13 +982,13 @@ static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
struct hlist_node *node, *n;
int r;
- pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn);
+ pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
r = 0;
- index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ index = kvm_page_table_hashfn(gfn);
bucket = &kvm->arch.mmu_page_hash[index];
hlist_for_each_entry_safe(sp, node, n, bucket, hash_link)
if (sp->gfn == gfn && !sp->role.metaphysical) {
- pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
+ pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
sp->role.word);
kvm_mmu_zap_page(kvm, sp);
r = 1;
@@ -857,7 +1001,7 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn)
struct kvm_mmu_page *sp;
while ((sp = kvm_mmu_lookup_page(kvm, gfn)) != NULL) {
- pgprintk("%s: zap %lx %x\n", __FUNCTION__, gfn, sp->role.word);
+ pgprintk("%s: zap %lx %x\n", __func__, gfn, sp->role.word);
kvm_mmu_zap_page(kvm, sp);
}
}
@@ -889,26 +1033,39 @@ struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva)
static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
unsigned pt_access, unsigned pte_access,
int user_fault, int write_fault, int dirty,
- int *ptwrite, gfn_t gfn, struct page *page)
+ int *ptwrite, int largepage, gfn_t gfn,
+ pfn_t pfn, bool speculative)
{
u64 spte;
int was_rmapped = 0;
int was_writeble = is_writeble_pte(*shadow_pte);
- hfn_t host_pfn = (*shadow_pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
pgprintk("%s: spte %llx access %x write_fault %d"
" user_fault %d gfn %lx\n",
- __FUNCTION__, *shadow_pte, pt_access,
+ __func__, *shadow_pte, pt_access,
write_fault, user_fault, gfn);
if (is_rmap_pte(*shadow_pte)) {
- if (host_pfn != page_to_pfn(page)) {
+ /*
+ * If we overwrite a PTE page pointer with a 2MB PMD, unlink
+ * the parent of the now unreachable PTE.
+ */
+ if (largepage && !is_large_pte(*shadow_pte)) {
+ struct kvm_mmu_page *child;
+ u64 pte = *shadow_pte;
+
+ child = page_header(pte & PT64_BASE_ADDR_MASK);
+ mmu_page_remove_parent_pte(child, shadow_pte);
+ } else if (pfn != spte_to_pfn(*shadow_pte)) {
pgprintk("hfn old %lx new %lx\n",
- host_pfn, page_to_pfn(page));
+ spte_to_pfn(*shadow_pte), pfn);
rmap_remove(vcpu->kvm, shadow_pte);
+ } else {
+ if (largepage)
+ was_rmapped = is_large_pte(*shadow_pte);
+ else
+ was_rmapped = 1;
}
- else
- was_rmapped = 1;
}
/*
@@ -917,6 +1074,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
* demand paging).
*/
spte = PT_PRESENT_MASK | PT_DIRTY_MASK;
+ if (!speculative)
+ pte_access |= PT_ACCESSED_MASK;
if (!dirty)
pte_access &= ~ACC_WRITE_MASK;
if (!(pte_access & ACC_EXEC_MASK))
@@ -925,15 +1084,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
spte |= PT_PRESENT_MASK;
if (pte_access & ACC_USER_MASK)
spte |= PT_USER_MASK;
+ if (largepage)
+ spte |= PT_PAGE_SIZE_MASK;
- if (is_error_page(page)) {
- set_shadow_pte(shadow_pte,
- shadow_trap_nonpresent_pte | PT_SHADOW_IO_MARK);
- kvm_release_page_clean(page);
- return;
- }
-
- spte |= page_to_phys(page);
+ spte |= (u64)pfn << PAGE_SHIFT;
if ((pte_access & ACC_WRITE_MASK)
|| (write_fault && !is_write_protection(vcpu) && !user_fault)) {
@@ -946,9 +1100,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
}
shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn);
- if (shadow) {
+ if (shadow ||
+ (largepage && has_wrprotected_page(vcpu->kvm, gfn))) {
pgprintk("%s: found shadow page for %lx, marking ro\n",
- __FUNCTION__, gfn);
+ __func__, gfn);
pte_access &= ~ACC_WRITE_MASK;
if (is_writeble_pte(spte)) {
spte &= ~PT_WRITABLE_MASK;
@@ -964,18 +1119,25 @@ unshadowed:
if (pte_access & ACC_WRITE_MASK)
mark_page_dirty(vcpu->kvm, gfn);
- pgprintk("%s: setting spte %llx\n", __FUNCTION__, spte);
+ pgprintk("%s: setting spte %llx\n", __func__, spte);
+ pgprintk("instantiating %s PTE (%s) at %d (%llx) addr %llx\n",
+ (spte&PT_PAGE_SIZE_MASK)? "2MB" : "4kB",
+ (spte&PT_WRITABLE_MASK)?"RW":"R", gfn, spte, shadow_pte);
set_shadow_pte(shadow_pte, spte);
+ if (!was_rmapped && (spte & PT_PAGE_SIZE_MASK)
+ && (spte & PT_PRESENT_MASK))
+ ++vcpu->kvm->stat.lpages;
+
page_header_update_slot(vcpu->kvm, shadow_pte, gfn);
if (!was_rmapped) {
- rmap_add(vcpu, shadow_pte, gfn);
+ rmap_add(vcpu, shadow_pte, gfn, largepage);
if (!is_rmap_pte(*shadow_pte))
- kvm_release_page_clean(page);
+ kvm_release_pfn_clean(pfn);
} else {
if (was_writeble)
- kvm_release_page_dirty(page);
+ kvm_release_pfn_dirty(pfn);
else
- kvm_release_page_clean(page);
+ kvm_release_pfn_clean(pfn);
}
if (!ptwrite || !*ptwrite)
vcpu->arch.last_pte_updated = shadow_pte;
@@ -985,10 +1147,10 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
{
}
-static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write,
- gfn_t gfn, struct page *page)
+static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
+ int largepage, gfn_t gfn, pfn_t pfn,
+ int level)
{
- int level = PT32E_ROOT_LEVEL;
hpa_t table_addr = vcpu->arch.mmu.root_hpa;
int pt_write = 0;
@@ -1001,8 +1163,14 @@ static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write,
if (level == 1) {
mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL,
- 0, write, 1, &pt_write, gfn, page);
- return pt_write || is_io_pte(table[index]);
+ 0, write, 1, &pt_write, 0, gfn, pfn, false);
+ return pt_write;
+ }
+
+ if (largepage && level == 2) {
+ mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL,
+ 0, write, 1, &pt_write, 1, gfn, pfn, false);
+ return pt_write;
}
if (table[index] == shadow_trap_nonpresent_pte) {
@@ -1016,7 +1184,7 @@ static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write,
1, ACC_ALL, &table[index]);
if (!new_table) {
pgprintk("nonpaging_map: ENOMEM\n");
- kvm_release_page_clean(page);
+ kvm_release_pfn_clean(pfn);
return -ENOMEM;
}
@@ -1030,21 +1198,30 @@ static int __nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write,
static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)
{
int r;
-
- struct page *page;
-
- down_read(&vcpu->kvm->slots_lock);
+ int largepage = 0;
+ pfn_t pfn;
down_read(&current->mm->mmap_sem);
- page = gfn_to_page(vcpu->kvm, gfn);
+ if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) {
+ gfn &= ~(KVM_PAGES_PER_HPAGE-1);
+ largepage = 1;
+ }
+
+ pfn = gfn_to_pfn(vcpu->kvm, gfn);
up_read(&current->mm->mmap_sem);
+ /* mmio */
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
+ return 1;
+ }
+
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
- r = __nonpaging_map(vcpu, v, write, gfn, page);
+ r = __direct_map(vcpu, v, write, largepage, gfn, pfn,
+ PT32E_ROOT_LEVEL);
spin_unlock(&vcpu->kvm->mmu_lock);
- up_read(&vcpu->kvm->slots_lock);
return r;
}
@@ -1073,6 +1250,8 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
sp = page_header(root);
--sp->root_count;
+ if (!sp->root_count && sp->role.invalid)
+ kvm_mmu_zap_page(vcpu->kvm, sp);
vcpu->arch.mmu.root_hpa = INVALID_PAGE;
spin_unlock(&vcpu->kvm->mmu_lock);
return;
@@ -1085,6 +1264,8 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
root &= PT64_BASE_ADDR_MASK;
sp = page_header(root);
--sp->root_count;
+ if (!sp->root_count && sp->role.invalid)
+ kvm_mmu_zap_page(vcpu->kvm, sp);
}
vcpu->arch.mmu.pae_root[i] = INVALID_PAGE;
}
@@ -1097,6 +1278,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
int i;
gfn_t root_gfn;
struct kvm_mmu_page *sp;
+ int metaphysical = 0;
root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT;
@@ -1105,14 +1287,20 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
hpa_t root = vcpu->arch.mmu.root_hpa;
ASSERT(!VALID_PAGE(root));
+ if (tdp_enabled)
+ metaphysical = 1;
sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
- PT64_ROOT_LEVEL, 0, ACC_ALL, NULL);
+ PT64_ROOT_LEVEL, metaphysical,
+ ACC_ALL, NULL);
root = __pa(sp->spt);
++sp->root_count;
vcpu->arch.mmu.root_hpa = root;
return;
}
#endif
+ metaphysical = !is_paging(vcpu);
+ if (tdp_enabled)
+ metaphysical = 1;
for (i = 0; i < 4; ++i) {
hpa_t root = vcpu->arch.mmu.pae_root[i];
@@ -1126,7 +1314,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
} else if (vcpu->arch.mmu.root_level == 0)
root_gfn = 0;
sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
- PT32_ROOT_LEVEL, !is_paging(vcpu),
+ PT32_ROOT_LEVEL, metaphysical,
ACC_ALL, NULL);
root = __pa(sp->spt);
++sp->root_count;
@@ -1146,7 +1334,7 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
gfn_t gfn;
int r;
- pgprintk("%s: gva %lx error %x\n", __FUNCTION__, gva, error_code);
+ pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code);
r = mmu_topup_memory_caches(vcpu);
if (r)
return r;
@@ -1160,6 +1348,41 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
error_code & PFERR_WRITE_MASK, gfn);
}
+static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,
+ u32 error_code)
+{
+ pfn_t pfn;
+ int r;
+ int largepage = 0;
+ gfn_t gfn = gpa >> PAGE_SHIFT;
+
+ ASSERT(vcpu);
+ ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa));
+
+ r = mmu_topup_memory_caches(vcpu);
+ if (r)
+ return r;
+
+ down_read(&current->mm->mmap_sem);
+ if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) {
+ gfn &= ~(KVM_PAGES_PER_HPAGE-1);
+ largepage = 1;
+ }
+ pfn = gfn_to_pfn(vcpu->kvm, gfn);
+ up_read(&current->mm->mmap_sem);
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
+ return 1;
+ }
+ spin_lock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_free_some_pages(vcpu);
+ r = __direct_map(vcpu, gpa, error_code & PFERR_WRITE_MASK,
+ largepage, gfn, pfn, TDP_ROOT_LEVEL);
+ spin_unlock(&vcpu->kvm->mmu_lock);
+
+ return r;
+}
+
static void nonpaging_free(struct kvm_vcpu *vcpu)
{
mmu_free_roots(vcpu);
@@ -1188,7 +1411,7 @@ void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
static void paging_new_cr3(struct kvm_vcpu *vcpu)
{
- pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->arch.cr3);
+ pgprintk("%s: cr3 %lx\n", __func__, vcpu->arch.cr3);
mmu_free_roots(vcpu);
}
@@ -1253,7 +1476,35 @@ static int paging32E_init_context(struct kvm_vcpu *vcpu)
return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL);
}
-static int init_kvm_mmu(struct kvm_vcpu *vcpu)
+static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
+{
+ struct kvm_mmu *context = &vcpu->arch.mmu;
+
+ context->new_cr3 = nonpaging_new_cr3;
+ context->page_fault = tdp_page_fault;
+ context->free = nonpaging_free;
+ context->prefetch_page = nonpaging_prefetch_page;
+ context->shadow_root_level = TDP_ROOT_LEVEL;
+ context->root_hpa = INVALID_PAGE;
+
+ if (!is_paging(vcpu)) {
+ context->gva_to_gpa = nonpaging_gva_to_gpa;
+ context->root_level = 0;
+ } else if (is_long_mode(vcpu)) {
+ context->gva_to_gpa = paging64_gva_to_gpa;
+ context->root_level = PT64_ROOT_LEVEL;
+ } else if (is_pae(vcpu)) {
+ context->gva_to_gpa = paging64_gva_to_gpa;
+ context->root_level = PT32E_ROOT_LEVEL;
+ } else {
+ context->gva_to_gpa = paging32_gva_to_gpa;
+ context->root_level = PT32_ROOT_LEVEL;
+ }
+
+ return 0;
+}
+
+static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
{
ASSERT(vcpu);
ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa));
@@ -1268,6 +1519,16 @@ static int init_kvm_mmu(struct kvm_vcpu *vcpu)
return paging32_init_context(vcpu);
}
+static int init_kvm_mmu(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.update_pte.pfn = bad_pfn;
+
+ if (tdp_enabled)
+ return init_kvm_tdp_mmu(vcpu);
+ else
+ return init_kvm_softmmu(vcpu);
+}
+
static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
{
ASSERT(vcpu);
@@ -1316,7 +1577,8 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
pte = *spte;
if (is_shadow_present_pte(pte)) {
- if (sp->role.level == PT_PAGE_TABLE_LEVEL)
+ if (sp->role.level == PT_PAGE_TABLE_LEVEL ||
+ is_large_pte(pte))
rmap_remove(vcpu->kvm, spte);
else {
child = page_header(pte & PT64_BASE_ADDR_MASK);
@@ -1324,24 +1586,26 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
}
}
set_shadow_pte(spte, shadow_trap_nonpresent_pte);
+ if (is_large_pte(pte))
+ --vcpu->kvm->stat.lpages;
}
static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp,
u64 *spte,
- const void *new, int bytes,
- int offset_in_pte)
+ const void *new)
{
- if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
+ if ((sp->role.level != PT_PAGE_TABLE_LEVEL)
+ && !vcpu->arch.update_pte.largepage) {
++vcpu->kvm->stat.mmu_pde_zapped;
return;
}
++vcpu->kvm->stat.mmu_pte_updated;
if (sp->role.glevels == PT32_ROOT_LEVEL)
- paging32_update_pte(vcpu, sp, spte, new, bytes, offset_in_pte);
+ paging32_update_pte(vcpu, sp, spte, new);
else
- paging64_update_pte(vcpu, sp, spte, new, bytes, offset_in_pte);
+ paging64_update_pte(vcpu, sp, spte, new);
}
static bool need_remote_flush(u64 old, u64 new)
@@ -1378,7 +1642,9 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
gfn_t gfn;
int r;
u64 gpte = 0;
- struct page *page;
+ pfn_t pfn;
+
+ vcpu->arch.update_pte.largepage = 0;
if (bytes != 4 && bytes != 8)
return;
@@ -1408,11 +1674,19 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
down_read(&current->mm->mmap_sem);
- page = gfn_to_page(vcpu->kvm, gfn);
+ if (is_large_pte(gpte) && is_largepage_backed(vcpu, gfn)) {
+ gfn &= ~(KVM_PAGES_PER_HPAGE-1);
+ vcpu->arch.update_pte.largepage = 1;
+ }
+ pfn = gfn_to_pfn(vcpu->kvm, gfn);
up_read(&current->mm->mmap_sem);
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
+ return;
+ }
vcpu->arch.update_pte.gfn = gfn;
- vcpu->arch.update_pte.page = page;
+ vcpu->arch.update_pte.pfn = pfn;
}
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -1423,7 +1697,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
struct hlist_node *node, *n;
struct hlist_head *bucket;
unsigned index;
- u64 entry;
+ u64 entry, gentry;
u64 *spte;
unsigned offset = offset_in_page(gpa);
unsigned pte_size;
@@ -1433,8 +1707,9 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
int level;
int flooded = 0;
int npte;
+ int r;
- pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes);
+ pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes);
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
@@ -1450,7 +1725,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
vcpu->arch.last_pt_write_count = 1;
vcpu->arch.last_pte_updated = NULL;
}
- index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
+ index = kvm_page_table_hashfn(gfn);
bucket = &vcpu->kvm->arch.mmu_page_hash[index];
hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) {
if (sp->gfn != gfn || sp->role.metaphysical)
@@ -1496,20 +1771,29 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
continue;
}
spte = &sp->spt[page_offset / sizeof(*spte)];
+ if ((gpa & (pte_size - 1)) || (bytes < pte_size)) {
+ gentry = 0;
+ r = kvm_read_guest_atomic(vcpu->kvm,
+ gpa & ~(u64)(pte_size - 1),
+ &gentry, pte_size);
+ new = (const void *)&gentry;
+ if (r < 0)
+ new = NULL;
+ }
while (npte--) {
entry = *spte;
mmu_pte_write_zap_pte(vcpu, sp, spte);
- mmu_pte_write_new_pte(vcpu, sp, spte, new, bytes,
- page_offset & (pte_size - 1));
+ if (new)
+ mmu_pte_write_new_pte(vcpu, sp, spte, new);
mmu_pte_write_flush_tlb(vcpu, entry, *spte);
++spte;
}
}
kvm_mmu_audit(vcpu, "post pte write");
spin_unlock(&vcpu->kvm->mmu_lock);
- if (vcpu->arch.update_pte.page) {
- kvm_release_page_clean(vcpu->arch.update_pte.page);
- vcpu->arch.update_pte.page = NULL;
+ if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
+ kvm_release_pfn_clean(vcpu->arch.update_pte.pfn);
+ vcpu->arch.update_pte.pfn = bad_pfn;
}
}
@@ -1518,9 +1802,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
gpa_t gpa;
int r;
- down_read(&vcpu->kvm->slots_lock);
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva);
- up_read(&vcpu->kvm->slots_lock);
spin_lock(&vcpu->kvm->mmu_lock);
r = kvm_mmu_unprotect_page(vcpu->kvm, gpa >> PAGE_SHIFT);
@@ -1577,6 +1859,12 @@ out:
}
EXPORT_SYMBOL_GPL(kvm_mmu_page_fault);
+void kvm_enable_tdp(void)
+{
+ tdp_enabled = true;
+}
+EXPORT_SYMBOL_GPL(kvm_enable_tdp);
+
static void free_mmu_pages(struct kvm_vcpu *vcpu)
{
struct kvm_mmu_page *sp;
@@ -1677,7 +1965,53 @@ void kvm_mmu_zap_all(struct kvm *kvm)
kvm_flush_remote_tlbs(kvm);
}
-void kvm_mmu_module_exit(void)
+void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm)
+{
+ struct kvm_mmu_page *page;
+
+ page = container_of(kvm->arch.active_mmu_pages.prev,
+ struct kvm_mmu_page, link);
+ kvm_mmu_zap_page(kvm, page);
+}
+
+static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
+{
+ struct kvm *kvm;
+ struct kvm *kvm_freed = NULL;
+ int cache_count = 0;
+
+ spin_lock(&kvm_lock);
+
+ list_for_each_entry(kvm, &vm_list, vm_list) {
+ int npages;
+
+ spin_lock(&kvm->mmu_lock);
+ npages = kvm->arch.n_alloc_mmu_pages -
+ kvm->arch.n_free_mmu_pages;
+ cache_count += npages;
+ if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
+ kvm_mmu_remove_one_alloc_mmu_page(kvm);
+ cache_count--;
+ kvm_freed = kvm;
+ }
+ nr_to_scan--;
+
+ spin_unlock(&kvm->mmu_lock);
+ }
+ if (kvm_freed)
+ list_move_tail(&kvm_freed->vm_list, &vm_list);
+
+ spin_unlock(&kvm_lock);
+
+ return cache_count;
+}
+
+static struct shrinker mmu_shrinker = {
+ .shrink = mmu_shrink,
+ .seeks = DEFAULT_SEEKS * 10,
+};
+
+void mmu_destroy_caches(void)
{
if (pte_chain_cache)
kmem_cache_destroy(pte_chain_cache);
@@ -1687,6 +2021,12 @@ void kvm_mmu_module_exit(void)
kmem_cache_destroy(mmu_page_header_cache);
}
+void kvm_mmu_module_exit(void)
+{
+ mmu_destroy_caches();
+ unregister_shrinker(&mmu_shrinker);
+}
+
int kvm_mmu_module_init(void)
{
pte_chain_cache = kmem_cache_create("kvm_pte_chain",
@@ -1706,10 +2046,12 @@ int kvm_mmu_module_init(void)
if (!mmu_page_header_cache)
goto nomem;
+ register_shrinker(&mmu_shrinker);
+
return 0;
nomem:
- kvm_mmu_module_exit();
+ mmu_destroy_caches();
return -ENOMEM;
}
@@ -1732,6 +2074,127 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm)
return nr_mmu_pages;
}
+static void *pv_mmu_peek_buffer(struct kvm_pv_mmu_op_buffer *buffer,
+ unsigned len)
+{
+ if (len > buffer->len)
+ return NULL;
+ return buffer->ptr;
+}
+
+static void *pv_mmu_read_buffer(struct kvm_pv_mmu_op_buffer *buffer,
+ unsigned len)
+{
+ void *ret;
+
+ ret = pv_mmu_peek_buffer(buffer, len);
+ if (!ret)
+ return ret;
+ buffer->ptr += len;
+ buffer->len -= len;
+ buffer->processed += len;
+ return ret;
+}
+
+static int kvm_pv_mmu_write(struct kvm_vcpu *vcpu,
+ gpa_t addr, gpa_t value)
+{
+ int bytes = 8;
+ int r;
+
+ if (!is_long_mode(vcpu) && !is_pae(vcpu))
+ bytes = 4;
+
+ r = mmu_topup_memory_caches(vcpu);
+ if (r)
+ return r;
+
+ if (!emulator_write_phys(vcpu, addr, &value, bytes))
+ return -EFAULT;
+
+ return 1;
+}
+
+static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ kvm_x86_ops->tlb_flush(vcpu);
+ return 1;
+}
+
+static int kvm_pv_mmu_release_pt(struct kvm_vcpu *vcpu, gpa_t addr)
+{
+ spin_lock(&vcpu->kvm->mmu_lock);
+ mmu_unshadow(vcpu->kvm, addr >> PAGE_SHIFT);
+ spin_unlock(&vcpu->kvm->mmu_lock);
+ return 1;
+}
+
+static int kvm_pv_mmu_op_one(struct kvm_vcpu *vcpu,
+ struct kvm_pv_mmu_op_buffer *buffer)
+{
+ struct kvm_mmu_op_header *header;
+
+ header = pv_mmu_peek_buffer(buffer, sizeof *header);
+ if (!header)
+ return 0;
+ switch (header->op) {
+ case KVM_MMU_OP_WRITE_PTE: {
+ struct kvm_mmu_op_write_pte *wpte;
+
+ wpte = pv_mmu_read_buffer(buffer, sizeof *wpte);
+ if (!wpte)
+ return 0;
+ return kvm_pv_mmu_write(vcpu, wpte->pte_phys,
+ wpte->pte_val);
+ }
+ case KVM_MMU_OP_FLUSH_TLB: {
+ struct kvm_mmu_op_flush_tlb *ftlb;
+
+ ftlb = pv_mmu_read_buffer(buffer, sizeof *ftlb);
+ if (!ftlb)
+ return 0;
+ return kvm_pv_mmu_flush_tlb(vcpu);
+ }
+ case KVM_MMU_OP_RELEASE_PT: {
+ struct kvm_mmu_op_release_pt *rpt;
+
+ rpt = pv_mmu_read_buffer(buffer, sizeof *rpt);
+ if (!rpt)
+ return 0;
+ return kvm_pv_mmu_release_pt(vcpu, rpt->pt_phys);
+ }
+ default: return 0;
+ }
+}
+
+int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
+ gpa_t addr, unsigned long *ret)
+{
+ int r;
+ struct kvm_pv_mmu_op_buffer buffer;
+
+ buffer.ptr = buffer.buf;
+ buffer.len = min_t(unsigned long, bytes, sizeof buffer.buf);
+ buffer.processed = 0;
+
+ r = kvm_read_guest(vcpu->kvm, addr, buffer.buf, buffer.len);
+ if (r)
+ goto out;
+
+ while (buffer.len) {
+ r = kvm_pv_mmu_op_one(vcpu, &buffer);
+ if (r < 0)
+ goto out;
+ if (r == 0)
+ break;
+ }
+
+ r = 1;
+out:
+ *ret = buffer.processed;
+ return r;
+}
+
#ifdef AUDIT
static const char *audit_msg;
@@ -1768,8 +2231,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
audit_mappings_page(vcpu, ent, va, level - 1);
} else {
gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va);
- struct page *page = gpa_to_page(vcpu, gpa);
- hpa_t hpa = page_to_phys(page);
+ hpa_t hpa = (hpa_t)gpa_to_pfn(vcpu, gpa) << PAGE_SHIFT;
if (is_shadow_present_pte(ent)
&& (ent & PT64_BASE_ADDR_MASK) != hpa)
@@ -1782,7 +2244,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
&& !is_error_hpa(hpa))
printk(KERN_ERR "audit: (%s) notrap shadow,"
" valid guest gva %lx\n", audit_msg, va);
- kvm_release_page_clean(page);
+ kvm_release_pfn_clean(pfn);
}
}
@@ -1867,7 +2329,7 @@ static void audit_rmap(struct kvm_vcpu *vcpu)
if (n_rmap != n_actual)
printk(KERN_ERR "%s: (%s) rmap %d actual %d\n",
- __FUNCTION__, audit_msg, n_rmap, n_actual);
+ __func__, audit_msg, n_rmap, n_actual);
}
static void audit_write_protection(struct kvm_vcpu *vcpu)
@@ -1887,7 +2349,7 @@ static void audit_write_protection(struct kvm_vcpu *vcpu)
if (*rmapp)
printk(KERN_ERR "%s: (%s) shadow page has writable"
" mappings: gfn %lx role %x\n",
- __FUNCTION__, audit_msg, sp->gfn,
+ __func__, audit_msg, sp->gfn,
sp->role.word);
}
}
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 1fce19ec7a23..e64e9f56a65e 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -3,6 +3,12 @@
#include <linux/kvm_host.h>
+#ifdef CONFIG_X86_64
+#define TDP_ROOT_LEVEL PT64_ROOT_LEVEL
+#else
+#define TDP_ROOT_LEVEL PT32E_ROOT_LEVEL
+#endif
+
static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index ecc0856268c4..156fe10288ae 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -130,7 +130,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
unsigned index, pt_access, pte_access;
gpa_t pte_gpa;
- pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
+ pgprintk("%s: addr %lx\n", __func__, addr);
walk:
walker->level = vcpu->arch.mmu.root_level;
pte = vcpu->arch.cr3;
@@ -155,7 +155,7 @@ walk:
pte_gpa += index * sizeof(pt_element_t);
walker->table_gfn[walker->level - 1] = table_gfn;
walker->pte_gpa[walker->level - 1] = pte_gpa;
- pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
+ pgprintk("%s: table_gfn[%d] %lx\n", __func__,
walker->level - 1, table_gfn);
kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte));
@@ -222,7 +222,7 @@ walk:
walker->pt_access = pt_access;
walker->pte_access = pte_access;
pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
- __FUNCTION__, (u64)pte, pt_access, pte_access);
+ __func__, (u64)pte, pt_access, pte_access);
return 1;
not_present:
@@ -243,31 +243,30 @@ err:
}
static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
- u64 *spte, const void *pte, int bytes,
- int offset_in_pte)
+ u64 *spte, const void *pte)
{
pt_element_t gpte;
unsigned pte_access;
- struct page *npage;
+ pfn_t pfn;
+ int largepage = vcpu->arch.update_pte.largepage;
gpte = *(const pt_element_t *)pte;
if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
- if (!offset_in_pte && !is_present_pte(gpte))
+ if (!is_present_pte(gpte))
set_shadow_pte(spte, shadow_notrap_nonpresent_pte);
return;
}
- if (bytes < sizeof(pt_element_t))
- return;
- pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
+ pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte);
if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn)
return;
- npage = vcpu->arch.update_pte.page;
- if (!npage)
+ pfn = vcpu->arch.update_pte.pfn;
+ if (is_error_pfn(pfn))
return;
- get_page(npage);
+ kvm_get_pfn(pfn);
mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
- gpte & PT_DIRTY_MASK, NULL, gpte_to_gfn(gpte), npage);
+ gpte & PT_DIRTY_MASK, NULL, largepage, gpte_to_gfn(gpte),
+ pfn, true);
}
/*
@@ -275,8 +274,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
*/
static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
struct guest_walker *walker,
- int user_fault, int write_fault, int *ptwrite,
- struct page *page)
+ int user_fault, int write_fault, int largepage,
+ int *ptwrite, pfn_t pfn)
{
hpa_t shadow_addr;
int level;
@@ -304,11 +303,19 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
shadow_ent = ((u64 *)__va(shadow_addr)) + index;
if (level == PT_PAGE_TABLE_LEVEL)
break;
- if (is_shadow_present_pte(*shadow_ent)) {
+
+ if (largepage && level == PT_DIRECTORY_LEVEL)
+ break;
+
+ if (is_shadow_present_pte(*shadow_ent)
+ && !is_large_pte(*shadow_ent)) {
shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK;
continue;
}
+ if (is_large_pte(*shadow_ent))
+ rmap_remove(vcpu->kvm, shadow_ent);
+
if (level - 1 == PT_PAGE_TABLE_LEVEL
&& walker->level == PT_DIRECTORY_LEVEL) {
metaphysical = 1;
@@ -329,7 +336,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
walker->pte_gpa[level - 2],
&curr_pte, sizeof(curr_pte));
if (r || curr_pte != walker->ptes[level - 2]) {
- kvm_release_page_clean(page);
+ kvm_release_pfn_clean(pfn);
return NULL;
}
}
@@ -342,7 +349,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
mmu_set_spte(vcpu, shadow_ent, access, walker->pte_access & access,
user_fault, write_fault,
walker->ptes[walker->level-1] & PT_DIRTY_MASK,
- ptwrite, walker->gfn, page);
+ ptwrite, largepage, walker->gfn, pfn, false);
return shadow_ent;
}
@@ -371,16 +378,16 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
u64 *shadow_pte;
int write_pt = 0;
int r;
- struct page *page;
+ pfn_t pfn;
+ int largepage = 0;
- pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code);
+ pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
kvm_mmu_audit(vcpu, "pre page fault");
r = mmu_topup_memory_caches(vcpu);
if (r)
return r;
- down_read(&vcpu->kvm->slots_lock);
/*
* Look up the shadow pte for the faulting address.
*/
@@ -391,40 +398,45 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
* The page is not mapped by the guest. Let the guest handle it.
*/
if (!r) {
- pgprintk("%s: guest page fault\n", __FUNCTION__);
+ pgprintk("%s: guest page fault\n", __func__);
inject_page_fault(vcpu, addr, walker.error_code);
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
- up_read(&vcpu->kvm->slots_lock);
return 0;
}
down_read(&current->mm->mmap_sem);
- page = gfn_to_page(vcpu->kvm, walker.gfn);
+ if (walker.level == PT_DIRECTORY_LEVEL) {
+ gfn_t large_gfn;
+ large_gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE-1);
+ if (is_largepage_backed(vcpu, large_gfn)) {
+ walker.gfn = large_gfn;
+ largepage = 1;
+ }
+ }
+ pfn = gfn_to_pfn(vcpu->kvm, walker.gfn);
up_read(&current->mm->mmap_sem);
+ /* mmio */
+ if (is_error_pfn(pfn)) {
+ pgprintk("gfn %x is mmio\n", walker.gfn);
+ kvm_release_pfn_clean(pfn);
+ return 1;
+ }
+
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
- &write_pt, page);
- pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
+ largepage, &write_pt, pfn);
+
+ pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__,
shadow_pte, *shadow_pte, write_pt);
if (!write_pt)
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
- /*
- * mmio: emulate if accessible, otherwise its a guest fault.
- */
- if (shadow_pte && is_io_pte(*shadow_pte)) {
- spin_unlock(&vcpu->kvm->mmu_lock);
- up_read(&vcpu->kvm->slots_lock);
- return 1;
- }
-
++vcpu->stat.pf_fixed;
kvm_mmu_audit(vcpu, "post page fault (fixed)");
spin_unlock(&vcpu->kvm->mmu_lock);
- up_read(&vcpu->kvm->slots_lock);
return write_pt;
}
diff --git a/arch/x86/kvm/segment_descriptor.h b/arch/x86/kvm/segment_descriptor.h
deleted file mode 100644
index 56fc4c873389..000000000000
--- a/arch/x86/kvm/segment_descriptor.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __SEGMENT_DESCRIPTOR_H
-#define __SEGMENT_DESCRIPTOR_H
-
-struct segment_descriptor {
- u16 limit_low;
- u16 base_low;
- u8 base_mid;
- u8 type : 4;
- u8 system : 1;
- u8 dpl : 2;
- u8 present : 1;
- u8 limit_high : 4;
- u8 avl : 1;
- u8 long_mode : 1;
- u8 default_op : 1;
- u8 granularity : 1;
- u8 base_high;
-} __attribute__((packed));
-
-#ifdef CONFIG_X86_64
-/* LDT or TSS descriptor in the GDT. 16 bytes. */
-struct segment_descriptor_64 {
- struct segment_descriptor s;
- u32 base_higher;
- u32 pad_zero;
-};
-
-#endif
-#endif
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1a582f1090e8..89e0be2c10d0 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -47,6 +47,18 @@ MODULE_LICENSE("GPL");
#define SVM_FEATURE_LBRV (1 << 1)
#define SVM_DEATURE_SVML (1 << 2)
+#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
+
+/* enable NPT for AMD64 and X86 with PAE */
+#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
+static bool npt_enabled = true;
+#else
+static bool npt_enabled = false;
+#endif
+static int npt = 1;
+
+module_param(npt, int, S_IRUGO);
+
static void kvm_reput_irq(struct vcpu_svm *svm);
static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
@@ -54,8 +66,7 @@ static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
return container_of(vcpu, struct vcpu_svm, vcpu);
}
-unsigned long iopm_base;
-unsigned long msrpm_base;
+static unsigned long iopm_base;
struct kvm_ldttss_desc {
u16 limit0;
@@ -182,7 +193,7 @@ static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
- if (!(efer & EFER_LMA))
+ if (!npt_enabled && !(efer & EFER_LMA))
efer &= ~EFER_LME;
to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
@@ -219,12 +230,12 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
if (!svm->next_rip) {
- printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
+ printk(KERN_DEBUG "%s: NOP\n", __func__);
return;
}
if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE)
printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
- __FUNCTION__,
+ __func__,
svm->vmcb->save.rip,
svm->next_rip);
@@ -279,11 +290,7 @@ static void svm_hardware_enable(void *garbage)
struct svm_cpu_data *svm_data;
uint64_t efer;
-#ifdef CONFIG_X86_64
- struct desc_ptr gdt_descr;
-#else
struct desc_ptr gdt_descr;
-#endif
struct desc_struct *gdt;
int me = raw_smp_processor_id();
@@ -302,7 +309,6 @@ static void svm_hardware_enable(void *garbage)
svm_data->asid_generation = 1;
svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
svm_data->next_asid = svm_data->max_asid + 1;
- svm_features = cpuid_edx(SVM_CPUID_FUNC);
asm volatile ("sgdt %0" : "=m"(gdt_descr));
gdt = (struct desc_struct *)gdt_descr.address;
@@ -361,12 +367,51 @@ static void set_msr_interception(u32 *msrpm, unsigned msr,
BUG();
}
+static void svm_vcpu_init_msrpm(u32 *msrpm)
+{
+ memset(msrpm, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
+
+#ifdef CONFIG_X86_64
+ set_msr_interception(msrpm, MSR_GS_BASE, 1, 1);
+ set_msr_interception(msrpm, MSR_FS_BASE, 1, 1);
+ set_msr_interception(msrpm, MSR_KERNEL_GS_BASE, 1, 1);
+ set_msr_interception(msrpm, MSR_LSTAR, 1, 1);
+ set_msr_interception(msrpm, MSR_CSTAR, 1, 1);
+ set_msr_interception(msrpm, MSR_SYSCALL_MASK, 1, 1);
+#endif
+ set_msr_interception(msrpm, MSR_K6_STAR, 1, 1);
+ set_msr_interception(msrpm, MSR_IA32_SYSENTER_CS, 1, 1);
+ set_msr_interception(msrpm, MSR_IA32_SYSENTER_ESP, 1, 1);
+ set_msr_interception(msrpm, MSR_IA32_SYSENTER_EIP, 1, 1);
+}
+
+static void svm_enable_lbrv(struct vcpu_svm *svm)
+{
+ u32 *msrpm = svm->msrpm;
+
+ svm->vmcb->control.lbr_ctl = 1;
+ set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1);
+ set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1);
+ set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 1, 1);
+ set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 1, 1);
+}
+
+static void svm_disable_lbrv(struct vcpu_svm *svm)
+{
+ u32 *msrpm = svm->msrpm;
+
+ svm->vmcb->control.lbr_ctl = 0;
+ set_msr_interception(msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0);
+ set_msr_interception(msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0);
+ set_msr_interception(msrpm, MSR_IA32_LASTINTFROMIP, 0, 0);
+ set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 0, 0);
+}
+
static __init int svm_hardware_setup(void)
{
int cpu;
struct page *iopm_pages;
- struct page *msrpm_pages;
- void *iopm_va, *msrpm_va;
+ void *iopm_va;
int r;
iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
@@ -379,41 +424,33 @@ static __init int svm_hardware_setup(void)
clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */
iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
+ if (boot_cpu_has(X86_FEATURE_NX))
+ kvm_enable_efer_bits(EFER_NX);
- msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
+ for_each_online_cpu(cpu) {
+ r = svm_cpu_init(cpu);
+ if (r)
+ goto err;
+ }
- r = -ENOMEM;
- if (!msrpm_pages)
- goto err_1;
+ svm_features = cpuid_edx(SVM_CPUID_FUNC);
- msrpm_va = page_address(msrpm_pages);
- memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
- msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT;
+ if (!svm_has(SVM_FEATURE_NPT))
+ npt_enabled = false;
-#ifdef CONFIG_X86_64
- set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1);
- set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1);
- set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1);
- set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1);
- set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1);
- set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1);
-#endif
- set_msr_interception(msrpm_va, MSR_K6_STAR, 1, 1);
- set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1);
- set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1);
- set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1);
+ if (npt_enabled && !npt) {
+ printk(KERN_INFO "kvm: Nested Paging disabled\n");
+ npt_enabled = false;
+ }
- for_each_online_cpu(cpu) {
- r = svm_cpu_init(cpu);
- if (r)
- goto err_2;
+ if (npt_enabled) {
+ printk(KERN_INFO "kvm: Nested Paging enabled\n");
+ kvm_enable_tdp();
}
+
return 0;
-err_2:
- __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER);
- msrpm_base = 0;
-err_1:
+err:
__free_pages(iopm_pages, IOPM_ALLOC_ORDER);
iopm_base = 0;
return r;
@@ -421,9 +458,8 @@ err_1:
static __exit void svm_hardware_unsetup(void)
{
- __free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER);
__free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
- iopm_base = msrpm_base = 0;
+ iopm_base = 0;
}
static void init_seg(struct vmcb_seg *seg)
@@ -443,15 +479,14 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
-static void init_vmcb(struct vmcb *vmcb)
+static void init_vmcb(struct vcpu_svm *svm)
{
- struct vmcb_control_area *control = &vmcb->control;
- struct vmcb_save_area *save = &vmcb->save;
+ struct vmcb_control_area *control = &svm->vmcb->control;
+ struct vmcb_save_area *save = &svm->vmcb->save;
control->intercept_cr_read = INTERCEPT_CR0_MASK |
INTERCEPT_CR3_MASK |
- INTERCEPT_CR4_MASK |
- INTERCEPT_CR8_MASK;
+ INTERCEPT_CR4_MASK;
control->intercept_cr_write = INTERCEPT_CR0_MASK |
INTERCEPT_CR3_MASK |
@@ -471,23 +506,13 @@ static void init_vmcb(struct vmcb *vmcb)
INTERCEPT_DR7_MASK;
control->intercept_exceptions = (1 << PF_VECTOR) |
- (1 << UD_VECTOR);
+ (1 << UD_VECTOR) |
+ (1 << MC_VECTOR);
control->intercept = (1ULL << INTERCEPT_INTR) |
(1ULL << INTERCEPT_NMI) |
(1ULL << INTERCEPT_SMI) |
- /*
- * selective cr0 intercept bug?
- * 0: 0f 22 d8 mov %eax,%cr3
- * 3: 0f 20 c0 mov %cr0,%eax
- * 6: 0d 00 00 00 80 or $0x80000000,%eax
- * b: 0f 22 c0 mov %eax,%cr0
- * set cr3 ->interception
- * get cr0 ->interception
- * set cr0 -> no interception
- */
- /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */
(1ULL << INTERCEPT_CPUID) |
(1ULL << INTERCEPT_INVD) |
(1ULL << INTERCEPT_HLT) |
@@ -508,7 +533,7 @@ static void init_vmcb(struct vmcb *vmcb)
(1ULL << INTERCEPT_MWAIT);
control->iopm_base_pa = iopm_base;
- control->msrpm_base_pa = msrpm_base;
+ control->msrpm_base_pa = __pa(svm->msrpm);
control->tsc_offset = 0;
control->int_ctl = V_INTR_MASKING_MASK;
@@ -550,13 +575,30 @@ static void init_vmcb(struct vmcb *vmcb)
save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
save->cr4 = X86_CR4_PAE;
/* rdx = ?? */
+
+ if (npt_enabled) {
+ /* Setup VMCB for Nested Paging */
+ control->nested_ctl = 1;
+ control->intercept &= ~(1ULL << INTERCEPT_TASK_SWITCH);
+ control->intercept_exceptions &= ~(1 << PF_VECTOR);
+ control->intercept_cr_read &= ~(INTERCEPT_CR0_MASK|
+ INTERCEPT_CR3_MASK);
+ control->intercept_cr_write &= ~(INTERCEPT_CR0_MASK|
+ INTERCEPT_CR3_MASK);
+ save->g_pat = 0x0007040600070406ULL;
+ /* enable caching because the QEMU Bios doesn't enable it */
+ save->cr0 = X86_CR0_ET;
+ save->cr3 = 0;
+ save->cr4 = 0;
+ }
+ force_new_asid(&svm->vcpu);
}
static int svm_vcpu_reset(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
- init_vmcb(svm->vmcb);
+ init_vmcb(svm);
if (vcpu->vcpu_id != 0) {
svm->vmcb->save.rip = 0;
@@ -571,6 +613,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
{
struct vcpu_svm *svm;
struct page *page;
+ struct page *msrpm_pages;
int err;
svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
@@ -589,12 +632,19 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
goto uninit;
}
+ err = -ENOMEM;
+ msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
+ if (!msrpm_pages)
+ goto uninit;
+ svm->msrpm = page_address(msrpm_pages);
+ svm_vcpu_init_msrpm(svm->msrpm);
+
svm->vmcb = page_address(page);
clear_page(svm->vmcb);
svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
svm->asid_generation = 0;
memset(svm->db_regs, 0, sizeof(svm->db_regs));
- init_vmcb(svm->vmcb);
+ init_vmcb(svm);
fx_init(&svm->vcpu);
svm->vcpu.fpu_active = 1;
@@ -617,6 +667,7 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
__free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
+ __free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER);
kvm_vcpu_uninit(vcpu);
kmem_cache_free(kvm_vcpu_cache, svm);
}
@@ -731,6 +782,13 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
var->unusable = !var->present;
}
+static int svm_get_cpl(struct kvm_vcpu *vcpu)
+{
+ struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save;
+
+ return save->cpl;
+}
+
static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -784,6 +842,9 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
}
#endif
+ if (npt_enabled)
+ goto set;
+
if ((vcpu->arch.cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) {
svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
vcpu->fpu_active = 1;
@@ -791,18 +852,29 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
vcpu->arch.cr0 = cr0;
cr0 |= X86_CR0_PG | X86_CR0_WP;
- cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
if (!vcpu->fpu_active) {
svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
cr0 |= X86_CR0_TS;
}
+set:
+ /*
+ * re-enable caching here because the QEMU bios
+ * does not do it - this results in some delay at
+ * reboot
+ */
+ cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
svm->vmcb->save.cr0 = cr0;
}
static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
- vcpu->arch.cr4 = cr4;
- to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE;
+ unsigned long host_cr4_mce = read_cr4() & X86_CR4_MCE;
+
+ vcpu->arch.cr4 = cr4;
+ if (!npt_enabled)
+ cr4 |= X86_CR4_PAE;
+ cr4 |= host_cr4_mce;
+ to_svm(vcpu)->vmcb->save.cr4 = cr4;
}
static void svm_set_segment(struct kvm_vcpu *vcpu,
@@ -833,13 +905,6 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
}
-/* FIXME:
-
- svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK;
- svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
-
-*/
-
static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
{
return -EOPNOTSUPP;
@@ -920,7 +985,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
}
default:
printk(KERN_DEBUG "%s: unexpected dr %u\n",
- __FUNCTION__, dr);
+ __func__, dr);
*exception = UD_VECTOR;
return;
}
@@ -962,6 +1027,19 @@ static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
+static int mc_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+{
+ /*
+ * On an #MC intercept the MCE handler is not called automatically in
+ * the host. So do it by hand here.
+ */
+ asm volatile (
+ "int $0x12\n");
+ /* not sure if we ever come back to this point */
+
+ return 1;
+}
+
static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
/*
@@ -969,7 +1047,7 @@ static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
* so reinitialize it.
*/
clear_page(svm->vmcb);
- init_vmcb(svm->vmcb);
+ init_vmcb(svm);
kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
return 0;
@@ -1033,9 +1111,18 @@ static int invalid_op_interception(struct vcpu_svm *svm,
static int task_switch_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
- pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__);
- kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
- return 0;
+ u16 tss_selector;
+
+ tss_selector = (u16)svm->vmcb->control.exit_info_1;
+ if (svm->vmcb->control.exit_info_2 &
+ (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
+ return kvm_task_switch(&svm->vcpu, tss_selector,
+ TASK_SWITCH_IRET);
+ if (svm->vmcb->control.exit_info_2 &
+ (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
+ return kvm_task_switch(&svm->vcpu, tss_selector,
+ TASK_SWITCH_JMP);
+ return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL);
}
static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
@@ -1049,7 +1136,7 @@ static int emulate_on_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE)
- pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__);
+ pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
return 1;
}
@@ -1179,8 +1266,19 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
svm->vmcb->save.sysenter_esp = data;
break;
case MSR_IA32_DEBUGCTLMSR:
- pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
- __FUNCTION__, data);
+ if (!svm_has(SVM_FEATURE_LBRV)) {
+ pr_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
+ __func__, data);
+ break;
+ }
+ if (data & DEBUGCTL_RESERVED_BITS)
+ return 1;
+
+ svm->vmcb->save.dbgctl = data;
+ if (data & (1ULL<<0))
+ svm_enable_lbrv(svm);
+ else
+ svm_disable_lbrv(svm);
break;
case MSR_K7_EVNTSEL0:
case MSR_K7_EVNTSEL1:
@@ -1265,6 +1363,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
[SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception,
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
[SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception,
+ [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception,
[SVM_EXIT_INTR] = nop_on_interception,
[SVM_EXIT_NMI] = nop_on_interception,
[SVM_EXIT_SMI] = nop_on_interception,
@@ -1290,14 +1389,34 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
[SVM_EXIT_WBINVD] = emulate_on_interception,
[SVM_EXIT_MONITOR] = invalid_op_interception,
[SVM_EXIT_MWAIT] = invalid_op_interception,
+ [SVM_EXIT_NPF] = pf_interception,
};
-
static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
u32 exit_code = svm->vmcb->control.exit_code;
+ if (npt_enabled) {
+ int mmu_reload = 0;
+ if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) {
+ svm_set_cr0(vcpu, svm->vmcb->save.cr0);
+ mmu_reload = 1;
+ }
+ vcpu->arch.cr0 = svm->vmcb->save.cr0;
+ vcpu->arch.cr3 = svm->vmcb->save.cr3;
+ if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
+ if (!load_pdptrs(vcpu, vcpu->arch.cr3)) {
+ kvm_inject_gp(vcpu, 0);
+ return 1;
+ }
+ }
+ if (mmu_reload) {
+ kvm_mmu_reset_context(vcpu);
+ kvm_mmu_load(vcpu);
+ }
+ }
+
kvm_reput_irq(svm);
if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
@@ -1308,10 +1427,11 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
}
if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
- exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
+ exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
+ exit_code != SVM_EXIT_NPF)
printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
"exit_code 0x%x\n",
- __FUNCTION__, svm->vmcb->control.exit_int_info,
+ __func__, svm->vmcb->control.exit_int_info,
exit_code);
if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
@@ -1364,6 +1484,27 @@ static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
svm_inject_irq(svm, irq);
}
+static void update_cr8_intercept(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb *vmcb = svm->vmcb;
+ int max_irr, tpr;
+
+ if (!irqchip_in_kernel(vcpu->kvm) || vcpu->arch.apic->vapic_addr)
+ return;
+
+ vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
+
+ max_irr = kvm_lapic_find_highest_irr(vcpu);
+ if (max_irr == -1)
+ return;
+
+ tpr = kvm_lapic_get_cr8(vcpu) << 4;
+
+ if (tpr >= (max_irr & 0xf0))
+ vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK;
+}
+
static void svm_intr_assist(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1376,14 +1517,14 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
SVM_EVTINJ_VEC_MASK;
vmcb->control.exit_int_info = 0;
svm_inject_irq(svm, intr_vector);
- return;
+ goto out;
}
if (vmcb->control.int_ctl & V_IRQ_MASK)
- return;
+ goto out;
if (!kvm_cpu_has_interrupt(vcpu))
- return;
+ goto out;
if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
@@ -1391,12 +1532,14 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
/* unable to deliver irq, set pending irq */
vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
svm_inject_irq(svm, 0x0);
- return;
+ goto out;
}
/* Okay, we can deliver the interrupt: grab it and update PIC state. */
intr_vector = kvm_cpu_get_interrupt(vcpu);
svm_inject_irq(svm, intr_vector);
kvm_timer_intr_post(vcpu, intr_vector);
+out:
+ update_cr8_intercept(vcpu);
}
static void kvm_reput_irq(struct vcpu_svm *svm)
@@ -1482,6 +1625,29 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
{
}
+static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) {
+ int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
+ kvm_lapic_set_tpr(vcpu, cr8);
+ }
+}
+
+static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 cr8;
+
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return;
+
+ cr8 = kvm_get_cr8(vcpu);
+ svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
+ svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
+}
+
static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1491,6 +1657,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
pre_svm_run(svm);
+ sync_lapic_to_cr8(vcpu);
+
save_host_msrs(vcpu);
fs_selector = read_fs();
gs_selector = read_gs();
@@ -1499,6 +1667,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
svm->host_dr6 = read_dr6();
svm->host_dr7 = read_dr7();
svm->vmcb->save.cr2 = vcpu->arch.cr2;
+ /* required for live migration with NPT */
+ if (npt_enabled)
+ svm->vmcb->save.cr3 = vcpu->arch.cr3;
if (svm->vmcb->save.dr7 & 0xff) {
write_dr7(0);
@@ -1635,6 +1806,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
stgi();
+ sync_cr8_to_lapic(vcpu);
+
svm->next_rip = 0;
}
@@ -1642,6 +1815,12 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ if (npt_enabled) {
+ svm->vmcb->control.nested_cr3 = root;
+ force_new_asid(vcpu);
+ return;
+ }
+
svm->vmcb->save.cr3 = root;
force_new_asid(vcpu);
@@ -1709,6 +1888,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.get_segment_base = svm_get_segment_base,
.get_segment = svm_get_segment,
.set_segment = svm_set_segment,
+ .get_cpl = svm_get_cpl,
.get_cs_db_l_bits = kvm_get_cs_db_l_bits,
.decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
.set_cr0 = svm_set_cr0,
diff --git a/arch/x86/kvm/svm.h b/arch/x86/kvm/svm.h
index 5fd50491b555..1b8afa78e869 100644
--- a/arch/x86/kvm/svm.h
+++ b/arch/x86/kvm/svm.h
@@ -238,6 +238,9 @@ struct __attribute__ ((__packed__)) vmcb {
#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
+#define SVM_EXITINFOSHIFT_TS_REASON_IRET 36
+#define SVM_EXITINFOSHIFT_TS_REASON_JMP 38
+
#define SVM_EXIT_READ_CR0 0x000
#define SVM_EXIT_READ_CR3 0x003
#define SVM_EXIT_READ_CR4 0x004
diff --git a/arch/x86/kvm/tss.h b/arch/x86/kvm/tss.h
new file mode 100644
index 000000000000..622aa10f692f
--- /dev/null
+++ b/arch/x86/kvm/tss.h
@@ -0,0 +1,59 @@
+#ifndef __TSS_SEGMENT_H
+#define __TSS_SEGMENT_H
+
+struct tss_segment_32 {
+ u32 prev_task_link;
+ u32 esp0;
+ u32 ss0;
+ u32 esp1;
+ u32 ss1;
+ u32 esp2;
+ u32 ss2;
+ u32 cr3;
+ u32 eip;
+ u32 eflags;
+ u32 eax;
+ u32 ecx;
+ u32 edx;
+ u32 ebx;
+ u32 esp;
+ u32 ebp;
+ u32 esi;
+ u32 edi;
+ u32 es;
+ u32 cs;
+ u32 ss;
+ u32 ds;
+ u32 fs;
+ u32 gs;
+ u32 ldt_selector;
+ u16 t;
+ u16 io_map;
+};
+
+struct tss_segment_16 {
+ u16 prev_task_link;
+ u16 sp0;
+ u16 ss0;
+ u16 sp1;
+ u16 ss1;
+ u16 sp2;
+ u16 ss2;
+ u16 ip;
+ u16 flag;
+ u16 ax;
+ u16 cx;
+ u16 dx;
+ u16 bx;
+ u16 sp;
+ u16 bp;
+ u16 si;
+ u16 di;
+ u16 es;
+ u16 cs;
+ u16 ss;
+ u16 ds;
+ u16 ldt;
+};
+
+#endif
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 8e1462880d1f..8e5d6645b90d 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -17,7 +17,6 @@
#include "irq.h"
#include "vmx.h"
-#include "segment_descriptor.h"
#include "mmu.h"
#include <linux/kvm_host.h>
@@ -37,6 +36,12 @@ MODULE_LICENSE("GPL");
static int bypass_guest_pf = 1;
module_param(bypass_guest_pf, bool, 0);
+static int enable_vpid = 1;
+module_param(enable_vpid, bool, 0);
+
+static int flexpriority_enabled = 1;
+module_param(flexpriority_enabled, bool, 0);
+
struct vmcs {
u32 revision_id;
u32 abort;
@@ -71,6 +76,7 @@ struct vcpu_vmx {
unsigned rip;
} irq;
} rmode;
+ int vpid;
};
static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
@@ -85,6 +91,10 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
static struct page *vmx_io_bitmap_a;
static struct page *vmx_io_bitmap_b;
+static struct page *vmx_msr_bitmap;
+
+static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
+static DEFINE_SPINLOCK(vmx_vpid_lock);
static struct vmcs_config {
int size;
@@ -176,6 +186,11 @@ static inline int is_external_interrupt(u32 intr_info)
== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
}
+static inline int cpu_has_vmx_msr_bitmap(void)
+{
+ return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS);
+}
+
static inline int cpu_has_vmx_tpr_shadow(void)
{
return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
@@ -194,8 +209,9 @@ static inline int cpu_has_secondary_exec_ctrls(void)
static inline bool cpu_has_vmx_virtualize_apic_accesses(void)
{
- return (vmcs_config.cpu_based_2nd_exec_ctrl &
- SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
+ return flexpriority_enabled
+ && (vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
}
static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
@@ -204,6 +220,12 @@ static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
(irqchip_in_kernel(kvm)));
}
+static inline int cpu_has_vmx_vpid(void)
+{
+ return (vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_ENABLE_VPID);
+}
+
static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
{
int i;
@@ -214,6 +236,20 @@ static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
return -1;
}
+static inline void __invvpid(int ext, u16 vpid, gva_t gva)
+{
+ struct {
+ u64 vpid : 16;
+ u64 rsvd : 48;
+ u64 gva;
+ } operand = { vpid, 0, gva };
+
+ asm volatile (ASM_VMX_INVVPID
+ /* CF==1 or ZF==1 --> rc = -1 */
+ "; ja 1f ; ud2 ; 1:"
+ : : "a"(&operand), "c"(ext) : "cc", "memory");
+}
+
static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
{
int i;
@@ -257,6 +293,14 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
vmx->launched = 0;
}
+static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx)
+{
+ if (vmx->vpid == 0)
+ return;
+
+ __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0);
+}
+
static unsigned long vmcs_readl(unsigned long field)
{
unsigned long value;
@@ -353,7 +397,7 @@ static void reload_tss(void)
* VT restores TR but not its size. Useless.
*/
struct descriptor_table gdt;
- struct segment_descriptor *descs;
+ struct desc_struct *descs;
get_gdt(&gdt);
descs = (void *)gdt.base;
@@ -485,11 +529,12 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
u64 phys_addr = __pa(vmx->vmcs);
- u64 tsc_this, delta;
+ u64 tsc_this, delta, new_offset;
if (vcpu->cpu != cpu) {
vcpu_clear(vmx);
kvm_migrate_apic_timer(vcpu);
+ vpid_sync_vcpu_all(vmx);
}
if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
@@ -524,8 +569,11 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
* Make sure the time stamp counter is monotonous.
*/
rdtscll(tsc_this);
- delta = vcpu->arch.host_tsc - tsc_this;
- vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
+ if (tsc_this < vcpu->arch.host_tsc) {
+ delta = vcpu->arch.host_tsc - tsc_this;
+ new_offset = vmcs_read64(TSC_OFFSET) + delta;
+ vmcs_write64(TSC_OFFSET, new_offset);
+ }
}
}
@@ -596,7 +644,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
{
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
nr | INTR_TYPE_EXCEPTION
- | (has_error_code ? INTR_INFO_DELIEVER_CODE_MASK : 0)
+ | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0)
| INTR_INFO_VALID_MASK);
if (has_error_code)
vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
@@ -959,6 +1007,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
CPU_BASED_MOV_DR_EXITING |
CPU_BASED_USE_TSC_OFFSETING;
opt = CPU_BASED_TPR_SHADOW |
+ CPU_BASED_USE_MSR_BITMAPS |
CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
&_cpu_based_exec_control) < 0)
@@ -971,7 +1020,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) {
min = 0;
opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
- SECONDARY_EXEC_WBINVD_EXITING;
+ SECONDARY_EXEC_WBINVD_EXITING |
+ SECONDARY_EXEC_ENABLE_VPID;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2,
&_cpu_based_2nd_exec_control) < 0)
return -EIO;
@@ -1080,6 +1130,10 @@ static __init int hardware_setup(void)
{
if (setup_vmcs_config(&vmcs_config) < 0)
return -EIO;
+
+ if (boot_cpu_has(X86_FEATURE_NX))
+ kvm_enable_efer_bits(EFER_NX);
+
return alloc_kvm_area();
}
@@ -1214,7 +1268,7 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES);
if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
printk(KERN_DEBUG "%s: tss fixup for long mode. \n",
- __FUNCTION__);
+ __func__);
vmcs_write32(GUEST_TR_AR_BYTES,
(guest_tr_ar & ~AR_TYPE_MASK)
| AR_TYPE_BUSY_64_TSS);
@@ -1239,6 +1293,11 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
#endif
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ vpid_sync_vcpu_all(to_vmx(vcpu));
+}
+
static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
{
vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK;
@@ -1275,6 +1334,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
+ vmx_flush_tlb(vcpu);
vmcs_writel(GUEST_CR3, cr3);
if (vcpu->arch.cr0 & X86_CR0_PE)
vmx_fpu_deactivate(vcpu);
@@ -1288,14 +1348,14 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
vcpu->arch.cr4 = cr4;
}
-#ifdef CONFIG_X86_64
-
static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
vcpu->arch.shadow_efer = efer;
+ if (!msr)
+ return;
if (efer & EFER_LMA) {
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS) |
@@ -1312,8 +1372,6 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
setup_msrs(vmx);
}
-#endif
-
static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -1344,6 +1402,20 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
var->unusable = (ar >> 16) & 1;
}
+static int vmx_get_cpl(struct kvm_vcpu *vcpu)
+{
+ struct kvm_segment kvm_seg;
+
+ if (!(vcpu->arch.cr0 & X86_CR0_PE)) /* if real mode */
+ return 0;
+
+ if (vmx_get_rflags(vcpu) & X86_EFLAGS_VM) /* if virtual 8086 */
+ return 3;
+
+ vmx_get_segment(vcpu, &kvm_seg, VCPU_SREG_CS);
+ return kvm_seg.selector & 3;
+}
+
static u32 vmx_segment_access_rights(struct kvm_segment *var)
{
u32 ar;
@@ -1433,7 +1505,6 @@ static int init_rmode_tss(struct kvm *kvm)
int ret = 0;
int r;
- down_read(&kvm->slots_lock);
r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE);
if (r < 0)
goto out;
@@ -1456,7 +1527,6 @@ static int init_rmode_tss(struct kvm *kvm)
ret = 1;
out:
- up_read(&kvm->slots_lock);
return ret;
}
@@ -1494,6 +1564,46 @@ out:
return r;
}
+static void allocate_vpid(struct vcpu_vmx *vmx)
+{
+ int vpid;
+
+ vmx->vpid = 0;
+ if (!enable_vpid || !cpu_has_vmx_vpid())
+ return;
+ spin_lock(&vmx_vpid_lock);
+ vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS);
+ if (vpid < VMX_NR_VPIDS) {
+ vmx->vpid = vpid;
+ __set_bit(vpid, vmx_vpid_bitmap);
+ }
+ spin_unlock(&vmx_vpid_lock);
+}
+
+void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
+{
+ void *va;
+
+ if (!cpu_has_vmx_msr_bitmap())
+ return;
+
+ /*
+ * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals
+ * have the write-low and read-high bitmap offsets the wrong way round.
+ * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff.
+ */
+ va = kmap(msr_bitmap);
+ if (msr <= 0x1fff) {
+ __clear_bit(msr, va + 0x000); /* read-low */
+ __clear_bit(msr, va + 0x800); /* write-low */
+ } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+ msr &= 0x1fff;
+ __clear_bit(msr, va + 0x400); /* read-high */
+ __clear_bit(msr, va + 0xc00); /* write-high */
+ }
+ kunmap(msr_bitmap);
+}
+
/*
* Sets up the vmcs for emulated real mode.
*/
@@ -1511,6 +1621,9 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
+ if (cpu_has_vmx_msr_bitmap())
+ vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap));
+
vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
/* Control */
@@ -1532,6 +1645,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
if (!vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
exec_control &=
~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+ if (vmx->vpid == 0)
+ exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
}
@@ -1613,6 +1728,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
u64 msr;
int ret;
+ down_read(&vcpu->kvm->slots_lock);
if (!init_rmode_tss(vmx->vcpu.kvm)) {
ret = -ENOMEM;
goto out;
@@ -1621,7 +1737,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmx->vcpu.arch.rmode.active = 0;
vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val();
- set_cr8(&vmx->vcpu, 0);
+ kvm_set_cr8(&vmx->vcpu, 0);
msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
if (vmx->vcpu.vcpu_id == 0)
msr |= MSR_IA32_APICBASE_BSP;
@@ -1704,18 +1820,22 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmcs_write64(APIC_ACCESS_ADDR,
page_to_phys(vmx->vcpu.kvm->arch.apic_access_page));
+ if (vmx->vpid != 0)
+ vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
+
vmx->vcpu.arch.cr0 = 0x60000010;
vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */
vmx_set_cr4(&vmx->vcpu, 0);
-#ifdef CONFIG_X86_64
vmx_set_efer(&vmx->vcpu, 0);
-#endif
vmx_fpu_activate(&vmx->vcpu);
update_exception_bitmap(&vmx->vcpu);
- return 0;
+ vpid_sync_vcpu_all(vmx);
+
+ ret = 0;
out:
+ up_read(&vcpu->kvm->slots_lock);
return ret;
}
@@ -1723,6 +1843,8 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler);
+
if (vcpu->arch.rmode.active) {
vmx->rmode.irq.pending = true;
vmx->rmode.irq.vector = irq;
@@ -1844,7 +1966,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if ((vect_info & VECTORING_INFO_VALID_MASK) &&
!is_page_fault(intr_info))
printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
- "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
+ "intr info 0x%x\n", __func__, vect_info, intr_info);
if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
@@ -1869,10 +1991,12 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
error_code = 0;
rip = vmcs_readl(GUEST_RIP);
- if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
+ if (intr_info & INTR_INFO_DELIVER_CODE_MASK)
error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
if (is_page_fault(intr_info)) {
cr2 = vmcs_readl(EXIT_QUALIFICATION);
+ KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
+ (u32)((u64)cr2 >> 32), handler);
return kvm_mmu_page_fault(vcpu, cr2, error_code);
}
@@ -1901,6 +2025,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
++vcpu->stat.irq_exits;
+ KVMTRACE_1D(INTR, vcpu, vmcs_read32(VM_EXIT_INTR_INFO), handler);
return 1;
}
@@ -1958,25 +2083,27 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
reg = (exit_qualification >> 8) & 15;
switch ((exit_qualification >> 4) & 3) {
case 0: /* mov to cr */
+ KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr, (u32)vcpu->arch.regs[reg],
+ (u32)((u64)vcpu->arch.regs[reg] >> 32), handler);
switch (cr) {
case 0:
vcpu_load_rsp_rip(vcpu);
- set_cr0(vcpu, vcpu->arch.regs[reg]);
+ kvm_set_cr0(vcpu, vcpu->arch.regs[reg]);
skip_emulated_instruction(vcpu);
return 1;
case 3:
vcpu_load_rsp_rip(vcpu);
- set_cr3(vcpu, vcpu->arch.regs[reg]);
+ kvm_set_cr3(vcpu, vcpu->arch.regs[reg]);
skip_emulated_instruction(vcpu);
return 1;
case 4:
vcpu_load_rsp_rip(vcpu);
- set_cr4(vcpu, vcpu->arch.regs[reg]);
+ kvm_set_cr4(vcpu, vcpu->arch.regs[reg]);
skip_emulated_instruction(vcpu);
return 1;
case 8:
vcpu_load_rsp_rip(vcpu);
- set_cr8(vcpu, vcpu->arch.regs[reg]);
+ kvm_set_cr8(vcpu, vcpu->arch.regs[reg]);
skip_emulated_instruction(vcpu);
if (irqchip_in_kernel(vcpu->kvm))
return 1;
@@ -1990,6 +2117,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu->arch.cr0 &= ~X86_CR0_TS;
vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0);
vmx_fpu_activate(vcpu);
+ KVMTRACE_0D(CLTS, vcpu, handler);
skip_emulated_instruction(vcpu);
return 1;
case 1: /*mov from cr*/
@@ -1998,18 +2126,24 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load_rsp_rip(vcpu);
vcpu->arch.regs[reg] = vcpu->arch.cr3;
vcpu_put_rsp_rip(vcpu);
+ KVMTRACE_3D(CR_READ, vcpu, (u32)cr,
+ (u32)vcpu->arch.regs[reg],
+ (u32)((u64)vcpu->arch.regs[reg] >> 32),
+ handler);
skip_emulated_instruction(vcpu);
return 1;
case 8:
vcpu_load_rsp_rip(vcpu);
- vcpu->arch.regs[reg] = get_cr8(vcpu);
+ vcpu->arch.regs[reg] = kvm_get_cr8(vcpu);
vcpu_put_rsp_rip(vcpu);
+ KVMTRACE_2D(CR_READ, vcpu, (u32)cr,
+ (u32)vcpu->arch.regs[reg], handler);
skip_emulated_instruction(vcpu);
return 1;
}
break;
case 3: /* lmsw */
- lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f);
+ kvm_lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f);
skip_emulated_instruction(vcpu);
return 1;
@@ -2049,6 +2183,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
val = 0;
}
vcpu->arch.regs[reg] = val;
+ KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler);
} else {
/* mov to dr */
}
@@ -2073,6 +2208,9 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
+ KVMTRACE_3D(MSR_READ, vcpu, ecx, (u32)data, (u32)(data >> 32),
+ handler);
+
/* FIXME: handling of bits 32:63 of rax, rdx */
vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u;
vcpu->arch.regs[VCPU_REGS_RDX] = (data >> 32) & -1u;
@@ -2086,6 +2224,9 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u)
| ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32);
+ KVMTRACE_3D(MSR_WRITE, vcpu, ecx, (u32)data, (u32)(data >> 32),
+ handler);
+
if (vmx_set_msr(vcpu, ecx, data) != 0) {
kvm_inject_gp(vcpu, 0);
return 1;
@@ -2110,6 +2251,9 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+
+ KVMTRACE_0D(PEND_INTR, vcpu, handler);
+
/*
* If the user space waits to inject interrupts, exit as soon as
* possible
@@ -2152,6 +2296,8 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
offset = exit_qualification & 0xffful;
+ KVMTRACE_1D(APIC_ACCESS, vcpu, (u32)offset, handler);
+
er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
if (er != EMULATE_DONE) {
@@ -2163,6 +2309,20 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
+static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ unsigned long exit_qualification;
+ u16 tss_selector;
+ int reason;
+
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+
+ reason = (u32)exit_qualification >> 30;
+ tss_selector = exit_qualification;
+
+ return kvm_task_switch(vcpu, tss_selector, reason);
+}
+
/*
* The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -2185,6 +2345,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
[EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold,
[EXIT_REASON_APIC_ACCESS] = handle_apic_access,
[EXIT_REASON_WBINVD] = handle_wbinvd,
+ [EXIT_REASON_TASK_SWITCH] = handle_task_switch,
};
static const int kvm_vmx_max_exit_handlers =
@@ -2200,6 +2361,9 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
struct vcpu_vmx *vmx = to_vmx(vcpu);
u32 vectoring_info = vmx->idt_vectoring_info;
+ KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)vmcs_readl(GUEST_RIP),
+ (u32)((u64)vmcs_readl(GUEST_RIP) >> 32), entryexit);
+
if (unlikely(vmx->fail)) {
kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
kvm_run->fail_entry.hardware_entry_failure_reason
@@ -2210,7 +2374,7 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
if ((vectoring_info & VECTORING_INFO_VALID_MASK) &&
exit_reason != EXIT_REASON_EXCEPTION_NMI)
printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
- "exit reason is 0x%x\n", __FUNCTION__, exit_reason);
+ "exit reason is 0x%x\n", __func__, exit_reason);
if (exit_reason < kvm_vmx_max_exit_handlers
&& kvm_vmx_exit_handlers[exit_reason])
return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
@@ -2221,10 +2385,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
return 0;
}
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
-{
-}
-
static void update_tpr_threshold(struct kvm_vcpu *vcpu)
{
int max_irr, tpr;
@@ -2285,11 +2445,13 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
return;
}
+ KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler);
+
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
- if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
+ if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK))
vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
vmcs_read32(IDT_VECTORING_ERROR_CODE));
if (unlikely(has_ext_irq))
@@ -2470,8 +2632,10 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
/* We need to handle NMIs before interrupts are enabled */
- if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+ if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
+ KVMTRACE_0D(NMI, vcpu, handler);
asm("int $2");
+ }
}
static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
@@ -2489,6 +2653,10 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ spin_lock(&vmx_vpid_lock);
+ if (vmx->vpid != 0)
+ __clear_bit(vmx->vpid, vmx_vpid_bitmap);
+ spin_unlock(&vmx_vpid_lock);
vmx_free_vmcs(vcpu);
kfree(vmx->host_msrs);
kfree(vmx->guest_msrs);
@@ -2505,6 +2673,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (!vmx)
return ERR_PTR(-ENOMEM);
+ allocate_vpid(vmx);
+
err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
if (err)
goto free_vcpu;
@@ -2591,14 +2761,13 @@ static struct kvm_x86_ops vmx_x86_ops = {
.get_segment_base = vmx_get_segment_base,
.get_segment = vmx_get_segment,
.set_segment = vmx_set_segment,
+ .get_cpl = vmx_get_cpl,
.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
.decache_cr4_guest_bits = vmx_decache_cr4_guest_bits,
.set_cr0 = vmx_set_cr0,
.set_cr3 = vmx_set_cr3,
.set_cr4 = vmx_set_cr4,
-#ifdef CONFIG_X86_64
.set_efer = vmx_set_efer,
-#endif
.get_idt = vmx_get_idt,
.set_idt = vmx_set_idt,
.get_gdt = vmx_get_gdt,
@@ -2626,7 +2795,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
static int __init vmx_init(void)
{
- void *iova;
+ void *va;
int r;
vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
@@ -2639,28 +2808,48 @@ static int __init vmx_init(void)
goto out;
}
+ vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ if (!vmx_msr_bitmap) {
+ r = -ENOMEM;
+ goto out1;
+ }
+
/*
* Allow direct access to the PC debug port (it is often used for I/O
* delays, but the vmexits simply slow things down).
*/
- iova = kmap(vmx_io_bitmap_a);
- memset(iova, 0xff, PAGE_SIZE);
- clear_bit(0x80, iova);
+ va = kmap(vmx_io_bitmap_a);
+ memset(va, 0xff, PAGE_SIZE);
+ clear_bit(0x80, va);
kunmap(vmx_io_bitmap_a);
- iova = kmap(vmx_io_bitmap_b);
- memset(iova, 0xff, PAGE_SIZE);
+ va = kmap(vmx_io_bitmap_b);
+ memset(va, 0xff, PAGE_SIZE);
kunmap(vmx_io_bitmap_b);
+ va = kmap(vmx_msr_bitmap);
+ memset(va, 0xff, PAGE_SIZE);
+ kunmap(vmx_msr_bitmap);
+
+ set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
+
r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
if (r)
- goto out1;
+ goto out2;
+
+ vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE);
+ vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE);
+ vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_CS);
+ vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP);
+ vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP);
if (bypass_guest_pf)
kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);
return 0;
+out2:
+ __free_page(vmx_msr_bitmap);
out1:
__free_page(vmx_io_bitmap_b);
out:
@@ -2670,6 +2859,7 @@ out:
static void __exit vmx_exit(void)
{
+ __free_page(vmx_msr_bitmap);
__free_page(vmx_io_bitmap_b);
__free_page(vmx_io_bitmap_a);
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h
index d52ae8d7303d..5dff4606b988 100644
--- a/arch/x86/kvm/vmx.h
+++ b/arch/x86/kvm/vmx.h
@@ -49,6 +49,7 @@
* Definitions of Secondary Processor-Based VM-Execution Controls.
*/
#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
+#define SECONDARY_EXEC_ENABLE_VPID 0x00000020
#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040
@@ -65,6 +66,7 @@
/* VMCS Encodings */
enum vmcs_field {
+ VIRTUAL_PROCESSOR_ID = 0x00000000,
GUEST_ES_SELECTOR = 0x00000800,
GUEST_CS_SELECTOR = 0x00000802,
GUEST_SS_SELECTOR = 0x00000804,
@@ -231,12 +233,12 @@ enum vmcs_field {
*/
#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */
#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */
-#define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */
+#define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */
#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */
#define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK
#define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK
-#define VECTORING_INFO_DELIEVER_CODE_MASK INTR_INFO_DELIEVER_CODE_MASK
+#define VECTORING_INFO_DELIVER_CODE_MASK INTR_INFO_DELIVER_CODE_MASK
#define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK
#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */
@@ -321,4 +323,8 @@ enum vmcs_field {
#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9
+#define VMX_NR_VPIDS (1 << 16)
+#define VMX_VPID_EXTENT_SINGLE_CONTEXT 1
+#define VMX_VPID_EXTENT_ALL_CONTEXT 2
+
#endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6b01552bd1f1..0ce556372a4d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -15,10 +15,12 @@
*/
#include <linux/kvm_host.h>
-#include "segment_descriptor.h"
#include "irq.h"
#include "mmu.h"
+#include "i8254.h"
+#include "tss.h"
+#include <linux/clocksource.h>
#include <linux/kvm.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
@@ -28,6 +30,7 @@
#include <asm/uaccess.h>
#include <asm/msr.h>
+#include <asm/desc.h>
#define MAX_IO_MSRS 256
#define CR0_RESERVED_BITS \
@@ -41,7 +44,15 @@
| X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
-#define EFER_RESERVED_BITS 0xfffffffffffff2fe
+/* EFER defaults:
+ * - enable syscall per default because its emulated by KVM
+ * - enable LME and LMA per default on 64 bit KVM
+ */
+#ifdef CONFIG_X86_64
+static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffafeULL;
+#else
+static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL;
+#endif
#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
@@ -63,6 +74,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "irq_window", VCPU_STAT(irq_window_exits) },
{ "halt_exits", VCPU_STAT(halt_exits) },
{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
+ { "hypercalls", VCPU_STAT(hypercalls) },
{ "request_irq", VCPU_STAT(request_irq_exits) },
{ "irq_exits", VCPU_STAT(irq_exits) },
{ "host_state_reload", VCPU_STAT(host_state_reload) },
@@ -78,6 +90,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "mmu_recycled", VM_STAT(mmu_recycled) },
{ "mmu_cache_miss", VM_STAT(mmu_cache_miss) },
{ "remote_tlb_flush", VM_STAT(remote_tlb_flush) },
+ { "largepages", VM_STAT(lpages) },
{ NULL }
};
@@ -85,7 +98,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
unsigned long segment_base(u16 selector)
{
struct descriptor_table gdt;
- struct segment_descriptor *d;
+ struct desc_struct *d;
unsigned long table_base;
unsigned long v;
@@ -101,13 +114,12 @@ unsigned long segment_base(u16 selector)
asm("sldt %0" : "=g"(ldt_selector));
table_base = segment_base(ldt_selector);
}
- d = (struct segment_descriptor *)(table_base + (selector & ~7));
- v = d->base_low | ((unsigned long)d->base_mid << 16) |
- ((unsigned long)d->base_high << 24);
+ d = (struct desc_struct *)(table_base + (selector & ~7));
+ v = d->base0 | ((unsigned long)d->base1 << 16) |
+ ((unsigned long)d->base2 << 24);
#ifdef CONFIG_X86_64
- if (d->system == 0 && (d->type == 2 || d->type == 9 || d->type == 11))
- v |= ((unsigned long) \
- ((struct segment_descriptor_64 *)d)->base_higher) << 32;
+ if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11))
+ v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32;
#endif
return v;
}
@@ -145,11 +157,16 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
u32 error_code)
{
++vcpu->stat.pf_guest;
- if (vcpu->arch.exception.pending && vcpu->arch.exception.nr == PF_VECTOR) {
- printk(KERN_DEBUG "kvm: inject_page_fault:"
- " double fault 0x%lx\n", addr);
- vcpu->arch.exception.nr = DF_VECTOR;
- vcpu->arch.exception.error_code = 0;
+ if (vcpu->arch.exception.pending) {
+ if (vcpu->arch.exception.nr == PF_VECTOR) {
+ printk(KERN_DEBUG "kvm: inject_page_fault:"
+ " double fault 0x%lx\n", addr);
+ vcpu->arch.exception.nr = DF_VECTOR;
+ vcpu->arch.exception.error_code = 0;
+ } else if (vcpu->arch.exception.nr == DF_VECTOR) {
+ /* triple fault -> shutdown */
+ set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+ }
return;
}
vcpu->arch.cr2 = addr;
@@ -184,7 +201,6 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
int ret;
u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
- down_read(&vcpu->kvm->slots_lock);
ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte,
offset * sizeof(u64), sizeof(pdpte));
if (ret < 0) {
@@ -201,10 +217,10 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
out:
- up_read(&vcpu->kvm->slots_lock);
return ret;
}
+EXPORT_SYMBOL_GPL(load_pdptrs);
static bool pdptrs_changed(struct kvm_vcpu *vcpu)
{
@@ -215,18 +231,16 @@ static bool pdptrs_changed(struct kvm_vcpu *vcpu)
if (is_long_mode(vcpu) || !is_pae(vcpu))
return false;
- down_read(&vcpu->kvm->slots_lock);
r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte));
if (r < 0)
goto out;
changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0;
out:
- up_read(&vcpu->kvm->slots_lock);
return changed;
}
-void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
if (cr0 & CR0_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
@@ -284,15 +298,18 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
kvm_mmu_reset_context(vcpu);
return;
}
-EXPORT_SYMBOL_GPL(set_cr0);
+EXPORT_SYMBOL_GPL(kvm_set_cr0);
-void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
+void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
{
- set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f));
+ kvm_set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f));
+ KVMTRACE_1D(LMSW, vcpu,
+ (u32)((vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)),
+ handler);
}
-EXPORT_SYMBOL_GPL(lmsw);
+EXPORT_SYMBOL_GPL(kvm_lmsw);
-void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
if (cr4 & CR4_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
@@ -323,9 +340,9 @@ void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
vcpu->arch.cr4 = cr4;
kvm_mmu_reset_context(vcpu);
}
-EXPORT_SYMBOL_GPL(set_cr4);
+EXPORT_SYMBOL_GPL(kvm_set_cr4);
-void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) {
kvm_mmu_flush_tlb(vcpu);
@@ -359,7 +376,6 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
*/
}
- down_read(&vcpu->kvm->slots_lock);
/*
* Does the new cr3 value map to physical memory? (Note, we
* catch an invalid cr3 even in real-mode, because it would
@@ -375,11 +391,10 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
vcpu->arch.cr3 = cr3;
vcpu->arch.mmu.new_cr3(vcpu);
}
- up_read(&vcpu->kvm->slots_lock);
}
-EXPORT_SYMBOL_GPL(set_cr3);
+EXPORT_SYMBOL_GPL(kvm_set_cr3);
-void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
{
if (cr8 & CR8_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
@@ -391,16 +406,16 @@ void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
else
vcpu->arch.cr8 = cr8;
}
-EXPORT_SYMBOL_GPL(set_cr8);
+EXPORT_SYMBOL_GPL(kvm_set_cr8);
-unsigned long get_cr8(struct kvm_vcpu *vcpu)
+unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
{
if (irqchip_in_kernel(vcpu->kvm))
return kvm_lapic_get_cr8(vcpu);
else
return vcpu->arch.cr8;
}
-EXPORT_SYMBOL_GPL(get_cr8);
+EXPORT_SYMBOL_GPL(kvm_get_cr8);
/*
* List of msr numbers which we expose to userspace through KVM_GET_MSRS
@@ -415,7 +430,8 @@ static u32 msrs_to_save[] = {
#ifdef CONFIG_X86_64
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
- MSR_IA32_TIME_STAMP_COUNTER,
+ MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
+ MSR_IA32_PERF_STATUS,
};
static unsigned num_msrs_to_save;
@@ -424,11 +440,9 @@ static u32 emulated_msrs[] = {
MSR_IA32_MISC_ENABLE,
};
-#ifdef CONFIG_X86_64
-
static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
- if (efer & EFER_RESERVED_BITS) {
+ if (efer & efer_reserved_bits) {
printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
efer);
kvm_inject_gp(vcpu, 0);
@@ -450,7 +464,12 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
vcpu->arch.shadow_efer = efer;
}
-#endif
+void kvm_enable_efer_bits(u64 mask)
+{
+ efer_reserved_bits &= ~mask;
+}
+EXPORT_SYMBOL_GPL(kvm_enable_efer_bits);
+
/*
* Writes msr value into into the appropriate "register".
@@ -470,26 +489,86 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
return kvm_set_msr(vcpu, index, *data);
}
+static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
+{
+ static int version;
+ struct kvm_wall_clock wc;
+ struct timespec wc_ts;
+
+ if (!wall_clock)
+ return;
+
+ version++;
+
+ kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
+
+ wc_ts = current_kernel_time();
+ wc.wc_sec = wc_ts.tv_sec;
+ wc.wc_nsec = wc_ts.tv_nsec;
+ wc.wc_version = version;
+
+ kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
+
+ version++;
+ kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
+}
+
+static void kvm_write_guest_time(struct kvm_vcpu *v)
+{
+ struct timespec ts;
+ unsigned long flags;
+ struct kvm_vcpu_arch *vcpu = &v->arch;
+ void *shared_kaddr;
+
+ if ((!vcpu->time_page))
+ return;
+
+ /* Keep irq disabled to prevent changes to the clock */
+ local_irq_save(flags);
+ kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER,
+ &vcpu->hv_clock.tsc_timestamp);
+ ktime_get_ts(&ts);
+ local_irq_restore(flags);
+
+ /* With all the info we got, fill in the values */
+
+ vcpu->hv_clock.system_time = ts.tv_nsec +
+ (NSEC_PER_SEC * (u64)ts.tv_sec);
+ /*
+ * The interface expects us to write an even number signaling that the
+ * update is finished. Since the guest won't see the intermediate
+ * state, we just write "2" at the end
+ */
+ vcpu->hv_clock.version = 2;
+
+ shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0);
+
+ memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock,
+ sizeof(vcpu->hv_clock));
+
+ kunmap_atomic(shared_kaddr, KM_USER0);
+
+ mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT);
+}
+
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
{
switch (msr) {
-#ifdef CONFIG_X86_64
case MSR_EFER:
set_efer(vcpu, data);
break;
-#endif
case MSR_IA32_MC0_STATUS:
pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
- __FUNCTION__, data);
+ __func__, data);
break;
case MSR_IA32_MCG_STATUS:
pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
- __FUNCTION__, data);
+ __func__, data);
break;
case MSR_IA32_MCG_CTL:
pr_unimpl(vcpu, "%s: MSR_IA32_MCG_CTL 0x%llx, nop\n",
- __FUNCTION__, data);
+ __func__, data);
break;
case MSR_IA32_UCODE_REV:
case MSR_IA32_UCODE_WRITE:
@@ -501,6 +580,42 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
case MSR_IA32_MISC_ENABLE:
vcpu->arch.ia32_misc_enable_msr = data;
break;
+ case MSR_KVM_WALL_CLOCK:
+ vcpu->kvm->arch.wall_clock = data;
+ kvm_write_wall_clock(vcpu->kvm, data);
+ break;
+ case MSR_KVM_SYSTEM_TIME: {
+ if (vcpu->arch.time_page) {
+ kvm_release_page_dirty(vcpu->arch.time_page);
+ vcpu->arch.time_page = NULL;
+ }
+
+ vcpu->arch.time = data;
+
+ /* we verify if the enable bit is set... */
+ if (!(data & 1))
+ break;
+
+ /* ...but clean it before doing the actual write */
+ vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);
+
+ vcpu->arch.hv_clock.tsc_to_system_mul =
+ clocksource_khz2mult(tsc_khz, 22);
+ vcpu->arch.hv_clock.tsc_shift = 22;
+
+ down_read(&current->mm->mmap_sem);
+ vcpu->arch.time_page =
+ gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
+ up_read(&current->mm->mmap_sem);
+
+ if (is_error_page(vcpu->arch.time_page)) {
+ kvm_release_page_clean(vcpu->arch.time_page);
+ vcpu->arch.time_page = NULL;
+ }
+
+ kvm_write_guest_time(vcpu);
+ break;
+ }
default:
pr_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n", msr, data);
return 1;
@@ -540,7 +655,6 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_MC0_MISC+12:
case MSR_IA32_MC0_MISC+16:
case MSR_IA32_UCODE_REV:
- case MSR_IA32_PERF_STATUS:
case MSR_IA32_EBL_CR_POWERON:
/* MTRR registers */
case 0xfe:
@@ -556,11 +670,21 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_MISC_ENABLE:
data = vcpu->arch.ia32_misc_enable_msr;
break;
-#ifdef CONFIG_X86_64
+ case MSR_IA32_PERF_STATUS:
+ /* TSC increment by tick */
+ data = 1000ULL;
+ /* CPU multiplier */
+ data |= (((uint64_t)4ULL) << 40);
+ break;
case MSR_EFER:
data = vcpu->arch.shadow_efer;
break;
-#endif
+ case MSR_KVM_WALL_CLOCK:
+ data = vcpu->kvm->arch.wall_clock;
+ break;
+ case MSR_KVM_SYSTEM_TIME:
+ data = vcpu->arch.time;
+ break;
default:
pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
return 1;
@@ -584,9 +708,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
vcpu_load(vcpu);
+ down_read(&vcpu->kvm->slots_lock);
for (i = 0; i < msrs->nmsrs; ++i)
if (do_msr(vcpu, entries[i].index, &entries[i].data))
break;
+ up_read(&vcpu->kvm->slots_lock);
vcpu_put(vcpu);
@@ -688,11 +814,24 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_USER_MEMORY:
case KVM_CAP_SET_TSS_ADDR:
case KVM_CAP_EXT_CPUID:
+ case KVM_CAP_CLOCKSOURCE:
+ case KVM_CAP_PIT:
+ case KVM_CAP_NOP_IO_DELAY:
+ case KVM_CAP_MP_STATE:
r = 1;
break;
case KVM_CAP_VAPIC:
r = !kvm_x86_ops->cpu_has_accelerated_tpr();
break;
+ case KVM_CAP_NR_VCPUS:
+ r = KVM_MAX_VCPUS;
+ break;
+ case KVM_CAP_NR_MEMSLOTS:
+ r = KVM_MEMORY_SLOTS;
+ break;
+ case KVM_CAP_PV_MMU:
+ r = !tdp_enabled;
+ break;
default:
r = 0;
break;
@@ -763,6 +902,7 @@ out:
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
kvm_x86_ops->vcpu_load(vcpu, cpu);
+ kvm_write_guest_time(vcpu);
}
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -958,32 +1098,32 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
}
/* function 4 and 0xb have additional index. */
case 4: {
- int index, cache_type;
+ int i, cache_type;
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
/* read more entries until cache_type is zero */
- for (index = 1; *nent < maxnent; ++index) {
- cache_type = entry[index - 1].eax & 0x1f;
+ for (i = 1; *nent < maxnent; ++i) {
+ cache_type = entry[i - 1].eax & 0x1f;
if (!cache_type)
break;
- do_cpuid_1_ent(&entry[index], function, index);
- entry[index].flags |=
+ do_cpuid_1_ent(&entry[i], function, i);
+ entry[i].flags |=
KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
++*nent;
}
break;
}
case 0xb: {
- int index, level_type;
+ int i, level_type;
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
/* read more entries until level_type is zero */
- for (index = 1; *nent < maxnent; ++index) {
- level_type = entry[index - 1].ecx & 0xff;
+ for (i = 1; *nent < maxnent; ++i) {
+ level_type = entry[i - 1].ecx & 0xff;
if (!level_type)
break;
- do_cpuid_1_ent(&entry[index], function, index);
- entry[index].flags |=
+ do_cpuid_1_ent(&entry[i], function, i);
+ entry[i].flags |=
KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
++*nent;
}
@@ -1365,6 +1505,23 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
return r;
}
+static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
+{
+ int r = 0;
+
+ memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state));
+ return r;
+}
+
+static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
+{
+ int r = 0;
+
+ memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
+ kvm_pit_load_count(kvm, 0, ps->channels[0].count);
+ return r;
+}
+
/*
* Get (and clear) the dirty memory log for a memory slot.
*/
@@ -1457,6 +1614,12 @@ long kvm_arch_vm_ioctl(struct file *filp,
} else
goto out;
break;
+ case KVM_CREATE_PIT:
+ r = -ENOMEM;
+ kvm->arch.vpit = kvm_create_pit(kvm);
+ if (kvm->arch.vpit)
+ r = 0;
+ break;
case KVM_IRQ_LINE: {
struct kvm_irq_level irq_event;
@@ -1512,6 +1675,37 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_GET_PIT: {
+ struct kvm_pit_state ps;
+ r = -EFAULT;
+ if (copy_from_user(&ps, argp, sizeof ps))
+ goto out;
+ r = -ENXIO;
+ if (!kvm->arch.vpit)
+ goto out;
+ r = kvm_vm_ioctl_get_pit(kvm, &ps);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &ps, sizeof ps))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_PIT: {
+ struct kvm_pit_state ps;
+ r = -EFAULT;
+ if (copy_from_user(&ps, argp, sizeof ps))
+ goto out;
+ r = -ENXIO;
+ if (!kvm->arch.vpit)
+ goto out;
+ r = kvm_vm_ioctl_set_pit(kvm, &ps);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
default:
;
}
@@ -1570,7 +1764,6 @@ int emulator_read_std(unsigned long addr,
void *data = val;
int r = X86EMUL_CONTINUE;
- down_read(&vcpu->kvm->slots_lock);
while (bytes) {
gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
unsigned offset = addr & (PAGE_SIZE-1);
@@ -1592,7 +1785,6 @@ int emulator_read_std(unsigned long addr,
addr += tocopy;
}
out:
- up_read(&vcpu->kvm->slots_lock);
return r;
}
EXPORT_SYMBOL_GPL(emulator_read_std);
@@ -1611,9 +1803,7 @@ static int emulator_read_emulated(unsigned long addr,
return X86EMUL_CONTINUE;
}
- down_read(&vcpu->kvm->slots_lock);
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
- up_read(&vcpu->kvm->slots_lock);
/* For APIC access vmexit */
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
@@ -1646,19 +1836,15 @@ mmio:
return X86EMUL_UNHANDLEABLE;
}
-static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
- const void *val, int bytes)
+int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
+ const void *val, int bytes)
{
int ret;
- down_read(&vcpu->kvm->slots_lock);
ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes);
- if (ret < 0) {
- up_read(&vcpu->kvm->slots_lock);
+ if (ret < 0)
return 0;
- }
kvm_mmu_pte_write(vcpu, gpa, val, bytes);
- up_read(&vcpu->kvm->slots_lock);
return 1;
}
@@ -1670,9 +1856,7 @@ static int emulator_write_emulated_onepage(unsigned long addr,
struct kvm_io_device *mmio_dev;
gpa_t gpa;
- down_read(&vcpu->kvm->slots_lock);
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
- up_read(&vcpu->kvm->slots_lock);
if (gpa == UNMAPPED_GVA) {
kvm_inject_page_fault(vcpu, addr, 2);
@@ -1749,7 +1933,6 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
char *kaddr;
u64 val;
- down_read(&vcpu->kvm->slots_lock);
gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
if (gpa == UNMAPPED_GVA ||
@@ -1769,9 +1952,8 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val);
kunmap_atomic(kaddr, KM_USER0);
kvm_release_page_dirty(page);
- emul_write:
- up_read(&vcpu->kvm->slots_lock);
}
+emul_write:
#endif
return emulator_write_emulated(addr, new, bytes, vcpu);
@@ -1802,7 +1984,7 @@ int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
*dest = kvm_x86_ops->get_dr(vcpu, dr);
return X86EMUL_CONTINUE;
default:
- pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr);
+ pr_unimpl(vcpu, "%s: unexpected dr %u\n", __func__, dr);
return X86EMUL_UNHANDLEABLE;
}
}
@@ -1840,7 +2022,7 @@ void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
}
EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
-struct x86_emulate_ops emulate_ops = {
+static struct x86_emulate_ops emulate_ops = {
.read_std = emulator_read_std,
.read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated,
@@ -2091,6 +2273,13 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->arch.pio.guest_page_offset = 0;
vcpu->arch.pio.rep = 0;
+ if (vcpu->run->io.direction == KVM_EXIT_IO_IN)
+ KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size,
+ handler);
+ else
+ KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size,
+ handler);
+
kvm_x86_ops->cache_regs(vcpu);
memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4);
kvm_x86_ops->decache_regs(vcpu);
@@ -2129,6 +2318,13 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->arch.pio.guest_page_offset = offset_in_page(address);
vcpu->arch.pio.rep = rep;
+ if (vcpu->run->io.direction == KVM_EXIT_IO_IN)
+ KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size,
+ handler);
+ else
+ KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size,
+ handler);
+
if (!count) {
kvm_x86_ops->skip_emulated_instruction(vcpu);
return 1;
@@ -2163,10 +2359,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
kvm_x86_ops->skip_emulated_instruction(vcpu);
for (i = 0; i < nr_pages; ++i) {
- down_read(&vcpu->kvm->slots_lock);
page = gva_to_page(vcpu, address + i * PAGE_SIZE);
vcpu->arch.pio.guest_pages[i] = page;
- up_read(&vcpu->kvm->slots_lock);
if (!page) {
kvm_inject_gp(vcpu, 0);
free_pio_guest_pages(vcpu);
@@ -2238,10 +2432,13 @@ void kvm_arch_exit(void)
int kvm_emulate_halt(struct kvm_vcpu *vcpu)
{
++vcpu->stat.halt_exits;
+ KVMTRACE_0D(HLT, vcpu, handler);
if (irqchip_in_kernel(vcpu->kvm)) {
- vcpu->arch.mp_state = VCPU_MP_STATE_HALTED;
+ vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
+ up_read(&vcpu->kvm->slots_lock);
kvm_vcpu_block(vcpu);
- if (vcpu->arch.mp_state != VCPU_MP_STATE_RUNNABLE)
+ down_read(&vcpu->kvm->slots_lock);
+ if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE)
return -EINTR;
return 1;
} else {
@@ -2251,9 +2448,19 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_emulate_halt);
+static inline gpa_t hc_gpa(struct kvm_vcpu *vcpu, unsigned long a0,
+ unsigned long a1)
+{
+ if (is_long_mode(vcpu))
+ return a0;
+ else
+ return a0 | ((gpa_t)a1 << 32);
+}
+
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
{
unsigned long nr, a0, a1, a2, a3, ret;
+ int r = 1;
kvm_x86_ops->cache_regs(vcpu);
@@ -2263,6 +2470,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
a2 = vcpu->arch.regs[VCPU_REGS_RDX];
a3 = vcpu->arch.regs[VCPU_REGS_RSI];
+ KVMTRACE_1D(VMMCALL, vcpu, (u32)nr, handler);
+
if (!is_long_mode(vcpu)) {
nr &= 0xFFFFFFFF;
a0 &= 0xFFFFFFFF;
@@ -2275,13 +2484,17 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
case KVM_HC_VAPIC_POLL_IRQ:
ret = 0;
break;
+ case KVM_HC_MMU_OP:
+ r = kvm_pv_mmu_op(vcpu, a0, hc_gpa(vcpu, a1, a2), &ret);
+ break;
default:
ret = -KVM_ENOSYS;
break;
}
vcpu->arch.regs[VCPU_REGS_RAX] = ret;
kvm_x86_ops->decache_regs(vcpu);
- return 0;
+ ++vcpu->stat.hypercalls;
+ return r;
}
EXPORT_SYMBOL_GPL(kvm_emulate_hypercall);
@@ -2329,7 +2542,7 @@ void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long *rflags)
{
- lmsw(vcpu, msw);
+ kvm_lmsw(vcpu, msw);
*rflags = kvm_x86_ops->get_rflags(vcpu);
}
@@ -2346,9 +2559,9 @@ unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
case 4:
return vcpu->arch.cr4;
case 8:
- return get_cr8(vcpu);
+ return kvm_get_cr8(vcpu);
default:
- vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
return 0;
}
}
@@ -2358,23 +2571,23 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
{
switch (cr) {
case 0:
- set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
+ kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
*rflags = kvm_x86_ops->get_rflags(vcpu);
break;
case 2:
vcpu->arch.cr2 = val;
break;
case 3:
- set_cr3(vcpu, val);
+ kvm_set_cr3(vcpu, val);
break;
case 4:
- set_cr4(vcpu, mk_cr_64(vcpu->arch.cr4, val));
+ kvm_set_cr4(vcpu, mk_cr_64(vcpu->arch.cr4, val));
break;
case 8:
- set_cr8(vcpu, val & 0xfUL);
+ kvm_set_cr8(vcpu, val & 0xfUL);
break;
default:
- vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
+ vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
}
}
@@ -2447,6 +2660,11 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
}
kvm_x86_ops->decache_regs(vcpu);
kvm_x86_ops->skip_emulated_instruction(vcpu);
+ KVMTRACE_5D(CPUID, vcpu, function,
+ (u32)vcpu->arch.regs[VCPU_REGS_RAX],
+ (u32)vcpu->arch.regs[VCPU_REGS_RBX],
+ (u32)vcpu->arch.regs[VCPU_REGS_RCX],
+ (u32)vcpu->arch.regs[VCPU_REGS_RDX], handler);
}
EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
@@ -2469,7 +2687,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
- kvm_run->cr8 = get_cr8(vcpu);
+ kvm_run->cr8 = kvm_get_cr8(vcpu);
kvm_run->apic_base = kvm_get_apic_base(vcpu);
if (irqchip_in_kernel(vcpu->kvm))
kvm_run->ready_for_interrupt_injection = 1;
@@ -2509,16 +2727,17 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
int r;
- if (unlikely(vcpu->arch.mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) {
+ if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED)) {
pr_debug("vcpu %d received sipi with vector # %x\n",
vcpu->vcpu_id, vcpu->arch.sipi_vector);
kvm_lapic_reset(vcpu);
r = kvm_x86_ops->vcpu_reset(vcpu);
if (r)
return r;
- vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE;
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
}
+ down_read(&vcpu->kvm->slots_lock);
vapic_enter(vcpu);
preempted:
@@ -2526,6 +2745,10 @@ preempted:
kvm_x86_ops->guest_debug_pre(vcpu);
again:
+ if (vcpu->requests)
+ if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
+ kvm_mmu_unload(vcpu);
+
r = kvm_mmu_reload(vcpu);
if (unlikely(r))
goto out;
@@ -2539,6 +2762,11 @@ again:
r = 0;
goto out;
}
+ if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) {
+ kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ r = 0;
+ goto out;
+ }
}
kvm_inject_pending_timer_irqs(vcpu);
@@ -2557,6 +2785,14 @@ again:
goto out;
}
+ if (vcpu->requests)
+ if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) {
+ local_irq_enable();
+ preempt_enable();
+ r = 1;
+ goto out;
+ }
+
if (signal_pending(current)) {
local_irq_enable();
preempt_enable();
@@ -2566,6 +2802,13 @@ again:
goto out;
}
+ vcpu->guest_mode = 1;
+ /*
+ * Make sure that guest_mode assignment won't happen after
+ * testing the pending IRQ vector bitmap.
+ */
+ smp_wmb();
+
if (vcpu->arch.exception.pending)
__queue_exception(vcpu);
else if (irqchip_in_kernel(vcpu->kvm))
@@ -2575,13 +2818,15 @@ again:
kvm_lapic_sync_to_vapic(vcpu);
- vcpu->guest_mode = 1;
+ up_read(&vcpu->kvm->slots_lock);
+
kvm_guest_enter();
if (vcpu->requests)
if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
kvm_x86_ops->tlb_flush(vcpu);
+ KVMTRACE_0D(VMENTRY, vcpu, entryexit);
kvm_x86_ops->run(vcpu, kvm_run);
vcpu->guest_mode = 0;
@@ -2601,6 +2846,8 @@ again:
preempt_enable();
+ down_read(&vcpu->kvm->slots_lock);
+
/*
* Profile KVM exit RIPs:
*/
@@ -2628,14 +2875,18 @@ again:
}
out:
+ up_read(&vcpu->kvm->slots_lock);
if (r > 0) {
kvm_resched(vcpu);
+ down_read(&vcpu->kvm->slots_lock);
goto preempted;
}
post_kvm_run_save(vcpu, kvm_run);
+ down_read(&vcpu->kvm->slots_lock);
vapic_exit(vcpu);
+ up_read(&vcpu->kvm->slots_lock);
return r;
}
@@ -2647,7 +2898,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load(vcpu);
- if (unlikely(vcpu->arch.mp_state == VCPU_MP_STATE_UNINITIALIZED)) {
+ if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
kvm_vcpu_block(vcpu);
vcpu_put(vcpu);
return -EAGAIN;
@@ -2658,7 +2909,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
/* re-sync apic's tpr */
if (!irqchip_in_kernel(vcpu->kvm))
- set_cr8(vcpu, kvm_run->cr8);
+ kvm_set_cr8(vcpu, kvm_run->cr8);
if (vcpu->arch.pio.cur_count) {
r = complete_pio(vcpu);
@@ -2670,9 +2921,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
vcpu->mmio_read_completed = 1;
vcpu->mmio_needed = 0;
+
+ down_read(&vcpu->kvm->slots_lock);
r = emulate_instruction(vcpu, kvm_run,
vcpu->arch.mmio_fault_cr2, 0,
EMULTYPE_NO_DECODE);
+ up_read(&vcpu->kvm->slots_lock);
if (r == EMULATE_DO_MMIO) {
/*
* Read-modify-write. Back to userspace.
@@ -2773,7 +3027,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
static void get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
- return kvm_x86_ops->get_segment(vcpu, var, seg);
+ kvm_x86_ops->get_segment(vcpu, var, seg);
}
void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
@@ -2816,7 +3070,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
sregs->cr2 = vcpu->arch.cr2;
sregs->cr3 = vcpu->arch.cr3;
sregs->cr4 = vcpu->arch.cr4;
- sregs->cr8 = get_cr8(vcpu);
+ sregs->cr8 = kvm_get_cr8(vcpu);
sregs->efer = vcpu->arch.shadow_efer;
sregs->apic_base = kvm_get_apic_base(vcpu);
@@ -2836,12 +3090,438 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
return 0;
}
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ vcpu_load(vcpu);
+ mp_state->mp_state = vcpu->arch.mp_state;
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ vcpu_load(vcpu);
+ vcpu->arch.mp_state = mp_state->mp_state;
+ vcpu_put(vcpu);
+ return 0;
+}
+
static void set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
- return kvm_x86_ops->set_segment(vcpu, var, seg);
+ kvm_x86_ops->set_segment(vcpu, var, seg);
+}
+
+static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
+ struct kvm_segment *kvm_desct)
+{
+ kvm_desct->base = seg_desc->base0;
+ kvm_desct->base |= seg_desc->base1 << 16;
+ kvm_desct->base |= seg_desc->base2 << 24;
+ kvm_desct->limit = seg_desc->limit0;
+ kvm_desct->limit |= seg_desc->limit << 16;
+ kvm_desct->selector = selector;
+ kvm_desct->type = seg_desc->type;
+ kvm_desct->present = seg_desc->p;
+ kvm_desct->dpl = seg_desc->dpl;
+ kvm_desct->db = seg_desc->d;
+ kvm_desct->s = seg_desc->s;
+ kvm_desct->l = seg_desc->l;
+ kvm_desct->g = seg_desc->g;
+ kvm_desct->avl = seg_desc->avl;
+ if (!selector)
+ kvm_desct->unusable = 1;
+ else
+ kvm_desct->unusable = 0;
+ kvm_desct->padding = 0;
+}
+
+static void get_segment_descritptor_dtable(struct kvm_vcpu *vcpu,
+ u16 selector,
+ struct descriptor_table *dtable)
+{
+ if (selector & 1 << 2) {
+ struct kvm_segment kvm_seg;
+
+ get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR);
+
+ if (kvm_seg.unusable)
+ dtable->limit = 0;
+ else
+ dtable->limit = kvm_seg.limit;
+ dtable->base = kvm_seg.base;
+ }
+ else
+ kvm_x86_ops->get_gdt(vcpu, dtable);
+}
+
+/* allowed just for 8 bytes segments */
+static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+ struct desc_struct *seg_desc)
+{
+ struct descriptor_table dtable;
+ u16 index = selector >> 3;
+
+ get_segment_descritptor_dtable(vcpu, selector, &dtable);
+
+ if (dtable.limit < index * 8 + 7) {
+ kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
+ return 1;
+ }
+ return kvm_read_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
+}
+
+/* allowed just for 8 bytes segments */
+static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+ struct desc_struct *seg_desc)
+{
+ struct descriptor_table dtable;
+ u16 index = selector >> 3;
+
+ get_segment_descritptor_dtable(vcpu, selector, &dtable);
+
+ if (dtable.limit < index * 8 + 7)
+ return 1;
+ return kvm_write_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
+}
+
+static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
+ struct desc_struct *seg_desc)
+{
+ u32 base_addr;
+
+ base_addr = seg_desc->base0;
+ base_addr |= (seg_desc->base1 << 16);
+ base_addr |= (seg_desc->base2 << 24);
+
+ return base_addr;
+}
+
+static int load_tss_segment32(struct kvm_vcpu *vcpu,
+ struct desc_struct *seg_desc,
+ struct tss_segment_32 *tss)
+{
+ u32 base_addr;
+
+ base_addr = get_tss_base_addr(vcpu, seg_desc);
+
+ return kvm_read_guest(vcpu->kvm, base_addr, tss,
+ sizeof(struct tss_segment_32));
+}
+
+static int save_tss_segment32(struct kvm_vcpu *vcpu,
+ struct desc_struct *seg_desc,
+ struct tss_segment_32 *tss)
+{
+ u32 base_addr;
+
+ base_addr = get_tss_base_addr(vcpu, seg_desc);
+
+ return kvm_write_guest(vcpu->kvm, base_addr, tss,
+ sizeof(struct tss_segment_32));
+}
+
+static int load_tss_segment16(struct kvm_vcpu *vcpu,
+ struct desc_struct *seg_desc,
+ struct tss_segment_16 *tss)
+{
+ u32 base_addr;
+
+ base_addr = get_tss_base_addr(vcpu, seg_desc);
+
+ return kvm_read_guest(vcpu->kvm, base_addr, tss,
+ sizeof(struct tss_segment_16));
+}
+
+static int save_tss_segment16(struct kvm_vcpu *vcpu,
+ struct desc_struct *seg_desc,
+ struct tss_segment_16 *tss)
+{
+ u32 base_addr;
+
+ base_addr = get_tss_base_addr(vcpu, seg_desc);
+
+ return kvm_write_guest(vcpu->kvm, base_addr, tss,
+ sizeof(struct tss_segment_16));
+}
+
+static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
+{
+ struct kvm_segment kvm_seg;
+
+ get_segment(vcpu, &kvm_seg, seg);
+ return kvm_seg.selector;
+}
+
+static int load_segment_descriptor_to_kvm_desct(struct kvm_vcpu *vcpu,
+ u16 selector,
+ struct kvm_segment *kvm_seg)
+{
+ struct desc_struct seg_desc;
+
+ if (load_guest_segment_descriptor(vcpu, selector, &seg_desc))
+ return 1;
+ seg_desct_to_kvm_desct(&seg_desc, selector, kvm_seg);
+ return 0;
+}
+
+static int load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+ int type_bits, int seg)
+{
+ struct kvm_segment kvm_seg;
+
+ if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg))
+ return 1;
+ kvm_seg.type |= type_bits;
+
+ if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS &&
+ seg != VCPU_SREG_LDTR)
+ if (!kvm_seg.s)
+ kvm_seg.unusable = 1;
+
+ set_segment(vcpu, &kvm_seg, seg);
+ return 0;
+}
+
+static void save_state_to_tss32(struct kvm_vcpu *vcpu,
+ struct tss_segment_32 *tss)
+{
+ tss->cr3 = vcpu->arch.cr3;
+ tss->eip = vcpu->arch.rip;
+ tss->eflags = kvm_x86_ops->get_rflags(vcpu);
+ tss->eax = vcpu->arch.regs[VCPU_REGS_RAX];
+ tss->ecx = vcpu->arch.regs[VCPU_REGS_RCX];
+ tss->edx = vcpu->arch.regs[VCPU_REGS_RDX];
+ tss->ebx = vcpu->arch.regs[VCPU_REGS_RBX];
+ tss->esp = vcpu->arch.regs[VCPU_REGS_RSP];
+ tss->ebp = vcpu->arch.regs[VCPU_REGS_RBP];
+ tss->esi = vcpu->arch.regs[VCPU_REGS_RSI];
+ tss->edi = vcpu->arch.regs[VCPU_REGS_RDI];
+
+ tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
+ tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
+ tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
+ tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
+ tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
+ tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
+ tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
+ tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
+}
+
+static int load_state_from_tss32(struct kvm_vcpu *vcpu,
+ struct tss_segment_32 *tss)
+{
+ kvm_set_cr3(vcpu, tss->cr3);
+
+ vcpu->arch.rip = tss->eip;
+ kvm_x86_ops->set_rflags(vcpu, tss->eflags | 2);
+
+ vcpu->arch.regs[VCPU_REGS_RAX] = tss->eax;
+ vcpu->arch.regs[VCPU_REGS_RCX] = tss->ecx;
+ vcpu->arch.regs[VCPU_REGS_RDX] = tss->edx;
+ vcpu->arch.regs[VCPU_REGS_RBX] = tss->ebx;
+ vcpu->arch.regs[VCPU_REGS_RSP] = tss->esp;
+ vcpu->arch.regs[VCPU_REGS_RBP] = tss->ebp;
+ vcpu->arch.regs[VCPU_REGS_RSI] = tss->esi;
+ vcpu->arch.regs[VCPU_REGS_RDI] = tss->edi;
+
+ if (load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS))
+ return 1;
+ return 0;
+}
+
+static void save_state_to_tss16(struct kvm_vcpu *vcpu,
+ struct tss_segment_16 *tss)
+{
+ tss->ip = vcpu->arch.rip;
+ tss->flag = kvm_x86_ops->get_rflags(vcpu);
+ tss->ax = vcpu->arch.regs[VCPU_REGS_RAX];
+ tss->cx = vcpu->arch.regs[VCPU_REGS_RCX];
+ tss->dx = vcpu->arch.regs[VCPU_REGS_RDX];
+ tss->bx = vcpu->arch.regs[VCPU_REGS_RBX];
+ tss->sp = vcpu->arch.regs[VCPU_REGS_RSP];
+ tss->bp = vcpu->arch.regs[VCPU_REGS_RBP];
+ tss->si = vcpu->arch.regs[VCPU_REGS_RSI];
+ tss->di = vcpu->arch.regs[VCPU_REGS_RDI];
+
+ tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
+ tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
+ tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
+ tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
+ tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR);
+ tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
+}
+
+static int load_state_from_tss16(struct kvm_vcpu *vcpu,
+ struct tss_segment_16 *tss)
+{
+ vcpu->arch.rip = tss->ip;
+ kvm_x86_ops->set_rflags(vcpu, tss->flag | 2);
+ vcpu->arch.regs[VCPU_REGS_RAX] = tss->ax;
+ vcpu->arch.regs[VCPU_REGS_RCX] = tss->cx;
+ vcpu->arch.regs[VCPU_REGS_RDX] = tss->dx;
+ vcpu->arch.regs[VCPU_REGS_RBX] = tss->bx;
+ vcpu->arch.regs[VCPU_REGS_RSP] = tss->sp;
+ vcpu->arch.regs[VCPU_REGS_RBP] = tss->bp;
+ vcpu->arch.regs[VCPU_REGS_RSI] = tss->si;
+ vcpu->arch.regs[VCPU_REGS_RDI] = tss->di;
+
+ if (load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
+ return 1;
+
+ if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
+ return 1;
+ return 0;
+}
+
+int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
+ struct desc_struct *cseg_desc,
+ struct desc_struct *nseg_desc)
+{
+ struct tss_segment_16 tss_segment_16;
+ int ret = 0;
+
+ if (load_tss_segment16(vcpu, cseg_desc, &tss_segment_16))
+ goto out;
+
+ save_state_to_tss16(vcpu, &tss_segment_16);
+ save_tss_segment16(vcpu, cseg_desc, &tss_segment_16);
+
+ if (load_tss_segment16(vcpu, nseg_desc, &tss_segment_16))
+ goto out;
+ if (load_state_from_tss16(vcpu, &tss_segment_16))
+ goto out;
+
+ ret = 1;
+out:
+ return ret;
+}
+
+int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
+ struct desc_struct *cseg_desc,
+ struct desc_struct *nseg_desc)
+{
+ struct tss_segment_32 tss_segment_32;
+ int ret = 0;
+
+ if (load_tss_segment32(vcpu, cseg_desc, &tss_segment_32))
+ goto out;
+
+ save_state_to_tss32(vcpu, &tss_segment_32);
+ save_tss_segment32(vcpu, cseg_desc, &tss_segment_32);
+
+ if (load_tss_segment32(vcpu, nseg_desc, &tss_segment_32))
+ goto out;
+ if (load_state_from_tss32(vcpu, &tss_segment_32))
+ goto out;
+
+ ret = 1;
+out:
+ return ret;
}
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
+{
+ struct kvm_segment tr_seg;
+ struct desc_struct cseg_desc;
+ struct desc_struct nseg_desc;
+ int ret = 0;
+
+ get_segment(vcpu, &tr_seg, VCPU_SREG_TR);
+
+ if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
+ goto out;
+
+ if (load_guest_segment_descriptor(vcpu, tr_seg.selector, &cseg_desc))
+ goto out;
+
+
+ if (reason != TASK_SWITCH_IRET) {
+ int cpl;
+
+ cpl = kvm_x86_ops->get_cpl(vcpu);
+ if ((tss_selector & 3) > nseg_desc.dpl || cpl > nseg_desc.dpl) {
+ kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
+ return 1;
+ }
+ }
+
+ if (!nseg_desc.p || (nseg_desc.limit0 | nseg_desc.limit << 16) < 0x67) {
+ kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc);
+ return 1;
+ }
+
+ if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
+ cseg_desc.type &= ~(1 << 8); //clear the B flag
+ save_guest_segment_descriptor(vcpu, tr_seg.selector,
+ &cseg_desc);
+ }
+
+ if (reason == TASK_SWITCH_IRET) {
+ u32 eflags = kvm_x86_ops->get_rflags(vcpu);
+ kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
+ }
+
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
+
+ if (nseg_desc.type & 8)
+ ret = kvm_task_switch_32(vcpu, tss_selector, &cseg_desc,
+ &nseg_desc);
+ else
+ ret = kvm_task_switch_16(vcpu, tss_selector, &cseg_desc,
+ &nseg_desc);
+
+ if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
+ u32 eflags = kvm_x86_ops->get_rflags(vcpu);
+ kvm_x86_ops->set_rflags(vcpu, eflags | X86_EFLAGS_NT);
+ }
+
+ if (reason != TASK_SWITCH_IRET) {
+ nseg_desc.type |= (1 << 8);
+ save_guest_segment_descriptor(vcpu, tss_selector,
+ &nseg_desc);
+ }
+
+ kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 | X86_CR0_TS);
+ seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
+ tr_seg.type = 11;
+ set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
+out:
+ kvm_x86_ops->decache_regs(vcpu);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_task_switch);
+
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
@@ -2862,12 +3542,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
vcpu->arch.cr3 = sregs->cr3;
- set_cr8(vcpu, sregs->cr8);
+ kvm_set_cr8(vcpu, sregs->cr8);
mmu_reset_needed |= vcpu->arch.shadow_efer != sregs->efer;
-#ifdef CONFIG_X86_64
kvm_x86_ops->set_efer(vcpu, sregs->efer);
-#endif
kvm_set_apic_base(vcpu, sregs->apic_base);
kvm_x86_ops->decache_cr4_guest_bits(vcpu);
@@ -3141,9 +3819,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
vcpu->arch.mmu.root_hpa = INVALID_PAGE;
if (!irqchip_in_kernel(kvm) || vcpu->vcpu_id == 0)
- vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE;
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
else
- vcpu->arch.mp_state = VCPU_MP_STATE_UNINITIALIZED;
+ vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page) {
@@ -3175,7 +3853,9 @@ fail:
void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
{
kvm_free_lapic(vcpu);
+ down_read(&vcpu->kvm->slots_lock);
kvm_mmu_destroy(vcpu);
+ up_read(&vcpu->kvm->slots_lock);
free_page((unsigned long)vcpu->arch.pio_data);
}
@@ -3219,10 +3899,13 @@ static void kvm_free_vcpus(struct kvm *kvm)
void kvm_arch_destroy_vm(struct kvm *kvm)
{
+ kvm_free_pit(kvm);
kfree(kvm->arch.vpic);
kfree(kvm->arch.vioapic);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
+ if (kvm->arch.apic_access_page)
+ put_page(kvm->arch.apic_access_page);
kfree(kvm);
}
@@ -3278,8 +3961,8 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
- return vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE
- || vcpu->arch.mp_state == VCPU_MP_STATE_SIPI_RECEIVED;
+ return vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE
+ || vcpu->arch.mp_state == KVM_MP_STATE_SIPI_RECEIVED;
}
static void vcpu_kick_intr(void *info)
@@ -3293,11 +3976,17 @@ static void vcpu_kick_intr(void *info)
void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
{
int ipi_pcpu = vcpu->cpu;
+ int cpu = get_cpu();
if (waitqueue_active(&vcpu->wq)) {
wake_up_interruptible(&vcpu->wq);
++vcpu->stat.halt_wakeup;
}
- if (vcpu->guest_mode)
+ /*
+ * We may be called synchronously with irqs disabled in guest mode,
+ * So need not to call smp_call_function_single() in that case.
+ */
+ if (vcpu->guest_mode && vcpu->cpu != cpu)
smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
+ put_cpu();
}
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c
index 79586003397a..2ca08386f993 100644
--- a/arch/x86/kvm/x86_emulate.c
+++ b/arch/x86/kvm/x86_emulate.c
@@ -65,6 +65,14 @@
#define MemAbs (1<<9) /* Memory operand is absolute displacement */
#define String (1<<10) /* String instruction (rep capable) */
#define Stack (1<<11) /* Stack instruction (push/pop) */
+#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
+#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
+#define GroupMask 0xff /* Group number stored in bits 0:7 */
+
+enum {
+ Group1_80, Group1_81, Group1_82, Group1_83,
+ Group1A, Group3_Byte, Group3, Group4, Group5, Group7,
+};
static u16 opcode_table[256] = {
/* 0x00 - 0x07 */
@@ -123,14 +131,14 @@ static u16 opcode_table[256] = {
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x80 - 0x87 */
- ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
- ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
+ Group | Group1_80, Group | Group1_81,
+ Group | Group1_82, Group | Group1_83,
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
/* 0x88 - 0x8F */
ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov | Stack,
+ 0, ModRM | DstReg, 0, Group | Group1A,
/* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
@@ -164,16 +172,15 @@ static u16 opcode_table[256] = {
0, 0, 0, 0,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
- ImplicitOps, ImplicitOps,
- ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+ ImplicitOps, ImplicitOps, Group | Group3_Byte, Group | Group3,
/* 0xF8 - 0xFF */
ImplicitOps, 0, ImplicitOps, ImplicitOps,
- 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM
+ 0, 0, Group | Group4, Group | Group5,
};
static u16 twobyte_table[256] = {
/* 0x00 - 0x0F */
- 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
+ 0, Group | GroupDual | Group7, 0, 0, 0, 0, ImplicitOps, 0,
ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
/* 0x10 - 0x1F */
0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
@@ -229,6 +236,56 @@ static u16 twobyte_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
+static u16 group_table[] = {
+ [Group1_80*8] =
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ [Group1_81*8] =
+ DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+ DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+ DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+ DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+ [Group1_82*8] =
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+ [Group1_83*8] =
+ DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
+ DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
+ DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
+ DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
+ [Group1A*8] =
+ DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0,
+ [Group3_Byte*8] =
+ ByteOp | SrcImm | DstMem | ModRM, 0,
+ ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
+ 0, 0, 0, 0,
+ [Group3*8] =
+ DstMem | SrcImm | ModRM | SrcImm, 0,
+ DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
+ 0, 0, 0, 0,
+ [Group4*8] =
+ ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
+ 0, 0, 0, 0, 0, 0,
+ [Group5*8] =
+ DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, 0, 0,
+ SrcMem | ModRM, 0, SrcMem | ModRM | Stack, 0,
+ [Group7*8] =
+ 0, 0, ModRM | SrcMem, ModRM | SrcMem,
+ SrcNone | ModRM | DstMem | Mov, 0,
+ SrcMem16 | ModRM | Mov, SrcMem | ModRM | ByteOp,
+};
+
+static u16 group2_table[] = {
+ [Group7*8] =
+ SrcNone | ModRM, 0, 0, 0,
+ SrcNone | ModRM | DstMem | Mov, 0,
+ SrcMem16 | ModRM | Mov, 0,
+};
+
/* EFLAGS bit definitions. */
#define EFLG_OF (1<<11)
#define EFLG_DF (1<<10)
@@ -317,7 +374,7 @@ static u16 twobyte_table[256] = {
#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \
do { \
- unsigned long _tmp; \
+ unsigned long __tmp; \
switch ((_dst).bytes) { \
case 1: \
__asm__ __volatile__ ( \
@@ -325,7 +382,7 @@ static u16 twobyte_table[256] = {
_op"b %"_bx"3,%1; " \
_POST_EFLAGS("0", "4", "2") \
: "=m" (_eflags), "=m" ((_dst).val), \
- "=&r" (_tmp) \
+ "=&r" (__tmp) \
: _by ((_src).val), "i" (EFLAGS_MASK)); \
break; \
default: \
@@ -426,29 +483,40 @@ static u16 twobyte_table[256] = {
(_type)_x; \
})
+static inline unsigned long ad_mask(struct decode_cache *c)
+{
+ return (1UL << (c->ad_bytes << 3)) - 1;
+}
+
/* Access/update address held in a register, based on addressing mode. */
-#define address_mask(reg) \
- ((c->ad_bytes == sizeof(unsigned long)) ? \
- (reg) : ((reg) & ((1UL << (c->ad_bytes << 3)) - 1)))
-#define register_address(base, reg) \
- ((base) + address_mask(reg))
-#define register_address_increment(reg, inc) \
- do { \
- /* signed type ensures sign extension to long */ \
- int _inc = (inc); \
- if (c->ad_bytes == sizeof(unsigned long)) \
- (reg) += _inc; \
- else \
- (reg) = ((reg) & \
- ~((1UL << (c->ad_bytes << 3)) - 1)) | \
- (((reg) + _inc) & \
- ((1UL << (c->ad_bytes << 3)) - 1)); \
- } while (0)
+static inline unsigned long
+address_mask(struct decode_cache *c, unsigned long reg)
+{
+ if (c->ad_bytes == sizeof(unsigned long))
+ return reg;
+ else
+ return reg & ad_mask(c);
+}
-#define JMP_REL(rel) \
- do { \
- register_address_increment(c->eip, rel); \
- } while (0)
+static inline unsigned long
+register_address(struct decode_cache *c, unsigned long base, unsigned long reg)
+{
+ return base + address_mask(c, reg);
+}
+
+static inline void
+register_address_increment(struct decode_cache *c, unsigned long *reg, int inc)
+{
+ if (c->ad_bytes == sizeof(unsigned long))
+ *reg += inc;
+ else
+ *reg = (*reg & ~ad_mask(c)) | ((*reg + inc) & ad_mask(c));
+}
+
+static inline void jmp_rel(struct decode_cache *c, int rel)
+{
+ register_address_increment(c, &c->eip, rel);
+}
static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
@@ -763,7 +831,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
struct decode_cache *c = &ctxt->decode;
int rc = 0;
int mode = ctxt->mode;
- int def_op_bytes, def_ad_bytes;
+ int def_op_bytes, def_ad_bytes, group;
/* Shadow copy of register state. Committed on successful emulation. */
@@ -864,12 +932,24 @@ done_prefixes:
c->b = insn_fetch(u8, 1, c->eip);
c->d = twobyte_table[c->b];
}
+ }
- /* Unrecognised? */
- if (c->d == 0) {
- DPRINTF("Cannot emulate %02x\n", c->b);
- return -1;
- }
+ if (c->d & Group) {
+ group = c->d & GroupMask;
+ c->modrm = insn_fetch(u8, 1, c->eip);
+ --c->eip;
+
+ group = (group << 3) + ((c->modrm >> 3) & 7);
+ if ((c->d & GroupDual) && (c->modrm >> 6) == 3)
+ c->d = group2_table[group];
+ else
+ c->d = group_table[group];
+ }
+
+ /* Unrecognised? */
+ if (c->d == 0) {
+ DPRINTF("Cannot emulate %02x\n", c->b);
+ return -1;
}
if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
@@ -924,6 +1004,7 @@ done_prefixes:
*/
if ((c->d & ModRM) && c->modrm_mod == 3) {
c->src.type = OP_REG;
+ c->src.val = c->modrm_val;
break;
}
c->src.type = OP_MEM;
@@ -967,6 +1048,7 @@ done_prefixes:
case DstMem:
if ((c->d & ModRM) && c->modrm_mod == 3) {
c->dst.type = OP_REG;
+ c->dst.val = c->dst.orig_val = c->modrm_val;
break;
}
c->dst.type = OP_MEM;
@@ -984,8 +1066,8 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
c->dst.type = OP_MEM;
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
- register_address_increment(c->regs[VCPU_REGS_RSP], -c->op_bytes);
- c->dst.ptr = (void *) register_address(ctxt->ss_base,
+ register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
+ c->dst.ptr = (void *) register_address(c, ctxt->ss_base,
c->regs[VCPU_REGS_RSP]);
}
@@ -995,13 +1077,13 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c = &ctxt->decode;
int rc;
- rc = ops->read_std(register_address(ctxt->ss_base,
+ rc = ops->read_std(register_address(c, ctxt->ss_base,
c->regs[VCPU_REGS_RSP]),
&c->dst.val, c->dst.bytes, ctxt->vcpu);
if (rc != 0)
return rc;
- register_address_increment(c->regs[VCPU_REGS_RSP], c->dst.bytes);
+ register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->dst.bytes);
return 0;
}
@@ -1043,26 +1125,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
switch (c->modrm_reg) {
case 0 ... 1: /* test */
- /*
- * Special case in Grp3: test has an immediate
- * source operand.
- */
- c->src.type = OP_IMM;
- c->src.ptr = (unsigned long *)c->eip;
- c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- if (c->src.bytes == 8)
- c->src.bytes = 4;
- switch (c->src.bytes) {
- case 1:
- c->src.val = insn_fetch(s8, 1, c->eip);
- break;
- case 2:
- c->src.val = insn_fetch(s16, 2, c->eip);
- break;
- case 4:
- c->src.val = insn_fetch(s32, 4, c->eip);
- break;
- }
emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags);
break;
case 2: /* not */
@@ -1076,7 +1138,6 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
rc = X86EMUL_UNHANDLEABLE;
break;
}
-done:
return rc;
}
@@ -1084,7 +1145,6 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
- int rc;
switch (c->modrm_reg) {
case 0: /* inc */
@@ -1094,36 +1154,11 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
emulate_1op("dec", c->dst, ctxt->eflags);
break;
case 4: /* jmp abs */
- if (c->b == 0xff)
- c->eip = c->dst.val;
- else {
- DPRINTF("Cannot emulate %02x\n", c->b);
- return X86EMUL_UNHANDLEABLE;
- }
+ c->eip = c->src.val;
break;
case 6: /* push */
-
- /* 64-bit mode: PUSH always pushes a 64-bit operand. */
-
- if (ctxt->mode == X86EMUL_MODE_PROT64) {
- c->dst.bytes = 8;
- rc = ops->read_std((unsigned long)c->dst.ptr,
- &c->dst.val, 8, ctxt->vcpu);
- if (rc != 0)
- return rc;
- }
- register_address_increment(c->regs[VCPU_REGS_RSP],
- -c->dst.bytes);
- rc = ops->write_emulated(register_address(ctxt->ss_base,
- c->regs[VCPU_REGS_RSP]), &c->dst.val,
- c->dst.bytes, ctxt->vcpu);
- if (rc != 0)
- return rc;
- c->dst.type = OP_NONE;
+ emulate_push(ctxt);
break;
- default:
- DPRINTF("Cannot emulate %02x\n", c->b);
- return X86EMUL_UNHANDLEABLE;
}
return 0;
}
@@ -1361,19 +1396,19 @@ special_insn:
c->dst.type = OP_MEM;
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
- register_address_increment(c->regs[VCPU_REGS_RSP],
+ register_address_increment(c, &c->regs[VCPU_REGS_RSP],
-c->op_bytes);
c->dst.ptr = (void *) register_address(
- ctxt->ss_base, c->regs[VCPU_REGS_RSP]);
+ c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]);
break;
case 0x58 ... 0x5f: /* pop reg */
pop_instruction:
- if ((rc = ops->read_std(register_address(ctxt->ss_base,
+ if ((rc = ops->read_std(register_address(c, ctxt->ss_base,
c->regs[VCPU_REGS_RSP]), c->dst.ptr,
c->op_bytes, ctxt->vcpu)) != 0)
goto done;
- register_address_increment(c->regs[VCPU_REGS_RSP],
+ register_address_increment(c, &c->regs[VCPU_REGS_RSP],
c->op_bytes);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
@@ -1393,9 +1428,9 @@ special_insn:
1,
(c->d & ByteOp) ? 1 : c->op_bytes,
c->rep_prefix ?
- address_mask(c->regs[VCPU_REGS_RCX]) : 1,
+ address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
(ctxt->eflags & EFLG_DF),
- register_address(ctxt->es_base,
+ register_address(c, ctxt->es_base,
c->regs[VCPU_REGS_RDI]),
c->rep_prefix,
c->regs[VCPU_REGS_RDX]) == 0) {
@@ -1409,9 +1444,9 @@ special_insn:
0,
(c->d & ByteOp) ? 1 : c->op_bytes,
c->rep_prefix ?
- address_mask(c->regs[VCPU_REGS_RCX]) : 1,
+ address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
(ctxt->eflags & EFLG_DF),
- register_address(c->override_base ?
+ register_address(c, c->override_base ?
*c->override_base :
ctxt->ds_base,
c->regs[VCPU_REGS_RSI]),
@@ -1425,7 +1460,7 @@ special_insn:
int rel = insn_fetch(s8, 1, c->eip);
if (test_cc(c->b, ctxt->eflags))
- JMP_REL(rel);
+ jmp_rel(c, rel);
break;
}
case 0x80 ... 0x83: /* Grp1 */
@@ -1477,7 +1512,7 @@ special_insn:
case 0x88 ... 0x8b: /* mov */
goto mov;
case 0x8d: /* lea r16/r32, m */
- c->dst.val = c->modrm_val;
+ c->dst.val = c->modrm_ea;
break;
case 0x8f: /* pop (sole member of Grp1a) */
rc = emulate_grp1a(ctxt, ops);
@@ -1501,27 +1536,27 @@ special_insn:
case 0xa4 ... 0xa5: /* movs */
c->dst.type = OP_MEM;
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)register_address(
+ c->dst.ptr = (unsigned long *)register_address(c,
ctxt->es_base,
c->regs[VCPU_REGS_RDI]);
- if ((rc = ops->read_emulated(register_address(
+ if ((rc = ops->read_emulated(register_address(c,
c->override_base ? *c->override_base :
ctxt->ds_base,
c->regs[VCPU_REGS_RSI]),
&c->dst.val,
c->dst.bytes, ctxt->vcpu)) != 0)
goto done;
- register_address_increment(c->regs[VCPU_REGS_RSI],
+ register_address_increment(c, &c->regs[VCPU_REGS_RSI],
(ctxt->eflags & EFLG_DF) ? -c->dst.bytes
: c->dst.bytes);
- register_address_increment(c->regs[VCPU_REGS_RDI],
+ register_address_increment(c, &c->regs[VCPU_REGS_RDI],
(ctxt->eflags & EFLG_DF) ? -c->dst.bytes
: c->dst.bytes);
break;
case 0xa6 ... 0xa7: /* cmps */
c->src.type = OP_NONE; /* Disable writeback. */
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->src.ptr = (unsigned long *)register_address(
+ c->src.ptr = (unsigned long *)register_address(c,
c->override_base ? *c->override_base :
ctxt->ds_base,
c->regs[VCPU_REGS_RSI]);
@@ -1533,7 +1568,7 @@ special_insn:
c->dst.type = OP_NONE; /* Disable writeback. */
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)register_address(
+ c->dst.ptr = (unsigned long *)register_address(c,
ctxt->es_base,
c->regs[VCPU_REGS_RDI]);
if ((rc = ops->read_emulated((unsigned long)c->dst.ptr,
@@ -1546,10 +1581,10 @@ special_insn:
emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
- register_address_increment(c->regs[VCPU_REGS_RSI],
+ register_address_increment(c, &c->regs[VCPU_REGS_RSI],
(ctxt->eflags & EFLG_DF) ? -c->src.bytes
: c->src.bytes);
- register_address_increment(c->regs[VCPU_REGS_RDI],
+ register_address_increment(c, &c->regs[VCPU_REGS_RDI],
(ctxt->eflags & EFLG_DF) ? -c->dst.bytes
: c->dst.bytes);
@@ -1557,11 +1592,11 @@ special_insn:
case 0xaa ... 0xab: /* stos */
c->dst.type = OP_MEM;
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
- c->dst.ptr = (unsigned long *)register_address(
+ c->dst.ptr = (unsigned long *)register_address(c,
ctxt->es_base,
c->regs[VCPU_REGS_RDI]);
c->dst.val = c->regs[VCPU_REGS_RAX];
- register_address_increment(c->regs[VCPU_REGS_RDI],
+ register_address_increment(c, &c->regs[VCPU_REGS_RDI],
(ctxt->eflags & EFLG_DF) ? -c->dst.bytes
: c->dst.bytes);
break;
@@ -1569,7 +1604,7 @@ special_insn:
c->dst.type = OP_REG;
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
- if ((rc = ops->read_emulated(register_address(
+ if ((rc = ops->read_emulated(register_address(c,
c->override_base ? *c->override_base :
ctxt->ds_base,
c->regs[VCPU_REGS_RSI]),
@@ -1577,7 +1612,7 @@ special_insn:
c->dst.bytes,
ctxt->vcpu)) != 0)
goto done;
- register_address_increment(c->regs[VCPU_REGS_RSI],
+ register_address_increment(c, &c->regs[VCPU_REGS_RSI],
(ctxt->eflags & EFLG_DF) ? -c->dst.bytes
: c->dst.bytes);
break;
@@ -1616,14 +1651,14 @@ special_insn:
goto cannot_emulate;
}
c->src.val = (unsigned long) c->eip;
- JMP_REL(rel);
+ jmp_rel(c, rel);
c->op_bytes = c->ad_bytes;
emulate_push(ctxt);
break;
}
case 0xe9: /* jmp rel */
case 0xeb: /* jmp rel short */
- JMP_REL(c->src.val);
+ jmp_rel(c, c->src.val);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xf4: /* hlt */
@@ -1690,6 +1725,8 @@ twobyte_insn:
goto done;
kvm_emulate_hypercall(ctxt->vcpu);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
break;
case 2: /* lgdt */
rc = read_descriptor(ctxt, ops, c->src.ptr,
@@ -1697,6 +1734,8 @@ twobyte_insn:
if (rc)
goto done;
realmode_lgdt(ctxt->vcpu, size, address);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
break;
case 3: /* lidt/vmmcall */
if (c->modrm_mod == 3 && c->modrm_rm == 1) {
@@ -1712,27 +1751,25 @@ twobyte_insn:
goto done;
realmode_lidt(ctxt->vcpu, size, address);
}
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
break;
case 4: /* smsw */
- if (c->modrm_mod != 3)
- goto cannot_emulate;
- *(u16 *)&c->regs[c->modrm_rm]
- = realmode_get_cr(ctxt->vcpu, 0);
+ c->dst.bytes = 2;
+ c->dst.val = realmode_get_cr(ctxt->vcpu, 0);
break;
case 6: /* lmsw */
- if (c->modrm_mod != 3)
- goto cannot_emulate;
- realmode_lmsw(ctxt->vcpu, (u16)c->modrm_val,
- &ctxt->eflags);
+ realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
+ &ctxt->eflags);
break;
case 7: /* invlpg*/
emulate_invlpg(ctxt->vcpu, memop);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
break;
default:
goto cannot_emulate;
}
- /* Disable writeback. */
- c->dst.type = OP_NONE;
break;
case 0x06:
emulate_clts(ctxt->vcpu);
@@ -1823,7 +1860,7 @@ twobyte_insn:
goto cannot_emulate;
}
if (test_cc(c->b, ctxt->eflags))
- JMP_REL(rel);
+ jmp_rel(c, rel);
c->dst.type = OP_NONE;
break;
}
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 25df1c1989fe..76f60f52a885 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -11,7 +11,7 @@ lib-y += memcpy_$(BITS).o
ifeq ($(CONFIG_X86_32),y)
lib-y += checksum_32.o
lib-y += strstr_32.o
- lib-y += bitops_32.o semaphore_32.o string_32.o
+ lib-y += semaphore_32.o string_32.o
lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
else
@@ -21,7 +21,6 @@ else
lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
lib-y += thunk_64.o clear_page_64.o copy_page_64.o
- lib-y += bitops_64.o
lib-y += memmove_64.o memset_64.o
lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o
endif
diff --git a/arch/x86/lib/bitops_32.c b/arch/x86/lib/bitops_32.c
deleted file mode 100644
index b65440459859..000000000000
--- a/arch/x86/lib/bitops_32.c
+++ /dev/null
@@ -1,70 +0,0 @@
-#include <linux/bitops.h>
-#include <linux/module.h>
-
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-int find_next_bit(const unsigned long *addr, int size, int offset)
-{
- const unsigned long *p = addr + (offset >> 5);
- int set = 0, bit = offset & 31, res;
-
- if (bit) {
- /*
- * Look for nonzero in the first 32 bits:
- */
- __asm__("bsfl %1,%0\n\t"
- "jne 1f\n\t"
- "movl $32, %0\n"
- "1:"
- : "=r" (set)
- : "r" (*p >> bit));
- if (set < (32 - bit))
- return set + offset;
- set = 32 - bit;
- p++;
- }
- /*
- * No set bit yet, search remaining full words for a bit
- */
- res = find_first_bit (p, size - 32 * (p - addr));
- return (offset + set + res);
-}
-EXPORT_SYMBOL(find_next_bit);
-
-/**
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-int find_next_zero_bit(const unsigned long *addr, int size, int offset)
-{
- const unsigned long *p = addr + (offset >> 5);
- int set = 0, bit = offset & 31, res;
-
- if (bit) {
- /*
- * Look for zero in the first 32 bits.
- */
- __asm__("bsfl %1,%0\n\t"
- "jne 1f\n\t"
- "movl $32, %0\n"
- "1:"
- : "=r" (set)
- : "r" (~(*p >> bit)));
- if (set < (32 - bit))
- return set + offset;
- set = 32 - bit;
- p++;
- }
- /*
- * No zero yet, search remaining full bytes for a zero
- */
- res = find_first_zero_bit(p, size - 32 * (p - addr));
- return (offset + set + res);
-}
-EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/x86/lib/bitops_64.c b/arch/x86/lib/bitops_64.c
deleted file mode 100644
index 0e8f491e6ccc..000000000000
--- a/arch/x86/lib/bitops_64.c
+++ /dev/null
@@ -1,175 +0,0 @@
-#include <linux/bitops.h>
-
-#undef find_first_zero_bit
-#undef find_next_zero_bit
-#undef find_first_bit
-#undef find_next_bit
-
-static inline long
-__find_first_zero_bit(const unsigned long * addr, unsigned long size)
-{
- long d0, d1, d2;
- long res;
-
- /*
- * We must test the size in words, not in bits, because
- * otherwise incoming sizes in the range -63..-1 will not run
- * any scasq instructions, and then the flags used by the je
- * instruction will have whatever random value was in place
- * before. Nobody should call us like that, but
- * find_next_zero_bit() does when offset and size are at the
- * same word and it fails to find a zero itself.
- */
- size += 63;
- size >>= 6;
- if (!size)
- return 0;
- asm volatile(
- " repe; scasq\n"
- " je 1f\n"
- " xorq -8(%%rdi),%%rax\n"
- " subq $8,%%rdi\n"
- " bsfq %%rax,%%rdx\n"
- "1: subq %[addr],%%rdi\n"
- " shlq $3,%%rdi\n"
- " addq %%rdi,%%rdx"
- :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
- :"0" (0ULL), "1" (size), "2" (addr), "3" (-1ULL),
- [addr] "S" (addr) : "memory");
- /*
- * Any register would do for [addr] above, but GCC tends to
- * prefer rbx over rsi, even though rsi is readily available
- * and doesn't have to be saved.
- */
- return res;
-}
-
-/**
- * find_first_zero_bit - find the first zero bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first zero bit, not the number of the byte
- * containing a bit.
- */
-long find_first_zero_bit(const unsigned long * addr, unsigned long size)
-{
- return __find_first_zero_bit (addr, size);
-}
-
-/**
- * find_next_zero_bit - find the next zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-long find_next_zero_bit (const unsigned long * addr, long size, long offset)
-{
- const unsigned long * p = addr + (offset >> 6);
- unsigned long set = 0;
- unsigned long res, bit = offset&63;
-
- if (bit) {
- /*
- * Look for zero in first word
- */
- asm("bsfq %1,%0\n\t"
- "cmoveq %2,%0"
- : "=r" (set)
- : "r" (~(*p >> bit)), "r"(64L));
- if (set < (64 - bit))
- return set + offset;
- set = 64 - bit;
- p++;
- }
- /*
- * No zero yet, search remaining full words for a zero
- */
- res = __find_first_zero_bit (p, size - 64 * (p - addr));
-
- return (offset + set + res);
-}
-
-static inline long
-__find_first_bit(const unsigned long * addr, unsigned long size)
-{
- long d0, d1;
- long res;
-
- /*
- * We must test the size in words, not in bits, because
- * otherwise incoming sizes in the range -63..-1 will not run
- * any scasq instructions, and then the flags used by the jz
- * instruction will have whatever random value was in place
- * before. Nobody should call us like that, but
- * find_next_bit() does when offset and size are at the same
- * word and it fails to find a one itself.
- */
- size += 63;
- size >>= 6;
- if (!size)
- return 0;
- asm volatile(
- " repe; scasq\n"
- " jz 1f\n"
- " subq $8,%%rdi\n"
- " bsfq (%%rdi),%%rax\n"
- "1: subq %[addr],%%rdi\n"
- " shlq $3,%%rdi\n"
- " addq %%rdi,%%rax"
- :"=a" (res), "=&c" (d0), "=&D" (d1)
- :"0" (0ULL), "1" (size), "2" (addr),
- [addr] "r" (addr) : "memory");
- return res;
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-long find_first_bit(const unsigned long * addr, unsigned long size)
-{
- return __find_first_bit(addr,size);
-}
-
-/**
- * find_next_bit - find the first set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-long find_next_bit(const unsigned long * addr, long size, long offset)
-{
- const unsigned long * p = addr + (offset >> 6);
- unsigned long set = 0, bit = offset & 63, res;
-
- if (bit) {
- /*
- * Look for nonzero in the first 64 bits:
- */
- asm("bsfq %1,%0\n\t"
- "cmoveq %2,%0\n\t"
- : "=r" (set)
- : "r" (*p >> bit), "r" (64L));
- if (set < (64 - bit))
- return set + offset;
- set = 64 - bit;
- p++;
- }
- /*
- * No set bit yet, search remaining full words for a bit
- */
- res = __find_first_bit (p, size - 64 * (p - addr));
- return (offset + set + res);
-}
-
-#include <linux/module.h>
-
-EXPORT_SYMBOL(find_next_bit);
-EXPORT_SYMBOL(find_first_bit);
-EXPORT_SYMBOL(find_first_zero_bit);
-EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c
index d05722121d24..8acbf0cdf1a5 100644
--- a/arch/x86/mach-voyager/voyager_smp.c
+++ b/arch/x86/mach-voyager/voyager_smp.c
@@ -113,7 +113,7 @@ static inline void send_QIC_CPI(__u32 cpuset, __u8 cpi)
for_each_online_cpu(cpu) {
if (cpuset & (1 << cpu)) {
#ifdef VOYAGER_DEBUG
- if (!cpu_isset(cpu, cpu_online_map))
+ if (!cpu_online(cpu))
VDEBUG(("CPU%d sending cpi %d to CPU%d not in "
"cpu_online_map\n",
hard_smp_processor_id(), cpi, cpu));
@@ -543,8 +543,8 @@ static void __init do_boot_cpu(__u8 cpu)
hijack_source.idt.Offset, stack_start.sp));
/* init lowmem identity mapping */
- clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY));
flush_tlb_all();
if (quad_boot) {
@@ -683,9 +683,9 @@ void __init smp_boot_cpus(void)
* Code added from smpboot.c */
{
unsigned long bogosum = 0;
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_isset(i, cpu_online_map))
- bogosum += cpu_data(i).loops_per_jiffy;
+
+ for_each_online_cpu(i)
+ bogosum += cpu_data(i).loops_per_jiffy;
printk(KERN_INFO "Total of %d processors activated "
"(%lu.%02lu BogoMIPS).\n",
cpucount + 1, bogosum / (500000 / HZ),
@@ -1838,7 +1838,7 @@ static int __cpuinit voyager_cpu_up(unsigned int cpu)
return -EIO;
/* Unleash the CPU! */
cpu_set(cpu, smp_commenced_mask);
- while (!cpu_isset(cpu, cpu_online_map))
+ while (!cpu_online(cpu))
mb();
return 0;
}
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 20941d2954e2..b7b3e4c7cfc9 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -1,5 +1,5 @@
obj-y := init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
- pat.o
+ pat.o pgtable.o
obj-$(CONFIG_X86_32) += pgtable_32.o
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 9ec62da85fd7..de236e419cb5 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -71,7 +71,7 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- paravirt_alloc_pd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
+ paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
pud = pud_offset(pgd, 0);
BUG_ON(pmd_table != pmd_offset(pud, 0));
@@ -100,7 +100,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
(pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
}
- paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT);
+ paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT);
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
BUG_ON(page_table != pte_offset_kernel(pmd, 0));
}
@@ -227,6 +227,25 @@ static inline int page_kills_ppro(unsigned long pagenr)
return 0;
}
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+ * is valid. The argument is a physical page number.
+ *
+ *
+ * On x86, access has to be given to the first megabyte of ram because that area
+ * contains bios code and data regions used by X and dosemu and similar apps.
+ * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+ * mmio resources as well as potential bios/acpi data regions.
+ */
+int devmem_is_allowed(unsigned long pagenr)
+{
+ if (pagenr <= 256)
+ return 1;
+ if (!page_is_ram(pagenr))
+ return 1;
+ return 0;
+}
+
#ifdef CONFIG_HIGHMEM
pte_t *kmap_pte;
pgprot_t kmap_prot;
@@ -268,47 +287,17 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
pkmap_page_table = pte;
}
-static void __meminit free_new_highpage(struct page *page)
-{
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
-}
-
void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro)
{
if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) {
ClearPageReserved(page);
- free_new_highpage(page);
+ init_page_count(page);
+ __free_page(page);
+ totalhigh_pages++;
} else
SetPageReserved(page);
}
-static int __meminit
-add_one_highpage_hotplug(struct page *page, unsigned long pfn)
-{
- free_new_highpage(page);
- totalram_pages++;
-#ifdef CONFIG_FLATMEM
- max_mapnr = max(pfn, max_mapnr);
-#endif
- num_physpages++;
-
- return 0;
-}
-
-/*
- * Not currently handling the NUMA case.
- * Assuming single node and all memory that
- * has been added dynamically that would be
- * onlined here is in HIGHMEM.
- */
-void __meminit online_page(struct page *page)
-{
- ClearPageReserved(page);
- add_one_highpage_hotplug(page, page_to_pfn(page));
-}
-
#ifndef CONFIG_NUMA
static void __init set_highmem_pages_init(int bad_ppro)
{
@@ -365,7 +354,7 @@ void __init native_pagetable_setup_start(pgd_t *base)
pte_clear(NULL, va, pte);
}
- paravirt_alloc_pd(&init_mm, __pa(base) >> PAGE_SHIFT);
+ paravirt_alloc_pmd(&init_mm, __pa(base) >> PAGE_SHIFT);
}
void __init native_pagetable_setup_done(pgd_t *base)
@@ -457,7 +446,7 @@ void zap_low_mappings(void)
* Note that "pgd_clear()" doesn't do it for
* us, because pgd_clear() is a no-op on i386.
*/
- for (i = 0; i < USER_PTRS_PER_PGD; i++) {
+ for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) {
#ifdef CONFIG_X86_PAE
set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
#else
@@ -547,9 +536,9 @@ void __init paging_init(void)
/*
* Test if the WP bit works in supervisor mode. It isn't supported on 386's
- * and also on some strange 486's (NexGen etc.). All 586+'s are OK. This
- * used to involve black magic jumps to work around some nasty CPU bugs,
- * but fortunately the switch to using exceptions got rid of all that.
+ * and also on some strange 486's. All 586+'s are OK. This used to involve
+ * black magic jumps to work around some nasty CPU bugs, but fortunately the
+ * switch to using exceptions got rid of all that.
*/
static void __init test_wp_bit(void)
{
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 1ff7906a9a4d..32ba13b0f818 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -135,7 +135,7 @@ static __init void *spp_getpage(void)
return ptr;
}
-static __init void
+static void
set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
{
pgd_t *pgd;
@@ -173,7 +173,7 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
pte = pte_offset_kernel(pmd, vaddr);
- if (!pte_none(*pte) &&
+ 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);
@@ -214,8 +214,7 @@ void __init cleanup_highmap(void)
}
/* NOTE: this is meant to be run only at boot */
-void __init
-__set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
+void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
{
unsigned long address = __fix_to_virt(idx);
@@ -621,15 +620,6 @@ void __init paging_init(void)
/*
* Memory hotplug specific functions
*/
-void online_page(struct page *page)
-{
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalram_pages++;
- num_physpages++;
-}
-
#ifdef CONFIG_MEMORY_HOTPLUG
/*
* Memory is added always to NORMAL zone. This means you will never get
@@ -664,6 +654,26 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif /* CONFIG_MEMORY_HOTPLUG */
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+ * is valid. The argument is a physical page number.
+ *
+ *
+ * On x86, access has to be given to the first megabyte of ram because that area
+ * contains bios code and data regions used by X and dosemu and similar apps.
+ * Access has to be given to non-kernel-ram areas as well, these contain the PCI
+ * mmio resources as well as potential bios/acpi data regions.
+ */
+int devmem_is_allowed(unsigned long pagenr)
+{
+ if (pagenr <= 256)
+ return 1;
+ if (!page_is_ram(pagenr))
+ return 1;
+ return 0;
+}
+
+
static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel,
kcore_modules, kcore_vsyscall;
@@ -791,7 +801,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
{
#ifdef CONFIG_NUMA
- int nid = phys_to_nid(phys);
+ int nid, next_nid;
#endif
unsigned long pfn = phys >> PAGE_SHIFT;
@@ -810,10 +820,16 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
/* Should check here against the e820 map to avoid double free */
#ifdef CONFIG_NUMA
- reserve_bootmem_node(NODE_DATA(nid), phys, len, BOOTMEM_DEFAULT);
+ nid = phys_to_nid(phys);
+ next_nid = phys_to_nid(phys + len - 1);
+ if (nid == next_nid)
+ reserve_bootmem_node(NODE_DATA(nid), phys, len, BOOTMEM_DEFAULT);
+ else
+ reserve_bootmem(phys, len, BOOTMEM_DEFAULT);
#else
reserve_bootmem(phys, len, BOOTMEM_DEFAULT);
#endif
+
if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
dma_reserve += len / PAGE_SIZE;
set_dma_reserve(dma_reserve);
@@ -907,6 +923,10 @@ const char *arch_vma_name(struct vm_area_struct *vma)
/*
* Initialise the sparsemem vmemmap using huge-pages at the PMD level.
*/
+static long __meminitdata addr_start, addr_end;
+static void __meminitdata *p_start, *p_end;
+static int __meminitdata node_start;
+
int __meminit
vmemmap_populate(struct page *start_page, unsigned long size, int node)
{
@@ -941,12 +961,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
PAGE_KERNEL_LARGE);
set_pmd(pmd, __pmd(pte_val(entry)));
- printk(KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n",
- addr, addr + PMD_SIZE - 1, p, node);
+ /* check to see if we have contiguous blocks */
+ if (p_end != p || node_start != node) {
+ if (p_start)
+ printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n",
+ addr_start, addr_end-1, p_start, p_end-1, node_start);
+ addr_start = addr;
+ node_start = node;
+ p_start = p;
+ }
+ addr_end = addr + PMD_SIZE;
+ p_end = p + PMD_SIZE;
} else {
vmemmap_verify((pte_t *)pmd, node, addr, next);
}
}
return 0;
}
+
+void __meminit vmemmap_populate_print_last(void)
+{
+ if (p_start) {
+ printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n",
+ addr_start, addr_end-1, p_start, p_end-1, node_start);
+ p_start = NULL;
+ p_end = NULL;
+ node_start = 0;
+ }
+}
#endif
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 3a4baf95e24d..804de18abcc2 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -117,8 +117,8 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*/
-static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
- unsigned long prot_val)
+static void __iomem *__ioremap_caller(resource_size_t phys_addr,
+ unsigned long size, unsigned long prot_val, void *caller)
{
unsigned long pfn, offset, vaddr;
resource_size_t last_addr;
@@ -212,7 +212,7 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
/*
* Ok, go for it..
*/
- area = get_vm_area(size, VM_IOREMAP);
+ area = get_vm_area_caller(size, VM_IOREMAP, caller);
if (!area)
return NULL;
area->phys_addr = phys_addr;
@@ -255,7 +255,8 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
*/
void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
{
- return __ioremap(phys_addr, size, _PAGE_CACHE_UC);
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_UC,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_nocache);
@@ -272,7 +273,8 @@ EXPORT_SYMBOL(ioremap_nocache);
void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size)
{
if (pat_wc_enabled)
- return __ioremap(phys_addr, size, _PAGE_CACHE_WC);
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WC,
+ __builtin_return_address(0));
else
return ioremap_nocache(phys_addr, size);
}
@@ -280,7 +282,8 @@ EXPORT_SYMBOL(ioremap_wc);
void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size)
{
- return __ioremap(phys_addr, size, _PAGE_CACHE_WB);
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WB,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_cache);
@@ -336,6 +339,35 @@ void iounmap(volatile void __iomem *addr)
}
EXPORT_SYMBOL(iounmap);
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+void *xlate_dev_mem_ptr(unsigned long phys)
+{
+ void *addr;
+ unsigned long start = phys & PAGE_MASK;
+
+ /* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
+ if (page_is_ram(start >> PAGE_SHIFT))
+ return __va(phys);
+
+ addr = (void *)ioremap(start, PAGE_SIZE);
+ if (addr)
+ addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
+
+ return addr;
+}
+
+void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+{
+ if (page_is_ram(phys >> PAGE_SHIFT))
+ return;
+
+ iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK));
+ return;
+}
+
#ifdef CONFIG_X86_32
int __initdata early_ioremap_debug;
@@ -407,7 +439,7 @@ void __init early_ioremap_clear(void)
pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
pmd_clear(pmd);
- paravirt_release_pt(__pa(bm_pte) >> PAGE_SHIFT);
+ paravirt_release_pte(__pa(bm_pte) >> PAGE_SHIFT);
__flush_tlb_all();
}
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 9a6892200b27..c5066d519e5d 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -196,6 +196,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
unsigned long bootmap_start, nodedata_phys;
void *bootmap;
const int pgdat_size = round_up(sizeof(pg_data_t), PAGE_SIZE);
+ int nid;
start = round_up(start, ZONE_ALIGN);
@@ -218,9 +219,19 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
NODE_DATA(nodeid)->node_start_pfn = start_pfn;
NODE_DATA(nodeid)->node_spanned_pages = end_pfn - start_pfn;
- /* Find a place for the bootmem map */
+ /*
+ * Find a place for the bootmem map
+ * nodedata_phys could be on other nodes by alloc_bootmem,
+ * so need to sure bootmap_start not to be small, otherwise
+ * early_node_mem will get that with find_e820_area instead
+ * of alloc_bootmem, that could clash with reserved range
+ */
bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
- bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
+ nid = phys_to_nid(nodedata_phys);
+ if (nid == nodeid)
+ bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
+ else
+ bootmap_start = round_up(start, PAGE_SIZE);
/*
* SMP_CAHCE_BYTES could be enough, but init_bootmem_node like
* to use that to align to PAGE_SIZE
@@ -245,10 +256,29 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
free_bootmem_with_active_regions(nodeid, end);
- reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size,
- BOOTMEM_DEFAULT);
- reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start,
- bootmap_pages<<PAGE_SHIFT, BOOTMEM_DEFAULT);
+ /*
+ * convert early reserve to bootmem reserve earlier
+ * otherwise early_node_mem could use early reserved mem
+ * on previous node
+ */
+ early_res_to_bootmem(start, end);
+
+ /*
+ * in some case early_node_mem could use alloc_bootmem
+ * to get range on other node, don't reserve that again
+ */
+ if (nid != nodeid)
+ printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nodeid, nid);
+ else
+ reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys,
+ pgdat_size, BOOTMEM_DEFAULT);
+ nid = phys_to_nid(bootmap_start);
+ if (nid != nodeid)
+ printk(KERN_INFO " bootmap(%d) on node %d\n", nodeid, nid);
+ else
+ reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start,
+ bootmap_pages<<PAGE_SHIFT, BOOTMEM_DEFAULT);
+
#ifdef CONFIG_ACPI_NUMA
srat_reserve_add_area(nodeid);
#endif
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index c29ebd037254..bd5e05c654dc 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -483,9 +483,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
goto out_unlock;
pbase = (pte_t *)page_address(base);
-#ifdef CONFIG_X86_32
- paravirt_alloc_pt(&init_mm, page_to_pfn(base));
-#endif
+ paravirt_alloc_pte(&init_mm, page_to_pfn(base));
ref_prot = pte_pgprot(pte_clrhuge(*kpte));
#ifdef CONFIG_X86_64
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 72c0f6097402..277446cd30b6 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -11,16 +11,19 @@
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/fs.h>
+#include <linux/bootmem.h>
#include <asm/msr.h>
#include <asm/tlbflush.h>
#include <asm/processor.h>
+#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/pat.h>
#include <asm/e820.h>
#include <asm/cacheflush.h>
#include <asm/fcntl.h>
#include <asm/mtrr.h>
+#include <asm/io.h>
int pat_wc_enabled = 1;
@@ -190,6 +193,21 @@ static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot,
return 0;
}
+/*
+ * req_type typically has one of the:
+ * - _PAGE_CACHE_WB
+ * - _PAGE_CACHE_WC
+ * - _PAGE_CACHE_UC_MINUS
+ * - _PAGE_CACHE_UC
+ *
+ * req_type will have a special case value '-1', when requester want to inherit
+ * the memory type from mtrr (if WB), existing PAT, defaulting to UC_MINUS.
+ *
+ * If ret_type is NULL, function will return an error if it cannot reserve the
+ * region with req_type. If ret_type is non-null, function will return
+ * available type in ret_type in case of no error. In case of any error
+ * it will return a negative return value.
+ */
int reserve_memtype(u64 start, u64 end, unsigned long req_type,
unsigned long *ret_type)
{
@@ -200,9 +218,14 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
/* Only track when pat_wc_enabled */
if (!pat_wc_enabled) {
- if (ret_type)
- *ret_type = req_type;
-
+ /* This is identical to page table setting without PAT */
+ if (ret_type) {
+ if (req_type == -1) {
+ *ret_type = _PAGE_CACHE_WB;
+ } else {
+ *ret_type = req_type;
+ }
+ }
return 0;
}
@@ -214,8 +237,29 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
return 0;
}
- req_type &= _PAGE_CACHE_MASK;
- err = pat_x_mtrr_type(start, end, req_type, &actual_type);
+ if (req_type == -1) {
+ /*
+ * Special case where caller wants to inherit from mtrr or
+ * existing pat mapping, defaulting to UC_MINUS in case of
+ * no match.
+ */
+ u8 mtrr_type = mtrr_type_lookup(start, end);
+ if (mtrr_type == 0xFE) { /* MTRR match error */
+ err = -1;
+ }
+
+ if (mtrr_type == MTRR_TYPE_WRBACK) {
+ req_type = _PAGE_CACHE_WB;
+ actual_type = _PAGE_CACHE_WB;
+ } else {
+ req_type = _PAGE_CACHE_UC_MINUS;
+ actual_type = _PAGE_CACHE_UC_MINUS;
+ }
+ } else {
+ req_type &= _PAGE_CACHE_MASK;
+ err = pat_x_mtrr_type(start, end, req_type, &actual_type);
+ }
+
if (err) {
if (ret_type)
*ret_type = actual_type;
@@ -241,7 +285,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
struct memtype *saved_ptr;
if (parse->start >= end) {
- printk("New Entry\n");
+ pr_debug("New Entry\n");
list_add(&new_entry->nd, parse->nd.prev);
new_entry = NULL;
break;
@@ -291,7 +335,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
break;
}
- printk("Overlap at 0x%Lx-0x%Lx\n",
+ pr_debug("Overlap at 0x%Lx-0x%Lx\n",
saved_ptr->start, saved_ptr->end);
/* No conflict. Go ahead and add this new entry */
list_add(&new_entry->nd, saved_ptr->nd.prev);
@@ -343,8 +387,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
break;
}
- printk("Overlap at 0x%Lx-0x%Lx\n",
- saved_ptr->start, saved_ptr->end);
+ pr_debug(KERN_INFO "Overlap at 0x%Lx-0x%Lx\n",
+ saved_ptr->start, saved_ptr->end);
/* No conflict. Go ahead and add this new entry */
list_add(&new_entry->nd, &saved_ptr->nd);
new_entry = NULL;
@@ -353,7 +397,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
}
if (err) {
- printk(
+ printk(KERN_INFO
"reserve_memtype failed 0x%Lx-0x%Lx, track %s, req %s\n",
start, end, cattr_name(new_entry->type),
cattr_name(req_type));
@@ -365,16 +409,16 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
if (new_entry) {
/* No conflict. Not yet added to the list. Add to the tail */
list_add_tail(&new_entry->nd, &memtype_list);
- printk("New Entry\n");
- }
+ pr_debug("New Entry\n");
+ }
if (ret_type) {
- printk(
+ pr_debug(
"reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n",
start, end, cattr_name(actual_type),
cattr_name(req_type), cattr_name(*ret_type));
} else {
- printk(
+ pr_debug(
"reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s\n",
start, end, cattr_name(actual_type),
cattr_name(req_type));
@@ -411,11 +455,142 @@ int free_memtype(u64 start, u64 end)
spin_unlock(&memtype_lock);
if (err) {
- printk(KERN_DEBUG "%s:%d freeing invalid memtype %Lx-%Lx\n",
+ printk(KERN_INFO "%s:%d freeing invalid memtype %Lx-%Lx\n",
current->comm, current->pid, start, end);
}
- printk( "free_memtype request 0x%Lx-0x%Lx\n", start, end);
+ pr_debug("free_memtype request 0x%Lx-0x%Lx\n", start, end);
return err;
}
+
+/*
+ * /dev/mem mmap interface. The memtype used for mapping varies:
+ * - Use UC for mappings with O_SYNC flag
+ * - Without O_SYNC flag, if there is any conflict in reserve_memtype,
+ * inherit the memtype from existing mapping.
+ * - Else use UC_MINUS memtype (for backward compatibility with existing
+ * X drivers.
+ */
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot)
+{
+ return vma_prot;
+}
+
+#ifdef CONFIG_NONPROMISC_DEVMEM
+/* This check is done in drivers/char/mem.c in case of NONPROMISC_DEVMEM*/
+static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+{
+ return 1;
+}
+#else
+static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+{
+ u64 from = ((u64)pfn) << PAGE_SHIFT;
+ u64 to = from + size;
+ u64 cursor = from;
+
+ while (cursor < to) {
+ if (!devmem_is_allowed(pfn)) {
+ printk(KERN_INFO
+ "Program %s tried to access /dev/mem between %Lx->%Lx.\n",
+ current->comm, from, to);
+ return 0;
+ }
+ cursor += PAGE_SIZE;
+ pfn++;
+ }
+ return 1;
+}
+#endif /* CONFIG_NONPROMISC_DEVMEM */
+
+int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t *vma_prot)
+{
+ u64 offset = ((u64) pfn) << PAGE_SHIFT;
+ unsigned long flags = _PAGE_CACHE_UC_MINUS;
+ int retval;
+
+ if (!range_is_allowed(pfn, size))
+ return 0;
+
+ if (file->f_flags & O_SYNC) {
+ flags = _PAGE_CACHE_UC;
+ }
+
+#ifdef CONFIG_X86_32
+ /*
+ * On the PPro and successors, the MTRRs are used to set
+ * memory types for physical addresses outside main memory,
+ * so blindly setting UC or PWT on those pages is wrong.
+ * For Pentiums and earlier, the surround logic should disable
+ * caching for the high addresses through the KEN pin, but
+ * we maintain the tradition of paranoia in this code.
+ */
+ if (!pat_wc_enabled &&
+ ! ( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) ||
+ test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) ||
+ test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ||
+ test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability)) &&
+ (pfn << PAGE_SHIFT) >= __pa(high_memory)) {
+ flags = _PAGE_CACHE_UC;
+ }
+#endif
+
+ /*
+ * With O_SYNC, we can only take UC mapping. Fail if we cannot.
+ * Without O_SYNC, we want to get
+ * - WB for WB-able memory and no other conflicting mappings
+ * - UC_MINUS for non-WB-able memory with no other conflicting mappings
+ * - Inherit from confliting mappings otherwise
+ */
+ if (flags != _PAGE_CACHE_UC_MINUS) {
+ retval = reserve_memtype(offset, offset + size, flags, NULL);
+ } else {
+ retval = reserve_memtype(offset, offset + size, -1, &flags);
+ }
+
+ if (retval < 0)
+ return 0;
+
+ if (pfn <= max_pfn_mapped &&
+ ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) {
+ free_memtype(offset, offset + size);
+ printk(KERN_INFO
+ "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n",
+ current->comm, current->pid,
+ cattr_name(flags),
+ offset, offset + size);
+ return 0;
+ }
+
+ *vma_prot = __pgprot((pgprot_val(*vma_prot) & ~_PAGE_CACHE_MASK) |
+ flags);
+ return 1;
+}
+
+void map_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
+{
+ u64 addr = (u64)pfn << PAGE_SHIFT;
+ unsigned long flags;
+ unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
+
+ reserve_memtype(addr, addr + size, want_flags, &flags);
+ if (flags != want_flags) {
+ printk(KERN_INFO
+ "%s:%d /dev/mem expected mapping type %s for %Lx-%Lx, got %s\n",
+ current->comm, current->pid,
+ cattr_name(want_flags),
+ addr, addr + size,
+ cattr_name(flags));
+ }
+}
+
+void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
+{
+ u64 addr = (u64)pfn << PAGE_SHIFT;
+
+ free_memtype(addr, addr + size);
+}
+
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
new file mode 100644
index 000000000000..50159764f694
--- /dev/null
+++ b/arch/x86/mm/pgtable.c
@@ -0,0 +1,276 @@
+#include <linux/mm.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/tlb.h>
+
+pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+ return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+}
+
+pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ struct page *pte;
+
+#ifdef CONFIG_HIGHPTE
+ pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0);
+#else
+ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
+#endif
+ if (pte)
+ pgtable_page_ctor(pte);
+ return pte;
+}
+
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
+{
+ pgtable_page_dtor(pte);
+ paravirt_release_pte(page_to_pfn(pte));
+ tlb_remove_page(tlb, pte);
+}
+
+#if PAGETABLE_LEVELS > 2
+void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+{
+ paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT);
+ tlb_remove_page(tlb, virt_to_page(pmd));
+}
+
+#if PAGETABLE_LEVELS > 3
+void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud)
+{
+ paravirt_release_pud(__pa(pud) >> PAGE_SHIFT);
+ tlb_remove_page(tlb, virt_to_page(pud));
+}
+#endif /* PAGETABLE_LEVELS > 3 */
+#endif /* PAGETABLE_LEVELS > 2 */
+
+static inline void pgd_list_add(pgd_t *pgd)
+{
+ struct page *page = virt_to_page(pgd);
+
+ list_add(&page->lru, &pgd_list);
+}
+
+static inline void pgd_list_del(pgd_t *pgd)
+{
+ struct page *page = virt_to_page(pgd);
+
+ list_del(&page->lru);
+}
+
+#define UNSHARED_PTRS_PER_PGD \
+ (SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD)
+
+static void pgd_ctor(void *p)
+{
+ pgd_t *pgd = p;
+ unsigned long flags;
+
+ /* Clear usermode parts of PGD */
+ memset(pgd, 0, KERNEL_PGD_BOUNDARY*sizeof(pgd_t));
+
+ spin_lock_irqsave(&pgd_lock, flags);
+
+ /* If the pgd points to a shared pagetable level (either the
+ ptes in non-PAE, or shared PMD in PAE), then just copy the
+ references from swapper_pg_dir. */
+ if (PAGETABLE_LEVELS == 2 ||
+ (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD) ||
+ PAGETABLE_LEVELS == 4) {
+ clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
+ swapper_pg_dir + KERNEL_PGD_BOUNDARY,
+ KERNEL_PGD_PTRS);
+ paravirt_alloc_pmd_clone(__pa(pgd) >> PAGE_SHIFT,
+ __pa(swapper_pg_dir) >> PAGE_SHIFT,
+ KERNEL_PGD_BOUNDARY,
+ KERNEL_PGD_PTRS);
+ }
+
+ /* list required to sync kernel mapping updates */
+ if (!SHARED_KERNEL_PMD)
+ pgd_list_add(pgd);
+
+ spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
+static void pgd_dtor(void *pgd)
+{
+ unsigned long flags; /* can be called from interrupt context */
+
+ if (SHARED_KERNEL_PMD)
+ return;
+
+ spin_lock_irqsave(&pgd_lock, flags);
+ pgd_list_del(pgd);
+ spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
+/*
+ * List of all pgd's needed for non-PAE so it can invalidate entries
+ * in both cached and uncached pgd's; not needed for PAE since the
+ * kernel pmd is shared. If PAE were not to share the pmd a similar
+ * tactic would be needed. This is essentially codepath-based locking
+ * against pageattr.c; it is the unique case in which a valid change
+ * of kernel pagetables can't be lazily synchronized by vmalloc faults.
+ * vmalloc faults work because attached pagetables are never freed.
+ * -- wli
+ */
+
+#ifdef CONFIG_X86_PAE
+/*
+ * Mop up any pmd pages which may still be attached to the pgd.
+ * Normally they will be freed by munmap/exit_mmap, but any pmd we
+ * preallocate which never got a corresponding vma will need to be
+ * freed manually.
+ */
+static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
+{
+ int i;
+
+ for(i = 0; i < UNSHARED_PTRS_PER_PGD; i++) {
+ pgd_t pgd = pgdp[i];
+
+ if (pgd_val(pgd) != 0) {
+ pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd);
+
+ pgdp[i] = native_make_pgd(0);
+
+ paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT);
+ pmd_free(mm, pmd);
+ }
+ }
+}
+
+/*
+ * In PAE mode, we need to do a cr3 reload (=tlb flush) when
+ * updating the top-level pagetable entries to guarantee the
+ * processor notices the update. Since this is expensive, and
+ * all 4 top-level entries are used almost immediately in a
+ * new process's life, we just pre-populate them here.
+ *
+ * Also, if we're in a paravirt environment where the kernel pmd is
+ * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate
+ * and initialize the kernel pmds here.
+ */
+static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
+{
+ pud_t *pud;
+ unsigned long addr;
+ int i;
+
+ pud = pud_offset(pgd, 0);
+ for (addr = i = 0; i < UNSHARED_PTRS_PER_PGD;
+ i++, pud++, addr += PUD_SIZE) {
+ pmd_t *pmd = pmd_alloc_one(mm, addr);
+
+ if (!pmd) {
+ pgd_mop_up_pmds(mm, pgd);
+ return 0;
+ }
+
+ if (i >= KERNEL_PGD_BOUNDARY)
+ memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]),
+ sizeof(pmd_t) * PTRS_PER_PMD);
+
+ pud_populate(mm, pud, pmd);
+ }
+
+ return 1;
+}
+
+void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
+{
+ paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT);
+
+ /* Note: almost everything apart from _PAGE_PRESENT is
+ reserved at the pmd (PDPT) level. */
+ set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
+
+ /*
+ * According to Intel App note "TLBs, Paging-Structure Caches,
+ * and Their Invalidation", April 2007, document 317080-001,
+ * section 8.1: in PAE mode we explicitly have to flush the
+ * TLB via cr3 if the top-level pgd is changed...
+ */
+ if (mm == current->active_mm)
+ write_cr3(read_cr3());
+}
+#else /* !CONFIG_X86_PAE */
+/* No need to prepopulate any pagetable entries in non-PAE modes. */
+static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
+{
+ return 1;
+}
+
+static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgd)
+{
+}
+#endif /* CONFIG_X86_PAE */
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+
+ /* so that alloc_pmd can use it */
+ mm->pgd = pgd;
+ if (pgd)
+ pgd_ctor(pgd);
+
+ if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
+ pgd_dtor(pgd);
+ free_page((unsigned long)pgd);
+ pgd = NULL;
+ }
+
+ return pgd;
+}
+
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+ pgd_mop_up_pmds(mm, pgd);
+ pgd_dtor(pgd);
+ free_page((unsigned long)pgd);
+}
+
+int ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty)
+{
+ int changed = !pte_same(*ptep, entry);
+
+ if (changed && dirty) {
+ *ptep = entry;
+ pte_update_defer(vma->vm_mm, address, ptep);
+ flush_tlb_page(vma, address);
+ }
+
+ return changed;
+}
+
+int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ int ret = 0;
+
+ if (pte_young(*ptep))
+ ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,
+ &ptep->pte);
+
+ if (ret)
+ pte_update(vma->vm_mm, addr, ptep);
+
+ return ret;
+}
+
+int ptep_clear_flush_young(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)
+{
+ int young;
+
+ young = ptep_test_and_clear_young(vma, address, ptep);
+ if (young)
+ flush_tlb_page(vma, address);
+
+ return young;
+}
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index 6fb9e7c6893f..9ee007be9142 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -173,210 +173,6 @@ void reserve_top_address(unsigned long reserve)
__VMALLOC_RESERVE += reserve;
}
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
- return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
-}
-
-pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- struct page *pte;
-
-#ifdef CONFIG_HIGHPTE
- pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0);
-#else
- pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
-#endif
- if (pte)
- pgtable_page_ctor(pte);
- return pte;
-}
-
-/*
- * List of all pgd's needed for non-PAE so it can invalidate entries
- * in both cached and uncached pgd's; not needed for PAE since the
- * kernel pmd is shared. If PAE were not to share the pmd a similar
- * tactic would be needed. This is essentially codepath-based locking
- * against pageattr.c; it is the unique case in which a valid change
- * of kernel pagetables can't be lazily synchronized by vmalloc faults.
- * vmalloc faults work because attached pagetables are never freed.
- * -- wli
- */
-static inline void pgd_list_add(pgd_t *pgd)
-{
- struct page *page = virt_to_page(pgd);
-
- list_add(&page->lru, &pgd_list);
-}
-
-static inline void pgd_list_del(pgd_t *pgd)
-{
- struct page *page = virt_to_page(pgd);
-
- list_del(&page->lru);
-}
-
-#define UNSHARED_PTRS_PER_PGD \
- (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
-
-static void pgd_ctor(void *p)
-{
- pgd_t *pgd = p;
- unsigned long flags;
-
- /* Clear usermode parts of PGD */
- memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
-
- spin_lock_irqsave(&pgd_lock, flags);
-
- /* If the pgd points to a shared pagetable level (either the
- ptes in non-PAE, or shared PMD in PAE), then just copy the
- references from swapper_pg_dir. */
- if (PAGETABLE_LEVELS == 2 ||
- (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) {
- clone_pgd_range(pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
- KERNEL_PGD_PTRS);
- paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
- __pa(swapper_pg_dir) >> PAGE_SHIFT,
- USER_PTRS_PER_PGD,
- KERNEL_PGD_PTRS);
- }
-
- /* list required to sync kernel mapping updates */
- if (!SHARED_KERNEL_PMD)
- pgd_list_add(pgd);
-
- spin_unlock_irqrestore(&pgd_lock, flags);
-}
-
-static void pgd_dtor(void *pgd)
-{
- unsigned long flags; /* can be called from interrupt context */
-
- if (SHARED_KERNEL_PMD)
- return;
-
- spin_lock_irqsave(&pgd_lock, flags);
- pgd_list_del(pgd);
- spin_unlock_irqrestore(&pgd_lock, flags);
-}
-
-#ifdef CONFIG_X86_PAE
-/*
- * Mop up any pmd pages which may still be attached to the pgd.
- * Normally they will be freed by munmap/exit_mmap, but any pmd we
- * preallocate which never got a corresponding vma will need to be
- * freed manually.
- */
-static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
-{
- int i;
-
- for(i = 0; i < UNSHARED_PTRS_PER_PGD; i++) {
- pgd_t pgd = pgdp[i];
-
- if (pgd_val(pgd) != 0) {
- pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd);
-
- pgdp[i] = native_make_pgd(0);
-
- paravirt_release_pd(pgd_val(pgd) >> PAGE_SHIFT);
- pmd_free(mm, pmd);
- }
- }
-}
-
-/*
- * In PAE mode, we need to do a cr3 reload (=tlb flush) when
- * updating the top-level pagetable entries to guarantee the
- * processor notices the update. Since this is expensive, and
- * all 4 top-level entries are used almost immediately in a
- * new process's life, we just pre-populate them here.
- *
- * Also, if we're in a paravirt environment where the kernel pmd is
- * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate
- * and initialize the kernel pmds here.
- */
-static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
-{
- pud_t *pud;
- unsigned long addr;
- int i;
-
- pud = pud_offset(pgd, 0);
- for (addr = i = 0; i < UNSHARED_PTRS_PER_PGD;
- i++, pud++, addr += PUD_SIZE) {
- pmd_t *pmd = pmd_alloc_one(mm, addr);
-
- if (!pmd) {
- pgd_mop_up_pmds(mm, pgd);
- return 0;
- }
-
- if (i >= USER_PTRS_PER_PGD)
- memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]),
- sizeof(pmd_t) * PTRS_PER_PMD);
-
- pud_populate(mm, pud, pmd);
- }
-
- return 1;
-}
-#else /* !CONFIG_X86_PAE */
-/* No need to prepopulate any pagetable entries in non-PAE modes. */
-static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
-{
- return 1;
-}
-
-static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
-{
-}
-#endif /* CONFIG_X86_PAE */
-
-pgd_t *pgd_alloc(struct mm_struct *mm)
-{
- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
-
- /* so that alloc_pd can use it */
- mm->pgd = pgd;
- if (pgd)
- pgd_ctor(pgd);
-
- if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
- pgd_dtor(pgd);
- free_page((unsigned long)pgd);
- pgd = NULL;
- }
-
- return pgd;
-}
-
-void pgd_free(struct mm_struct *mm, pgd_t *pgd)
-{
- pgd_mop_up_pmds(mm, pgd);
- pgd_dtor(pgd);
- free_page((unsigned long)pgd);
-}
-
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
-{
- pgtable_page_dtor(pte);
- paravirt_release_pt(page_to_pfn(pte));
- tlb_remove_page(tlb, pte);
-}
-
-#ifdef CONFIG_X86_PAE
-
-void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
-{
- paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
- tlb_remove_page(tlb, virt_to_page(pmd));
-}
-
-#endif
-
int pmd_bad(pmd_t pmd)
{
WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd));
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S
index 4b1620a1529e..1d3aa6b87181 100644
--- a/arch/x86/vdso/vdso.S
+++ b/arch/x86/vdso/vdso.S
@@ -1,2 +1,10 @@
- .section ".vdso","a"
+#include <linux/init.h>
+
+__INITDATA
+
+ .globl vdso_start, vdso_end
+vdso_start:
.incbin "arch/x86/vdso/vdso.so"
+vdso_end:
+
+__FINIT
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 4d5f2649bee4..2e641be2737e 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -6,7 +6,7 @@ config XEN
bool "Xen guest support"
select PARAVIRT
depends on X86_32
- depends on X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES && !(X86_VISWS || X86_VOYAGER)
+ depends on X86_CMPXCHG && X86_TSC && !(X86_VISWS || X86_VOYAGER)
help
This is the Linux Xen port. Enabling this will allow the
kernel to boot in a paravirtualized environment under the
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 343df246bd3e..3d8df981d5fd 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -1,4 +1,4 @@
-obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \
- events.o time.o manage.o xen-asm.o
+obj-y := enlighten.o setup.o multicalls.o mmu.o \
+ time.o manage.o xen-asm.o grant-table.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index c0388220cf97..c8a56e457d61 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -155,7 +155,8 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
if (*ax == 1)
maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
(1 << X86_FEATURE_ACPI) | /* disable ACPI */
- (1 << X86_FEATURE_SEP) | /* disable SEP */
+ (1 << X86_FEATURE_MCE) | /* disable MCE */
+ (1 << X86_FEATURE_MCA) | /* disable MCA */
(1 << X86_FEATURE_ACC)); /* thermal monitoring */
asm(XEN_EMULATE_PREFIX "cpuid"
@@ -531,26 +532,37 @@ static void xen_apic_write(unsigned long reg, u32 val)
static void xen_flush_tlb(void)
{
struct mmuext_op *op;
- struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+ struct multicall_space mcs;
+
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*op));
op = mcs.args;
op->cmd = MMUEXT_TLB_FLUSH_LOCAL;
MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ preempt_enable();
}
static void xen_flush_tlb_single(unsigned long addr)
{
struct mmuext_op *op;
- struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+ struct multicall_space mcs;
+
+ preempt_disable();
+ mcs = xen_mc_entry(sizeof(*op));
op = mcs.args;
op->cmd = MMUEXT_INVLPG_LOCAL;
op->arg1.linear_addr = addr & PAGE_MASK;
MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ preempt_enable();
}
static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
@@ -655,15 +667,17 @@ static void xen_write_cr3(unsigned long cr3)
/* Early in boot, while setting up the initial pagetable, assume
everything is pinned. */
-static __init void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
+static __init void xen_alloc_pte_init(struct mm_struct *mm, u32 pfn)
{
+#ifdef CONFIG_FLATMEM
BUG_ON(mem_map); /* should only be used early */
+#endif
make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
}
-/* Early release_pt assumes that all pts are pinned, since there's
+/* Early release_pte assumes that all pts are pinned, since there's
only init_mm and anything attached to that is pinned. */
-static void xen_release_pt_init(u32 pfn)
+static void xen_release_pte_init(u32 pfn)
{
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
}
@@ -697,12 +711,12 @@ static void xen_alloc_ptpage(struct mm_struct *mm, u32 pfn, unsigned level)
}
}
-static void xen_alloc_pt(struct mm_struct *mm, u32 pfn)
+static void xen_alloc_pte(struct mm_struct *mm, u32 pfn)
{
xen_alloc_ptpage(mm, pfn, PT_PTE);
}
-static void xen_alloc_pd(struct mm_struct *mm, u32 pfn)
+static void xen_alloc_pmd(struct mm_struct *mm, u32 pfn)
{
xen_alloc_ptpage(mm, pfn, PT_PMD);
}
@@ -722,12 +736,12 @@ static void xen_release_ptpage(u32 pfn, unsigned level)
}
}
-static void xen_release_pt(u32 pfn)
+static void xen_release_pte(u32 pfn)
{
xen_release_ptpage(pfn, PT_PTE);
}
-static void xen_release_pd(u32 pfn)
+static void xen_release_pmd(u32 pfn)
{
xen_release_ptpage(pfn, PT_PMD);
}
@@ -849,10 +863,10 @@ static __init void xen_pagetable_setup_done(pgd_t *base)
{
/* This will work as long as patching hasn't happened yet
(which it hasn't) */
- pv_mmu_ops.alloc_pt = xen_alloc_pt;
- pv_mmu_ops.alloc_pd = xen_alloc_pd;
- pv_mmu_ops.release_pt = xen_release_pt;
- pv_mmu_ops.release_pd = xen_release_pd;
+ pv_mmu_ops.alloc_pte = xen_alloc_pte;
+ pv_mmu_ops.alloc_pmd = xen_alloc_pmd;
+ pv_mmu_ops.release_pte = xen_release_pte;
+ pv_mmu_ops.release_pmd = xen_release_pmd;
pv_mmu_ops.set_pte = xen_set_pte;
setup_shared_info();
@@ -994,7 +1008,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
.read_pmc = native_read_pmc,
.iret = xen_iret,
- .irq_enable_syscall_ret = NULL, /* never called */
+ .irq_enable_syscall_ret = xen_sysexit,
.load_tr_desc = paravirt_nop,
.set_ldt = xen_set_ldt,
@@ -1059,11 +1073,11 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
.pte_update = paravirt_nop,
.pte_update_defer = paravirt_nop,
- .alloc_pt = xen_alloc_pt_init,
- .release_pt = xen_release_pt_init,
- .alloc_pd = xen_alloc_pt_init,
- .alloc_pd_clone = paravirt_nop,
- .release_pd = xen_release_pt_init,
+ .alloc_pte = xen_alloc_pte_init,
+ .release_pte = xen_release_pte_init,
+ .alloc_pmd = xen_alloc_pte_init,
+ .alloc_pmd_clone = paravirt_nop,
+ .release_pmd = xen_release_pte_init,
#ifdef CONFIG_HIGHPTE
.kmap_atomic_pte = xen_kmap_atomic_pte,
diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c
new file mode 100644
index 000000000000..49ba9b5224d1
--- /dev/null
+++ b/arch/x86/xen/grant-table.c
@@ -0,0 +1,91 @@
+/******************************************************************************
+ * grant_table.c
+ * x86 specific part
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A Fraser
+ * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan. Split out x86 specific part.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+
+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
+ unsigned long addr, void *data)
+{
+ unsigned long **frames = (unsigned long **)data;
+
+ set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
+ (*frames)++;
+ return 0;
+}
+
+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
+ unsigned long addr, void *data)
+{
+
+ set_pte_at(&init_mm, addr, pte, __pte(0));
+ return 0;
+}
+
+int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
+ unsigned long max_nr_gframes,
+ struct grant_entry **__shared)
+{
+ int rc;
+ struct grant_entry *shared = *__shared;
+
+ if (shared == NULL) {
+ struct vm_struct *area =
+ xen_alloc_vm_area(PAGE_SIZE * max_nr_gframes);
+ BUG_ON(area == NULL);
+ shared = area->addr;
+ *__shared = shared;
+ }
+
+ rc = apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_gframes,
+ map_pte_fn, &frames);
+ return rc;
+}
+
+void arch_gnttab_unmap_shared(struct grant_entry *shared,
+ unsigned long nr_gframes)
+{
+ apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL);
+}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 2a054ef2a3da..126766d43aea 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -156,6 +156,10 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pteval)
{
+ /* updates to init_mm may be done without lock */
+ if (mm == &init_mm)
+ preempt_disable();
+
if (mm == current->mm || mm == &init_mm) {
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
struct multicall_space mcs;
@@ -163,14 +167,61 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
xen_mc_issue(PARAVIRT_LAZY_MMU);
- return;
+ goto out;
} else
if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
- return;
+ goto out;
}
xen_set_pte(ptep, pteval);
+
+out:
+ if (mm == &init_mm)
+ preempt_enable();
+}
+
+pteval_t xen_pte_val(pte_t pte)
+{
+ pteval_t ret = pte.pte;
+
+ if (ret & _PAGE_PRESENT)
+ ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
+
+ return ret;
+}
+
+pgdval_t xen_pgd_val(pgd_t pgd)
+{
+ pgdval_t ret = pgd.pgd;
+ if (ret & _PAGE_PRESENT)
+ ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
+ return ret;
+}
+
+pte_t xen_make_pte(pteval_t pte)
+{
+ if (pte & _PAGE_PRESENT) {
+ pte = phys_to_machine(XPADDR(pte)).maddr;
+ pte &= ~(_PAGE_PCD | _PAGE_PWT);
+ }
+
+ return (pte_t){ .pte = pte };
}
+pgd_t xen_make_pgd(pgdval_t pgd)
+{
+ if (pgd & _PAGE_PRESENT)
+ pgd = phys_to_machine(XPADDR(pgd)).maddr;
+
+ return (pgd_t){ pgd };
+}
+
+pmdval_t xen_pmd_val(pmd_t pmd)
+{
+ pmdval_t ret = native_pmd_val(pmd);
+ if (ret & _PAGE_PRESENT)
+ ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
+ return ret;
+}
#ifdef CONFIG_X86_PAE
void xen_set_pud(pud_t *ptr, pud_t val)
{
@@ -214,100 +265,18 @@ void xen_pmd_clear(pmd_t *pmdp)
xen_set_pmd(pmdp, __pmd(0));
}
-unsigned long long xen_pte_val(pte_t pte)
+pmd_t xen_make_pmd(pmdval_t pmd)
{
- unsigned long long ret = 0;
-
- if (pte.pte_low) {
- ret = ((unsigned long long)pte.pte_high << 32) | pte.pte_low;
- ret = machine_to_phys(XMADDR(ret)).paddr | 1;
- }
-
- return ret;
-}
-
-unsigned long long xen_pmd_val(pmd_t pmd)
-{
- unsigned long long ret = pmd.pmd;
- if (ret)
- ret = machine_to_phys(XMADDR(ret)).paddr | 1;
- return ret;
-}
-
-unsigned long long xen_pgd_val(pgd_t pgd)
-{
- unsigned long long ret = pgd.pgd;
- if (ret)
- ret = machine_to_phys(XMADDR(ret)).paddr | 1;
- return ret;
-}
-
-pte_t xen_make_pte(unsigned long long pte)
-{
- if (pte & _PAGE_PRESENT) {
- pte = phys_to_machine(XPADDR(pte)).maddr;
- pte &= ~(_PAGE_PCD | _PAGE_PWT);
- }
-
- return (pte_t){ .pte = pte };
-}
-
-pmd_t xen_make_pmd(unsigned long long pmd)
-{
- if (pmd & 1)
+ if (pmd & _PAGE_PRESENT)
pmd = phys_to_machine(XPADDR(pmd)).maddr;
- return (pmd_t){ pmd };
-}
-
-pgd_t xen_make_pgd(unsigned long long pgd)
-{
- if (pgd & _PAGE_PRESENT)
- pgd = phys_to_machine(XPADDR(pgd)).maddr;
-
- return (pgd_t){ pgd };
+ return native_make_pmd(pmd);
}
#else /* !PAE */
void xen_set_pte(pte_t *ptep, pte_t pte)
{
*ptep = pte;
}
-
-unsigned long xen_pte_val(pte_t pte)
-{
- unsigned long ret = pte.pte_low;
-
- if (ret & _PAGE_PRESENT)
- ret = machine_to_phys(XMADDR(ret)).paddr;
-
- return ret;
-}
-
-unsigned long xen_pgd_val(pgd_t pgd)
-{
- unsigned long ret = pgd.pgd;
- if (ret)
- ret = machine_to_phys(XMADDR(ret)).paddr | 1;
- return ret;
-}
-
-pte_t xen_make_pte(unsigned long pte)
-{
- if (pte & _PAGE_PRESENT) {
- pte = phys_to_machine(XPADDR(pte)).maddr;
- pte &= ~(_PAGE_PCD | _PAGE_PWT);
- }
-
- return (pte_t){ pte };
-}
-
-pgd_t xen_make_pgd(unsigned long pgd)
-{
- if (pgd & _PAGE_PRESENT)
- pgd = phys_to_machine(XPADDR(pgd)).maddr;
-
- return (pgd_t){ pgd };
-}
#endif /* CONFIG_X86_PAE */
/*
@@ -418,7 +387,7 @@ static void xen_do_pin(unsigned level, unsigned long pfn)
static int pin_page(struct page *page, enum pt_level level)
{
- unsigned pgfl = test_and_set_bit(PG_pinned, &page->flags);
+ unsigned pgfl = TestSetPagePinned(page);
int flush;
if (pgfl)
@@ -499,7 +468,7 @@ void __init xen_mark_init_mm_pinned(void)
static int unpin_page(struct page *page, enum pt_level level)
{
- unsigned pgfl = test_and_clear_bit(PG_pinned, &page->flags);
+ unsigned pgfl = TestClearPagePinned(page);
if (pgfl && !PageHighMem(page)) {
void *pt = lowmem_page_address(page);
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 2341492bf7a0..82517e4a752a 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -16,6 +16,7 @@
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
+#include <xen/interface/callback.h>
#include <xen/interface/physdev.h>
#include <xen/features.h>
@@ -68,6 +69,24 @@ static void __init fiddle_vdso(void)
*mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
}
+void xen_enable_sysenter(void)
+{
+ int cpu = smp_processor_id();
+ extern void xen_sysenter_target(void);
+ /* Mask events on entry, even though they get enabled immediately */
+ static struct callback_register sysenter = {
+ .type = CALLBACKTYPE_sysenter,
+ .address = { __KERNEL_CS, (unsigned long)xen_sysenter_target },
+ .flags = CALLBACKF_mask_events,
+ };
+
+ if (!boot_cpu_has(X86_FEATURE_SEP) ||
+ HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) != 0) {
+ clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SEP);
+ clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP);
+ }
+}
+
void __init xen_arch_setup(void)
{
struct physdev_set_iopl set_iopl;
@@ -82,6 +101,8 @@ void __init xen_arch_setup(void)
HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback,
__KERNEL_CS, (unsigned long)xen_failsafe_callback);
+ xen_enable_sysenter();
+
set_iopl.iopl = 1;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
if (rc != 0)
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index e340ff92f6b6..94e69000f982 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -36,8 +36,9 @@
#include "mmu.h"
static cpumask_t xen_cpu_initialized_map;
-static DEFINE_PER_CPU(int, resched_irq);
-static DEFINE_PER_CPU(int, callfunc_irq);
+static DEFINE_PER_CPU(int, resched_irq) = -1;
+static DEFINE_PER_CPU(int, callfunc_irq) = -1;
+static DEFINE_PER_CPU(int, debug_irq) = -1;
/*
* Structure and data for smp_call_function(). This is designed to minimise
@@ -72,6 +73,7 @@ static __cpuinit void cpu_bringup_and_idle(void)
int cpu = smp_processor_id();
cpu_init();
+ xen_enable_sysenter();
preempt_disable();
per_cpu(cpu_state, cpu) = CPU_ONLINE;
@@ -88,9 +90,7 @@ static __cpuinit void cpu_bringup_and_idle(void)
static int xen_smp_intr_init(unsigned int cpu)
{
int rc;
- const char *resched_name, *callfunc_name;
-
- per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
+ const char *resched_name, *callfunc_name, *debug_name;
resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
@@ -114,6 +114,14 @@ static int xen_smp_intr_init(unsigned int cpu)
goto fail;
per_cpu(callfunc_irq, cpu) = rc;
+ debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
+ rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
+ IRQF_DISABLED | IRQF_PERCPU | IRQF_NOBALANCING,
+ debug_name, NULL);
+ if (rc < 0)
+ goto fail;
+ per_cpu(debug_irq, cpu) = rc;
+
return 0;
fail:
@@ -121,6 +129,8 @@ static int xen_smp_intr_init(unsigned int cpu)
unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
if (per_cpu(callfunc_irq, cpu) >= 0)
unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+ if (per_cpu(debug_irq, cpu) >= 0)
+ unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
return rc;
}
@@ -183,7 +193,7 @@ void __init xen_smp_prepare_cpus(unsigned int max_cpus)
/* Restrict the possible_map according to max_cpus. */
while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
- for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
+ for (cpu = NR_CPUS - 1; !cpu_possible(cpu); cpu--)
continue;
cpu_clear(cpu, cpu_possible_map);
}
diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S
index fe161ed4b01e..2497a30f41de 100644
--- a/arch/x86/xen/xen-asm.S
+++ b/arch/x86/xen/xen-asm.S
@@ -108,6 +108,20 @@ ENDPATCH(xen_restore_fl_direct)
RELOC(xen_restore_fl_direct, 2b+1)
/*
+ We can't use sysexit directly, because we're not running in ring0.
+ But we can easily fake it up using iret. Assuming xen_sysexit
+ is jumped to with a standard stack frame, we can just strip it
+ back to a standard iret frame and use iret.
+ */
+ENTRY(xen_sysexit)
+ movl PT_EAX(%esp), %eax /* Shouldn't be necessary? */
+ orl $X86_EFLAGS_IF, PT_EFLAGS(%esp)
+ lea PT_EIP(%esp), %esp
+
+ jmp xen_iret
+ENDPROC(xen_sysexit)
+
+/*
This is run where a normal iret would be run, with the same stack setup:
8: eflags
4: cs
@@ -184,8 +198,12 @@ iret_restore_end:
region is OK. */
je xen_hypervisor_callback
- iret
+1: iret
xen_iret_end_crit:
+.section __ex_table,"a"
+ .align 4
+ .long 1b,iret_exc
+.previous
hyper_iret:
/* put this out of line since its very rarely used */
@@ -219,9 +237,7 @@ hyper_iret:
ds } SAVE_ALL state
eax }
: :
- ebx }
- ----------------
- return addr <- esp
+ ebx }<- esp
----------------
In order to deliver the nested exception properly, we need to shift
@@ -236,10 +252,8 @@ hyper_iret:
it's usermode state which we eventually need to restore.
*/
ENTRY(xen_iret_crit_fixup)
- /* offsets +4 for return address */
-
/*
- Paranoia: Make sure we're really coming from userspace.
+ Paranoia: Make sure we're really coming from kernel space.
One could imagine a case where userspace jumps into the
critical range address, but just before the CPU delivers a GP,
it decides to deliver an interrupt instead. Unlikely?
@@ -248,32 +262,32 @@ ENTRY(xen_iret_crit_fixup)
jump instruction itself, not the destination, but some virtual
environments get this wrong.
*/
- movl PT_CS+4(%esp), %ecx
+ movl PT_CS(%esp), %ecx
andl $SEGMENT_RPL_MASK, %ecx
cmpl $USER_RPL, %ecx
je 2f
- lea PT_ORIG_EAX+4(%esp), %esi
- lea PT_EFLAGS+4(%esp), %edi
+ lea PT_ORIG_EAX(%esp), %esi
+ lea PT_EFLAGS(%esp), %edi
/* If eip is before iret_restore_end then stack
hasn't been restored yet. */
cmp $iret_restore_end, %eax
jae 1f
- movl 0+4(%edi),%eax /* copy EAX */
- movl %eax, PT_EAX+4(%esp)
+ movl 0+4(%edi),%eax /* copy EAX (just above top of frame) */
+ movl %eax, PT_EAX(%esp)
lea ESP_OFFSET(%edi),%edi /* move dest up over saved regs */
/* set up the copy */
1: std
- mov $(PT_EIP+4) / 4, %ecx /* copy ret+saved regs up to orig_eax */
+ mov $PT_EIP / 4, %ecx /* saved regs up to orig_eax */
rep movsl
cld
lea 4(%edi),%esp /* point esp to new frame */
-2: ret
+2: jmp xen_do_upcall
/*
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 956a491ea998..f1063ae08037 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -2,6 +2,8 @@
#define XEN_OPS_H
#include <linux/init.h>
+#include <linux/irqreturn.h>
+#include <xen/xen-ops.h>
/* These are code, but not functions. Defined in entry.S */
extern const char xen_hypervisor_callback[];
@@ -9,7 +11,6 @@ extern const char xen_failsafe_callback[];
void xen_copy_trap_info(struct trap_info *traps);
-DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
DECLARE_PER_CPU(unsigned long, xen_cr3);
DECLARE_PER_CPU(unsigned long, xen_current_cr3);
@@ -19,6 +20,7 @@ extern struct shared_info *HYPERVISOR_shared_info;
char * __init xen_memory_setup(void);
void __init xen_arch_setup(void);
void __init xen_init_IRQ(void);
+void xen_enable_sysenter(void);
void xen_setup_timer(int cpu);
void xen_setup_cpu_clockevents(void);
@@ -28,6 +30,8 @@ unsigned long xen_get_wallclock(void);
int xen_set_wallclock(unsigned long time);
unsigned long long xen_sched_clock(void);
+irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
+
bool xen_vcpu_stolen(int vcpu);
void xen_mark_init_mm_pinned(void);
@@ -64,4 +68,6 @@ DECL_ASM(unsigned long, xen_save_fl_direct, void);
DECL_ASM(void, xen_restore_fl_direct, unsigned long);
void xen_iret(void);
+void xen_sysexit(void);
+
#endif /* XEN_OPS_H */
diff --git a/block/bsg.c b/block/bsg.c
index f51172ed27c2..23ea4fd1a66d 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -699,14 +699,26 @@ static struct bsg_device *bsg_alloc_device(void)
return bd;
}
+static void bsg_kref_release_function(struct kref *kref)
+{
+ struct bsg_class_device *bcd =
+ container_of(kref, struct bsg_class_device, ref);
+
+ if (bcd->release)
+ bcd->release(bcd->parent);
+
+ put_device(bcd->parent);
+}
+
static int bsg_put_device(struct bsg_device *bd)
{
- int ret = 0;
- struct device *dev = bd->queue->bsg_dev.dev;
+ int ret = 0, do_free;
+ struct request_queue *q = bd->queue;
mutex_lock(&bsg_mutex);
- if (!atomic_dec_and_test(&bd->ref_count))
+ do_free = atomic_dec_and_test(&bd->ref_count);
+ if (!do_free)
goto out;
dprintk("%s: tearing down\n", bd->name);
@@ -723,12 +735,13 @@ static int bsg_put_device(struct bsg_device *bd)
*/
ret = bsg_complete_all_commands(bd);
- blk_put_queue(bd->queue);
hlist_del(&bd->dev_list);
kfree(bd);
out:
mutex_unlock(&bsg_mutex);
- put_device(dev);
+ kref_put(&q->bsg_dev.ref, bsg_kref_release_function);
+ if (do_free)
+ blk_put_queue(q);
return ret;
}
@@ -796,7 +809,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
mutex_lock(&bsg_mutex);
bcd = idr_find(&bsg_minor_idr, iminor(inode));
if (bcd)
- get_device(bcd->dev);
+ kref_get(&bcd->ref);
mutex_unlock(&bsg_mutex);
if (!bcd)
@@ -808,7 +821,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
bd = bsg_add_device(inode, bcd->queue, file);
if (IS_ERR(bd))
- put_device(bcd->dev);
+ kref_put(&bcd->ref, bsg_kref_release_function);
return bd;
}
@@ -947,14 +960,14 @@ void bsg_unregister_queue(struct request_queue *q)
idr_remove(&bsg_minor_idr, bcd->minor);
sysfs_remove_link(&q->kobj, "bsg");
device_unregister(bcd->class_dev);
- put_device(bcd->dev);
bcd->class_dev = NULL;
+ kref_put(&bcd->ref, bsg_kref_release_function);
mutex_unlock(&bsg_mutex);
}
EXPORT_SYMBOL_GPL(bsg_unregister_queue);
-int bsg_register_queue(struct request_queue *q, struct device *gdev,
- const char *name)
+int bsg_register_queue(struct request_queue *q, struct device *parent,
+ const char *name, void (*release)(struct device *))
{
struct bsg_class_device *bcd;
dev_t dev;
@@ -965,7 +978,7 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
if (name)
devname = name;
else
- devname = gdev->bus_id;
+ devname = parent->bus_id;
/*
* we need a proper transport to send commands, not a stacked device
@@ -996,9 +1009,11 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
bcd->minor = minor;
bcd->queue = q;
- bcd->dev = get_device(gdev);
+ bcd->parent = get_device(parent);
+ bcd->release = release;
+ kref_init(&bcd->ref);
dev = MKDEV(bsg_major, bcd->minor);
- class_dev = device_create(bsg_class, gdev, dev, "%s", devname);
+ class_dev = device_create(bsg_class, parent, dev, "%s", devname);
if (IS_ERR(class_dev)) {
ret = PTR_ERR(class_dev);
goto put_dev;
@@ -1017,7 +1032,7 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
unregister_class_dev:
device_unregister(class_dev);
put_dev:
- put_device(gdev);
+ put_device(parent);
remove_idr:
idr_remove(&bsg_minor_idr, minor);
unlock:
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 3a0e3549739f..80f0ec91e2cf 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -97,4 +97,6 @@ source "drivers/dca/Kconfig"
source "drivers/auxdisplay/Kconfig"
source "drivers/uio/Kconfig"
+
+source "drivers/xen/Kconfig"
endmenu
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b4f5e8542829..c52fca833268 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -140,6 +140,7 @@ config ACPI_VIDEO
tristate "Video"
depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
depends on INPUT
+ select THERMAL
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -151,6 +152,7 @@ config ACPI_VIDEO
config ACPI_FAN
tristate "Fan"
+ select THERMAL
default y
help
This driver adds support for ACPI fan devices, allowing user-mode
@@ -172,6 +174,7 @@ config ACPI_BAY
config ACPI_PROCESSOR
tristate "Processor"
+ select THERMAL
default y
help
This driver installs ACPI as the idle handler for Linux, and uses
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 1fa86811b8ee..d2fc94161848 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -201,6 +201,7 @@ static int is_ejectable_bay(acpi_handle handle)
return 0;
}
+#if 0
/**
* eject_removable_drive - try to eject this drive
* @dev : the device structure of the drive
@@ -225,6 +226,7 @@ int eject_removable_drive(struct device *dev)
return 0;
}
EXPORT_SYMBOL_GPL(eject_removable_drive);
+#endif /* 0 */
static int acpi_bay_add_fs(struct bay *bay)
{
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index f049639bac35..c78078315be9 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,12 +89,16 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
ACPI_FUNCTION_TRACE(ds_create_buffer_field);
- /* Get the name_string argument */
-
+ /*
+ * Get the name_string argument (name of the new buffer_field)
+ */
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
+ /* For create_field, name is the 4th argument */
+
arg = acpi_ps_get_arg(op, 3);
} else {
- /* Create Bit/Byte/Word/Dword field */
+ /* For all other create_xXXField operators, name is the 3rd argument */
arg = acpi_ps_get_arg(op, 2);
}
@@ -107,26 +111,30 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
node = walk_state->deferred_node;
status = AE_OK;
} else {
- /*
- * During the load phase, we want to enter the name of the field into
- * the namespace. During the execute phase (when we evaluate the size
- * operand), we want to lookup the name
- */
- if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
- } else {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
- ACPI_NS_ERROR_IF_FOUND;
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ return_ACPI_STATUS(AE_AML_INTERNAL);
}
- /*
- * Enter the name_string into the namespace
- */
+ /* Creating new namespace node, should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
+ /* Enter the name_string into the namespace */
+
status =
acpi_ns_lookup(walk_state->scope_info,
arg->common.value.string, ACPI_TYPE_ANY,
ACPI_IMODE_LOAD_PASS1, flags, walk_state,
- &(node));
+ &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
return_ACPI_STATUS(status);
@@ -136,13 +144,13 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
/*
* We could put the returned object (Node) on the object stack for later,
* but for now, we will put it in the "op" object that the parser uses,
- * so we can get it again at the end of this scope
+ * so we can get it again at the end of this scope.
*/
op->common.node = node;
/*
* If there is no object attached to the node, this node was just created
- * and we need to create the field object. Otherwise, this was a lookup
+ * and we need to create the field object. Otherwise, this was a lookup
* of an existing node and we don't want to create the field object again.
*/
obj_desc = acpi_ns_get_attached_object(node);
@@ -164,9 +172,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
}
/*
- * Remember location in AML stream of the field unit
- * opcode and operands -- since the buffer and index
- * operands must be evaluated.
+ * Remember location in AML stream of the field unit opcode and operands --
+ * since the buffer and index operands must be evaluated.
*/
second_desc = obj_desc->common.next_object;
second_desc->extra.aml_start = op->named.data;
@@ -261,7 +268,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
case AML_INT_NAMEDFIELD_OP:
- /* Lookup the name */
+ /* Lookup the name, it should already exist */
status = acpi_ns_lookup(walk_state->scope_info,
(char *)&arg->named.name,
@@ -272,20 +279,23 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
status);
- if (status != AE_ALREADY_EXISTS) {
- return_ACPI_STATUS(status);
- }
-
- /* Already exists, ignore error */
+ return_ACPI_STATUS(status);
} else {
arg->common.node = info->field_node;
info->field_bit_length = arg->common.value.size;
- /* Create and initialize an object for the new Field Node */
-
- status = acpi_ex_prep_field_value(info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * If there is no object attached to the node, this node was
+ * just created and we need to create the field object.
+ * Otherwise, this was a lookup of an existing node and we
+ * don't want to create the field object again.
+ */
+ if (!acpi_ns_get_attached_object
+ (info->field_node)) {
+ status = acpi_ex_prep_field_value(info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
@@ -399,9 +409,27 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
union acpi_parse_object *arg = NULL;
struct acpi_namespace_node *node;
u8 type = 0;
+ u32 flags;
ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) {
+
+ /* bank_field Op is deferred, just return OK */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ /*
+ * Get the field_list argument for this opcode. This is the start of the
+ * list of field elements.
+ */
switch (walk_state->opcode) {
case AML_FIELD_OP:
arg = acpi_ps_get_arg(op, 2);
@@ -422,20 +450,33 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ if (!arg) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
+
+ /* Creating new namespace node(s), should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node(s) temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
/*
* Walk the list of entries in the field_list
*/
while (arg) {
-
- /* Ignore OFFSET and ACCESSAS terms here */
-
+ /*
+ * Ignore OFFSET and ACCESSAS terms here; we are only interested in the
+ * field names in order to enter them into the namespace.
+ */
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
status = acpi_ns_lookup(walk_state->scope_info,
- (char *)&arg->named.name,
- type, ACPI_IMODE_LOAD_PASS1,
- ACPI_NS_NO_UPSEARCH |
- ACPI_NS_DONT_OPEN_SCOPE |
- ACPI_NS_ERROR_IF_FOUND,
+ (char *)&arg->named.name, type,
+ ACPI_IMODE_LOAD_PASS1, flags,
walk_state, &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
@@ -452,7 +493,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
arg->common.node = node;
}
- /* Move to next field in the list */
+ /* Get the next field element in the list */
arg = arg->common.next;
}
@@ -466,7 +507,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
*
* PARAMETERS: Op - Op containing the Field definition and args
* region_node - Object for the containing Operation Region
- * ` walk_state - Current method state
+ * walk_state - Current method state
*
* RETURN: Status
*
@@ -513,36 +554,13 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
return_ACPI_STATUS(status);
}
- /* Third arg is the bank_value */
-
- /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
-
+ /*
+ * Third arg is the bank_value
+ * This arg is a term_arg, not a constant
+ * It will be evaluated later, by acpi_ds_eval_bank_field_operands
+ */
arg = arg->common.next;
- /* Currently, only the following constants are supported */
-
- switch (arg->common.aml_opcode) {
- case AML_ZERO_OP:
- info.bank_value = 0;
- break;
-
- case AML_ONE_OP:
- info.bank_value = 1;
- break;
-
- case AML_BYTE_OP:
- case AML_WORD_OP:
- case AML_DWORD_OP:
- case AML_QWORD_OP:
- info.bank_value = (u32) arg->common.value.integer;
- break;
-
- default:
- info.bank_value = 0;
- ACPI_ERROR((AE_INFO,
- "Non-constant BankValue for BankField is not implemented"));
- }
-
/* Fourth arg is the field flags */
arg = arg->common.next;
@@ -553,8 +571,17 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
info.region_node = region_node;
- status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+ /*
+ * Use Info.data_register_node to store bank_field Op
+ * It's safe because data_register_node will never be used when create bank field
+ * We store aml_start and aml_length in the bank_field Op for late evaluation
+ * Used in acpi_ex_prep_field_value(Info)
+ *
+ * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?
+ */
+ info.data_register_node = (struct acpi_namespace_node *)op;
+ status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index af923c388520..610b1ee102b0 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 1cbe61905824..e48a3ea03117 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,6 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
#include <acpi/amlcode.h>
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
@@ -102,7 +101,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
walk_state->opcode,
walk_state->aml_offset,
NULL);
- (void)acpi_ex_enter_interpreter();
+ acpi_ex_enter_interpreter();
}
#ifdef ACPI_DISASSEMBLER
if (ACPI_FAILURE(status)) {
@@ -232,9 +231,9 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
* recursive call.
*/
if (!walk_state ||
- !obj_desc->method.mutex->mutex.owner_thread ||
- (walk_state->thread !=
- obj_desc->method.mutex->mutex.owner_thread)) {
+ !obj_desc->method.mutex->mutex.thread_id ||
+ (walk_state->thread->thread_id !=
+ obj_desc->method.mutex->mutex.thread_id)) {
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
@@ -254,8 +253,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
original_sync_level =
walk_state->thread->current_sync_level;
- obj_desc->method.mutex->mutex.owner_thread =
- walk_state->thread;
+ obj_desc->method.mutex->mutex.thread_id =
+ walk_state->thread->thread_id;
walk_state->thread->current_sync_level =
obj_desc->method.sync_level;
} else {
@@ -535,8 +534,6 @@ void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
struct acpi_walk_state *walk_state)
{
- struct acpi_namespace_node *method_node;
- acpi_status status;
ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
@@ -551,34 +548,26 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
/* Delete all arguments and locals */
acpi_ds_method_data_delete_all(walk_state);
- }
- /*
- * If method is serialized, release the mutex and restore the
- * current sync level for this thread
- */
- if (method_desc->method.mutex) {
+ /*
+ * If method is serialized, release the mutex and restore the
+ * current sync level for this thread
+ */
+ if (method_desc->method.mutex) {
- /* Acquisition Depth handles recursive calls */
+ /* Acquisition Depth handles recursive calls */
- method_desc->method.mutex->mutex.acquisition_depth--;
- if (!method_desc->method.mutex->mutex.acquisition_depth) {
- walk_state->thread->current_sync_level =
- method_desc->method.mutex->mutex.
- original_sync_level;
+ method_desc->method.mutex->mutex.acquisition_depth--;
+ if (!method_desc->method.mutex->mutex.acquisition_depth) {
+ walk_state->thread->current_sync_level =
+ method_desc->method.mutex->mutex.
+ original_sync_level;
- acpi_os_release_mutex(method_desc->method.mutex->mutex.
- os_mutex);
- method_desc->method.mutex->mutex.owner_thread = NULL;
+ acpi_os_release_mutex(method_desc->method.
+ mutex->mutex.os_mutex);
+ method_desc->method.mutex->mutex.thread_id = 0;
+ }
}
- }
-
- if (walk_state) {
- /*
- * Delete any objects created by this method during execution.
- * The method Node is stored in the walk state
- */
- method_node = walk_state->method_node;
/*
* Delete any namespace objects created anywhere within
@@ -620,7 +609,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
*/
if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
&& (!method_desc->method.mutex)) {
- status = acpi_ds_create_method_mutex(method_desc);
+ (void)acpi_ds_create_method_mutex(method_desc);
}
/* No more threads, we can free the owner_id */
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index ba4626e06a5e..13c43eac35db 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 954ac8ce958a..1022e38994c2 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -157,7 +157,9 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
* will remain as named references. This behavior is not described
* in the ACPI spec, but it appears to be an oversight.
*/
- obj_desc = (union acpi_operand_object *)op->common.node;
+ obj_desc =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ op->common.node);
status =
acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
@@ -172,7 +174,19 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
switch (op->common.node->type) {
/*
* For these types, we need the actual node, not the subobject.
- * However, the subobject got an extra reference count above.
+ * However, the subobject did not get an extra reference count above.
+ *
+ * TBD: should ex_resolve_node_to_value be changed to fix this?
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_THERMAL:
+
+ acpi_ut_add_reference(op->common.node->object);
+
+ /*lint -fallthrough */
+ /*
+ * For these types, we need the actual node, not the subobject.
+ * The subobject got an extra reference count in ex_resolve_node_to_value.
*/
case ACPI_TYPE_MUTEX:
case ACPI_TYPE_METHOD:
@@ -180,25 +194,15 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_EVENT:
case ACPI_TYPE_REGION:
- case ACPI_TYPE_DEVICE:
- case ACPI_TYPE_THERMAL:
- obj_desc =
- (union acpi_operand_object *)op->common.
- node;
+ /* We will create a reference object for these types below */
break;
default:
- break;
- }
-
- /*
- * If above resolved to an operand object, we are done. Otherwise,
- * we have a NS node, we must create the package entry as a named
- * reference.
- */
- if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) !=
- ACPI_DESC_TYPE_NAMED) {
+ /*
+ * All other types - the node was resolved to an actual
+ * object, we are done.
+ */
goto exit;
}
}
@@ -223,7 +227,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
exit:
*obj_desc_ptr = obj_desc;
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -369,7 +373,9 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
acpi_status status = AE_OK;
- acpi_native_uint i;
+ unsigned i;
+ u16 index;
+ u16 reference_count;
ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);
@@ -447,13 +453,60 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
package.
elements[i]);
}
+
+ if (*obj_desc_ptr) {
+
+ /* Existing package, get existing reference count */
+
+ reference_count =
+ (*obj_desc_ptr)->common.reference_count;
+ if (reference_count > 1) {
+
+ /* Make new element ref count match original ref count */
+
+ for (index = 0; index < (reference_count - 1);
+ index++) {
+ acpi_ut_add_reference((obj_desc->
+ package.
+ elements[i]));
+ }
+ }
+ }
+
arg = arg->common.next;
}
- if (!arg) {
+ /* Check for match between num_elements and actual length of package_list */
+
+ if (arg) {
+ /*
+ * num_elements was exhausted, but there are remaining elements in the
+ * package_list.
+ *
+ * Note: technically, this is an error, from ACPI spec: "It is an error
+ * for NumElements to be less than the number of elements in the
+ * PackageList". However, for now, we just print an error message and
+ * no exception is returned.
+ */
+ while (arg) {
+
+ /* Find out how many elements there really are */
+
+ i++;
+ arg = arg->common.next;
+ }
+
+ ACPI_ERROR((AE_INFO,
+ "Package List length (%X) larger than NumElements count (%X), truncated\n",
+ i, element_count));
+ } else if (i < element_count) {
+ /*
+ * Arg list (elements) was exhausted, but we did not reach num_elements count.
+ * Note: this is not an error, the package is padded out with NULLs.
+ */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Package List length larger than NumElements count (%X), truncated\n",
- element_count));
+ "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n",
+ i, element_count));
}
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
@@ -721,6 +774,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/* Node was saved in Op */
obj_desc->reference.node = op->common.node;
+ obj_desc->reference.object =
+ op->common.node->object;
}
obj_desc->reference.opcode = opcode;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index f501e083aac7..a818e0ddb996 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsopcode")
@@ -219,6 +220,50 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_get_bank_field_arguments
+ *
+ * PARAMETERS: obj_desc - A valid bank_field object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get bank_field bank_value. This implements the late
+ * evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object *extra_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the AML pointer (method object) and bank_field node */
+
+ extra_desc = acpi_ns_get_secondary_object(obj_desc);
+ node = obj_desc->bank_field.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
+ acpi_ut_get_node_name(node)));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ extra_desc->extra.aml_length,
+ extra_desc->extra.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_get_buffer_arguments
*
* PARAMETERS: obj_desc - A valid Buffer object
@@ -770,7 +815,109 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
obj_desc,
- ACPI_FORMAT_UINT64(obj_desc->region.address),
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
+ obj_desc->region.length));
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_table_region_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from acpi_ds_exec_end_op during data_table_region parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **operand;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ acpi_native_uint table_index;
+ struct acpi_table_header *table;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
+
+ /*
+ * This is where we evaluate the signature_string and oem_iDString
+ * and oem_table_iDString of the data_table_region declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to signature_string op */
+
+ next_op = op->common.value.arg;
+
+ /*
+ * Evaluate/create the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Resolve the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ex_resolve_operands(op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ 1, "after AcpiExResolveOperands");
+
+ operand = &walk_state->operands[0];
+
+ /* Find the ACPI table */
+
+ status = acpi_tb_find_table(operand[0]->string.pointer,
+ operand[1]->string.pointer,
+ operand[2]->string.pointer, &table_index);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ut_remove_reference(operand[0]);
+ acpi_ut_remove_reference(operand[1]);
+ acpi_ut_remove_reference(operand[2]);
+
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->region.address =
+ (acpi_physical_address) ACPI_TO_INTEGER(table);
+ obj_desc->region.length = table->length;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
+ obj_desc,
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
obj_desc->region.length));
/* Now the address and length are valid for this opregion */
@@ -808,6 +955,12 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
/* The first operand (for all of these data objects) is the length */
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ */
+ walk_state->operand_index = walk_state->num_operands;
+
status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -878,6 +1031,106 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_eval_bank_field_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid bank_field Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get bank_field bank_value
+ * Called from acpi_ds_exec_end_op during bank_field parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *operand_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ union acpi_parse_object *arg;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op);
+
+ /*
+ * This is where we evaluate the bank_value field of the
+ * bank_field declaration
+ */
+
+ /* next_op points to the op that holds the Region */
+
+ next_op = op->common.value.arg;
+
+ /* next_op points to the op that holds the Bank Register */
+
+ next_op = next_op->common.next;
+
+ /* next_op points to the op that holds the Bank Value */
+
+ next_op = next_op->common.next;
+
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ *
+ * We use walk_state->Operands[0] to store the evaluated bank_value
+ */
+ walk_state->operand_index = 0;
+
+ status = acpi_ds_create_operand(walk_state, next_op, 0);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ 1, "after AcpiExResolveOperands");
+
+ /*
+ * Get the bank_value operand and save it
+ * (at Top of stack)
+ */
+ operand_desc = walk_state->operands[0];
+
+ /* Arg points to the start Bank Field */
+
+ arg = acpi_ps_get_arg(op, 4);
+ while (arg) {
+
+ /* Ignore OFFSET and ACCESSAS terms here */
+
+ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+ node = arg->common.node;
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->bank_field.value =
+ (u32) operand_desc->integer.value;
+ }
+
+ /* Move to next field in the list */
+
+ arg = arg->common.next;
+ }
+
+ acpi_ut_remove_reference(operand_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_exec_begin_control_op
*
* PARAMETERS: walk_list - The list that owns the walk stack
@@ -1070,8 +1323,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
* is set to anything other than zero!
*/
walk_state->return_desc = walk_state->operands[0];
- } else if ((walk_state->results) &&
- (walk_state->results->results.num_results > 0)) {
+ } else if (walk_state->result_count) {
/* Since we have a real Return(), delete any implicit return */
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 71503c036f7c..b398982f0d8b 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -278,7 +278,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
AML_VAR_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
|| (op->common.parent->common.aml_opcode ==
- AML_INT_EVAL_SUBTREE_OP)) {
+ AML_INT_EVAL_SUBTREE_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)) {
/*
* These opcodes allow term_arg(s) as operands and therefore
* the operands can be method calls. The result is used.
@@ -472,7 +474,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
/* A valid name must be looked up in the namespace */
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
- (arg->common.value.string)) {
+ (arg->common.value.string) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
arg));
@@ -595,7 +598,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
} else {
/* Check for null name case */
- if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
/*
* If the name is null, this means that this is an
* optional result parameter that was not specified
@@ -617,7 +621,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
}
- if (op_info->flags & AML_HAS_RETVAL) {
+ if ((op_info->flags & AML_HAS_RETVAL)
+ || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Argument previously created, already stacked\n"));
@@ -630,9 +635,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
* Use value that was already previously returned
* by the evaluation of this argument
*/
- status =
- acpi_ds_result_pop_from_bottom(&obj_desc,
- walk_state);
+ status = acpi_ds_result_pop(&obj_desc, walk_state);
if (ACPI_FAILURE(status)) {
/*
* Only error is underflow, and this indicates
@@ -698,27 +701,52 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
{
acpi_status status = AE_OK;
union acpi_parse_object *arg;
+ union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
u32 arg_count = 0;
+ u32 index = walk_state->num_operands;
+ u32 i;
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
- /* For all arguments in the list... */
+ /* Get all arguments in the list */
arg = first_arg;
while (arg) {
- status = acpi_ds_create_operand(walk_state, arg, arg_count);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ if (index >= ACPI_OBJ_NUM_OPERANDS) {
+ return_ACPI_STATUS(AE_BAD_DATA);
}
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Arg #%d (%p) done, Arg1=%p\n", arg_count,
- arg, first_arg));
+ arguments[index] = arg;
+ walk_state->operands[index] = NULL;
/* Move on to next argument, if any */
arg = arg->common.next;
arg_count++;
+ index++;
+ }
+
+ index--;
+
+ /* It is the appropriate order to get objects from the Result stack */
+
+ for (i = 0; i < arg_count; i++) {
+ arg = arguments[index];
+
+ /* Force the filling of the operand stack in inverse order */
+
+ walk_state->operand_index = (u8) index;
+
+ status = acpi_ds_create_operand(walk_state, arg, index);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ index--;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Arg #%d (%p) done, Arg1=%p\n", index, arg,
+ first_arg));
}
return_ACPI_STATUS(status);
@@ -729,9 +757,112 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
* pop everything off of the operand stack and delete those
* objects
*/
- (void)acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+ acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+
+ ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_evaluate_name_path
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk,
+ * the opcode of current operation should be
+ * AML_INT_NAMEPATH_OP
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
+ * interpreter object, convert it to value, if needed, duplicate
+ * it, if needed, and push it onto the current result stack.
+ *
+ ****************************************************************************/
+
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = walk_state->op;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *new_obj_desc;
+ u8 type;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
+
+ if (!op->common.parent) {
+
+ /* This happens after certain exception processing */
+
+ goto exit;
+ }
+
+ if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
+
+ /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
+
+ goto exit;
+ }
+
+ status = acpi_ds_create_operand(walk_state, op, 0);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (op->common.flags & ACPI_PARSEOP_TARGET) {
+ new_obj_desc = *operand;
+ goto push_result;
+ }
+
+ type = ACPI_GET_OBJECT_TYPE(*operand);
+
+ status = acpi_ex_resolve_to_value(operand, walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (type == ACPI_TYPE_INTEGER) {
+
+ /* It was incremented by acpi_ex_resolve_to_value */
+
+ acpi_ut_remove_reference(*operand);
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+ } else {
+ /*
+ * The object either was anew created or is
+ * a Namespace node - don't decrement it.
+ */
+ new_obj_desc = *operand;
+ }
+
+ /* Cleanup for name-path operand */
+
+ status = acpi_ds_obj_stack_pop(1, walk_state);
+ if (ACPI_FAILURE(status)) {
+ walk_state->result_obj = new_obj_desc;
+ goto exit;
+ }
+
+ push_result:
+
+ walk_state->result_obj = new_obj_desc;
+
+ status = acpi_ds_result_push(walk_state->result_obj, walk_state);
+ if (ACPI_SUCCESS(status)) {
+
+ /* Force to take it from stack */
+
+ op->common.flags |= ACPI_PARSEOP_IN_STACK;
+ }
+
+ exit:
- ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d",
- (arg_count + 1)));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index 69693fa07224..b246b9657ead 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -285,11 +285,6 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
switch (opcode_class) {
case AML_CLASS_CONTROL:
- status = acpi_ds_result_stack_push(walk_state);
- if (ACPI_FAILURE(status)) {
- goto error_exit;
- }
-
status = acpi_ds_exec_begin_control_op(walk_state, op);
break;
@@ -305,20 +300,11 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_load2_begin_op(walk_state, NULL);
}
- if (op->common.aml_opcode == AML_REGION_OP) {
- status = acpi_ds_result_stack_push(walk_state);
- }
break;
case AML_CLASS_EXECUTE:
case AML_CLASS_CREATE:
- /*
- * Most operators with arguments (except create_xxx_field operators)
- * Start a new result/operand state
- */
- if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) {
- status = acpi_ds_result_stack_push(walk_state);
- }
+
break;
default:
@@ -374,6 +360,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
/* Init the walk state */
walk_state->num_operands = 0;
+ walk_state->operand_index = 0;
walk_state->return_desc = NULL;
walk_state->result_obj = NULL;
@@ -388,10 +375,17 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
/* Decode the Opcode Class */
switch (op_class) {
- case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */
+ case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */
+
+ if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+ status = acpi_ds_evaluate_name_path(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
break;
- case AML_CLASS_EXECUTE: /* most operators with arguments */
+ case AML_CLASS_EXECUTE: /* Most operators with arguments */
/* Build resolved operand stack */
@@ -400,13 +394,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
goto cleanup;
}
- /* Done with this result state (Now that operand stack is built) */
-
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
/*
* All opcodes require operand resolution, with the only exceptions
* being the object_type and size_of operators.
@@ -487,16 +474,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
status = acpi_ds_exec_end_control_op(walk_state, op);
- /* Make sure to properly pop the result stack */
-
- if (ACPI_SUCCESS(status)) {
- status = acpi_ds_result_stack_pop(walk_state);
- } else if (status == AE_CTRL_PENDING) {
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_PENDING;
- }
- }
break;
case AML_TYPE_METHOD_CALL:
@@ -516,7 +493,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
op->common.node =
(struct acpi_namespace_node *)op->asl.value.
- arg->asl.node->object;
+ arg->asl.node;
acpi_ut_add_reference(op->asl.value.arg->asl.
node->object);
return_ACPI_STATUS(AE_OK);
@@ -632,13 +609,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
break;
}
- /* Done with result state (Now that operand stack is built) */
-
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
/*
* If a result object was returned from above, push it on the
* current result stack
@@ -671,8 +641,28 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
break;
}
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing DataTableRegion Strings Op=%p\n",
+ op));
+
+ status =
+ acpi_ds_eval_table_region_operands
+ (walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ } else if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing BankField Op=%p\n",
+ op));
- status = acpi_ds_result_stack_pop(walk_state);
+ status =
+ acpi_ds_eval_bank_field_operands(walk_state,
+ op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
}
break;
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 8ab9d1b29a4c..dff7a3e445a8 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -443,6 +443,15 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ status =
+ acpi_ex_create_region(op->named.data,
+ op->named.length,
+ REGION_DATA_TABLE,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
#endif
@@ -767,6 +776,12 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
object_type, ACPI_IMODE_LOAD_PASS2, flags,
walk_state, &node);
+
+ if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "***New Node [%4.4s] %p is temporary\n",
+ acpi_ut_get_node_name(node), node));
+ }
break;
}
@@ -823,6 +838,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
struct acpi_namespace_node *new_node;
#ifndef ACPI_NO_METHOD_EXECUTION
u32 i;
+ u8 region_space;
#endif
ACPI_FUNCTION_TRACE(ds_load2_end_op);
@@ -1003,11 +1019,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
status = acpi_ex_create_event(walk_state);
break;
- case AML_DATA_REGION_OP:
-
- status = acpi_ex_create_table_region(walk_state);
- break;
-
case AML_ALIAS_OP:
status = acpi_ex_create_alias(walk_state);
@@ -1035,6 +1046,15 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
switch (op->common.aml_opcode) {
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_REGION_OP:
+ case AML_DATA_REGION_OP:
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ region_space = (acpi_adr_space_type)
+ ((op->common.value.arg)->common.value.
+ integer);
+ } else {
+ region_space = REGION_DATA_TABLE;
+ }
/*
* If we are executing a method, initialize the region
@@ -1043,10 +1063,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
status =
acpi_ex_create_region(op->named.data,
op->named.length,
- (acpi_adr_space_type)
- ((op->common.value.
- arg)->common.value.
- integer),
+ region_space,
walk_state);
if (ACPI_FAILURE(status)) {
return (status);
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index 3927c495e4bf..9e6073265873 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 5afcdd9c7449..1386ced332ec 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,85 +49,9 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswstate")
-/* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_ds_result_insert(void *object,
- u32 index, struct acpi_walk_state *walk_state);
-
-acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state *walk_state);
-
-acpi_status
-acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state);
-
-void *acpi_ds_obj_stack_get_value(u32 index,
- struct acpi_walk_state *walk_state);
-#endif
-
-#ifdef ACPI_FUTURE_USAGE
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_remove
- *
- * PARAMETERS: Object - Where to return the popped object
- * Index - Where to extract the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_remove(union acpi_operand_object **object,
- u32 index, struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_remove);
-
- state = walk_state->results;
- if (!state) {
- ACPI_ERROR((AE_INFO, "No result object pushed! State=%p",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_MAX_OPERAND) {
- ACPI_ERROR((AE_INFO,
- "Index out of range: %X State=%p Num=%X",
- index, walk_state, state->results.num_results));
- }
-
- /* Check for a valid result object */
-
- if (!state->results.obj_desc[index]) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X, Index=%X",
- walk_state, state->results.num_results, index));
- return (AE_AML_NO_RETURN_VALUE);
- }
-
- /* Remove the object */
-
- state->results.num_results--;
-
- *object = state->results.obj_desc[index];
- state->results.obj_desc[index] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object,
- (*object) ? acpi_ut_get_object_type_name(*object) :
- "NULL", index, walk_state,
- state->results.num_results));
-
- return (AE_OK);
-}
-#endif /* ACPI_FUTURE_USAGE */
+ /* Local prototypes */
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws);
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws);
/*******************************************************************************
*
@@ -138,122 +62,67 @@ acpi_ds_result_remove(union acpi_operand_object **object,
*
* RETURN: Status
*
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
+ * DESCRIPTION: Pop an object off the top of this walk's result stack
*
******************************************************************************/
acpi_status
-acpi_ds_result_pop(union acpi_operand_object ** object,
- struct acpi_walk_state * walk_state)
+acpi_ds_result_pop(union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
{
acpi_native_uint index;
union acpi_generic_state *state;
+ acpi_status status;
ACPI_FUNCTION_NAME(ds_result_pop);
state = walk_state->results;
- if (!state) {
- return (AE_OK);
- }
-
- if (!state->results.num_results) {
- ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
- walk_state));
- return (AE_AML_NO_RETURN_VALUE);
- }
- /* Remove top element */
+ /* Incorrect state of result stack */
- state->results.num_results--;
-
- for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) {
-
- /* Check for a valid result object */
-
- if (state->results.obj_desc[index - 1]) {
- *object = state->results.obj_desc[index - 1];
- state->results.obj_desc[index - 1] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object,
- (*object) ?
- acpi_ut_get_object_type_name(*object)
- : "NULL", (u32) index - 1, walk_state,
- state->results.num_results));
-
- return (AE_OK);
- }
+ if (state && !walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No results on result stack"));
+ return (AE_AML_INTERNAL);
}
- ACPI_ERROR((AE_INFO, "No result objects! State=%p", walk_state));
- return (AE_AML_NO_RETURN_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_pop_from_bottom
- *
- * PARAMETERS: Object - Where to return the popped object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_pop_from_bottom(union acpi_operand_object ** object,
- struct acpi_walk_state * walk_state)
-{
- acpi_native_uint index;
- union acpi_generic_state *state;
+ if (!state && walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No result state for result stack"));
+ return (AE_AML_INTERNAL);
+ }
- ACPI_FUNCTION_NAME(ds_result_pop_from_bottom);
+ /* Empty result stack */
- state = walk_state->results;
if (!state) {
- ACPI_ERROR((AE_INFO,
- "No result object pushed! State=%p", walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (!state->results.num_results) {
- ACPI_ERROR((AE_INFO, "No result objects! State=%p",
+ ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
- /* Remove Bottom element */
-
- *object = state->results.obj_desc[0];
-
- /* Push entire stack down one element */
-
- for (index = 0; index < state->results.num_results; index++) {
- state->results.obj_desc[index] =
- state->results.obj_desc[index + 1];
- }
+ /* Return object of the top element and clean that top element result stack */
- state->results.num_results--;
-
- /* Check for a valid result object */
+ walk_state->result_count--;
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+ *object = state->results.obj_desc[index];
if (!*object) {
ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X Index=%X",
- walk_state, state->results.num_results,
- (u32) index));
+ "No result objects on result stack, State=%p",
+ walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] Results=%p State=%p\n",
- *object,
- (*object) ? acpi_ut_get_object_type_name(*object) :
- "NULL", state, walk_state));
+ state->results.obj_desc[index] = NULL;
+ if (index == 0) {
+ status = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
+ acpi_ut_get_object_type_name(*object),
+ (u32) index, walk_state, walk_state->result_count));
return (AE_OK);
}
@@ -276,39 +145,56 @@ acpi_ds_result_push(union acpi_operand_object * object,
struct acpi_walk_state * walk_state)
{
union acpi_generic_state *state;
+ acpi_status status;
+ acpi_native_uint index;
ACPI_FUNCTION_NAME(ds_result_push);
+ if (walk_state->result_count > walk_state->result_size) {
+ ACPI_ERROR((AE_INFO, "Result stack is full"));
+ return (AE_AML_INTERNAL);
+ } else if (walk_state->result_count == walk_state->result_size) {
+
+ /* Extend the result stack */
+
+ status = acpi_ds_result_stack_push(walk_state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Failed to extend the result stack"));
+ return (status);
+ }
+ }
+
+ if (!(walk_state->result_count < walk_state->result_size)) {
+ ACPI_ERROR((AE_INFO, "No free elements in result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
state = walk_state->results;
if (!state) {
ACPI_ERROR((AE_INFO, "No result stack frame during push"));
return (AE_AML_INTERNAL);
}
- if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) {
- ACPI_ERROR((AE_INFO,
- "Result stack overflow: Obj=%p State=%p Num=%X",
- object, walk_state, state->results.num_results));
- return (AE_STACK_OVERFLOW);
- }
-
if (!object) {
ACPI_ERROR((AE_INFO,
"Null Object! Obj=%p State=%p Num=%X",
- object, walk_state, state->results.num_results));
+ object, walk_state, walk_state->result_count));
return (AE_BAD_PARAMETER);
}
- state->results.obj_desc[state->results.num_results] = object;
- state->results.num_results++;
+ /* Assign the address of object to the top free element of result stack */
+
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+ state->results.obj_desc[index] = object;
+ walk_state->result_count++;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
object,
- object ?
acpi_ut_get_object_type_name((union
acpi_operand_object *)
- object) : "NULL",
- walk_state, state->results.num_results,
+ object), walk_state,
+ walk_state->result_count,
walk_state->current_result));
return (AE_OK);
@@ -322,16 +208,25 @@ acpi_ds_result_push(union acpi_operand_object * object,
*
* RETURN: Status
*
- * DESCRIPTION: Push an object onto the walk_state result stack.
+ * DESCRIPTION: Push an object onto the walk_state result stack
*
******************************************************************************/
-acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
ACPI_FUNCTION_NAME(ds_result_stack_push);
+ /* Check for stack overflow */
+
+ if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) >
+ ACPI_RESULTS_OBJ_NUM_MAX) {
+ ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%X",
+ walk_state, walk_state->result_size));
+ return (AE_STACK_OVERFLOW);
+ }
+
state = acpi_ut_create_generic_state();
if (!state) {
return (AE_NO_MEMORY);
@@ -340,6 +235,10 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
acpi_ut_push_generic_state(&walk_state->results, state);
+ /* Increase the length of the result stack by the length of frame */
+
+ walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM;
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
state, walk_state));
@@ -354,11 +253,11 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
*
* RETURN: Status
*
- * DESCRIPTION: Pop an object off of the walk_state result stack.
+ * DESCRIPTION: Pop an object off of the walk_state result stack
*
******************************************************************************/
-acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
@@ -367,18 +266,27 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
/* Check for stack underflow */
if (walk_state->results == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Underflow - State=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Result stack underflow - State=%p\n",
walk_state));
return (AE_AML_NO_OPERAND);
}
+ if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) {
+ ACPI_ERROR((AE_INFO, "Insufficient result stack size"));
+ return (AE_AML_INTERNAL);
+ }
+
state = acpi_ut_pop_generic_state(&walk_state->results);
+ acpi_ut_delete_generic_state(state);
+
+ /* Decrease the length of result stack by the length of frame */
+
+ walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Result=%p RemainingResults=%X State=%p\n",
- state, state->results.num_results, walk_state));
-
- acpi_ut_delete_generic_state(state);
+ state, walk_state->result_count, walk_state));
return (AE_OK);
}
@@ -412,9 +320,13 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state)
/* Put the object onto the stack */
- walk_state->operands[walk_state->num_operands] = object;
+ walk_state->operands[walk_state->operand_index] = object;
walk_state->num_operands++;
+ /* For the usual order of filling the operand stack */
+
+ walk_state->operand_index++;
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
object,
acpi_ut_get_object_type_name((union
@@ -484,43 +396,36 @@ acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state)
*
******************************************************************************/
-acpi_status
+void
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
- struct acpi_walk_state * walk_state)
+ struct acpi_walk_state *walk_state)
{
- u32 i;
+ acpi_native_int i;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
- for (i = 0; i < pop_count; i++) {
-
- /* Check for stack underflow */
+ if (pop_count == 0) {
+ return;
+ }
+ for (i = (acpi_native_int) (pop_count - 1); i >= 0; i--) {
if (walk_state->num_operands == 0) {
- ACPI_ERROR((AE_INFO,
- "Object stack underflow! Count=%X State=%p #Ops=%X",
- pop_count, walk_state,
- walk_state->num_operands));
- return (AE_STACK_UNDERFLOW);
+ return;
}
/* Pop the stack and delete an object if present in this stack entry */
walk_state->num_operands--;
- obj_desc = walk_state->operands[walk_state->num_operands];
+ obj_desc = walk_state->operands[i];
if (obj_desc) {
- acpi_ut_remove_reference(walk_state->
- operands[walk_state->
- num_operands]);
- walk_state->operands[walk_state->num_operands] = NULL;
+ acpi_ut_remove_reference(walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
}
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
pop_count, walk_state, walk_state->num_operands));
-
- return (AE_OK);
}
/*******************************************************************************
@@ -560,7 +465,7 @@ struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
*
* RETURN: None
*
- * DESCRIPTION: Place the Thread state at the head of the state list.
+ * DESCRIPTION: Place the Thread state at the head of the state list
*
******************************************************************************/
@@ -636,7 +541,6 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union
*thread)
{
struct acpi_walk_state *walk_state;
- acpi_status status;
ACPI_FUNCTION_TRACE(ds_create_walk_state);
@@ -659,14 +563,6 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union
acpi_ds_method_data_init(walk_state);
#endif
- /* Create an initial result stack entry */
-
- status = acpi_ds_result_stack_push(walk_state);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(walk_state);
- return_PTR(NULL);
- }
-
/* Put the new state at the head of the walk list */
if (thread) {
@@ -860,190 +756,3 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
ACPI_FREE(walk_state);
return_VOID;
}
-
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_insert
- *
- * PARAMETERS: Object - Object to push
- * Index - Where to insert the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Insert an object onto this walk's result stack
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_insert(void *object,
- u32 index, struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_insert);
-
- state = walk_state->results;
- if (!state) {
- ACPI_ERROR((AE_INFO, "No result object pushed! State=%p",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_NUM_OPERANDS) {
- ACPI_ERROR((AE_INFO,
- "Index out of range: %X Obj=%p State=%p Num=%X",
- index, object, walk_state,
- state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- if (!object) {
- ACPI_ERROR((AE_INFO,
- "Null Object! Index=%X Obj=%p State=%p Num=%X",
- index, object, walk_state,
- state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- state->results.obj_desc[index] = object;
- state->results.num_results++;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
- object,
- object ?
- acpi_ut_get_object_type_name((union
- acpi_operand_object *)
- object) : "NULL",
- walk_state, state->results.num_results,
- walk_state->current_result));
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_delete_all
- *
- * PARAMETERS: walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
- * Should be used with great care, if at all!
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state * walk_state)
-{
- u32 i;
-
- ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_delete_all, walk_state);
-
- /* The stack size is configurable, but fixed */
-
- for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) {
- if (walk_state->operands[i]) {
- acpi_ut_remove_reference(walk_state->operands[i]);
- walk_state->operands[i] = NULL;
- }
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_pop_object
- *
- * PARAMETERS: Object - Where to return the popped object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
- * deleted by this routine.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state)
-{
- ACPI_FUNCTION_NAME(ds_obj_stack_pop_object);
-
- /* Check for stack underflow */
-
- if (walk_state->num_operands == 0) {
- ACPI_ERROR((AE_INFO,
- "Missing operand/stack empty! State=%p #Ops=%X",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Pop the stack */
-
- walk_state->num_operands--;
-
- /* Check for a valid operand */
-
- if (!walk_state->operands[walk_state->num_operands]) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Get operand and set stack entry to null */
-
- *object = walk_state->operands[walk_state->num_operands];
- walk_state->operands[walk_state->num_operands] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
- *object, acpi_ut_get_object_type_name(*object),
- walk_state, walk_state->num_operands));
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_get_value
- *
- * PARAMETERS: Index - Stack index whose value is desired. Based
- * on the top of the stack (index=0 == top)
- * walk_state - Current Walk state
- *
- * RETURN: Pointer to the requested operand
- *
- * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must
- * be within the range of the current stack pointer.
- *
- ******************************************************************************/
-
-void *acpi_ds_obj_stack_get_value(u32 index, struct acpi_walk_state *walk_state)
-{
-
- ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_get_value, walk_state);
-
- /* Can't do it if the stack is empty */
-
- if (walk_state->num_operands == 0) {
- return_PTR(NULL);
- }
-
- /* or if the index is past the top of the stack */
-
- if (index > (walk_state->num_operands - (u32) 1)) {
- return_PTR(NULL);
- }
-
- return_PTR(walk_state->
- operands[(acpi_native_uint) (walk_state->num_operands - 1) -
- index]);
-}
-#endif
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7222a18a0319..3d9362140831 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -73,38 +73,14 @@ enum ec_event {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
- EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
- EC_FLAGS_ADDRESS, /* Address is being written */
- EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
- EC_FLAGS_WDATA, /* Data is being written */
- EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
-};
-
-static int acpi_ec_remove(struct acpi_device *device, int type);
-static int acpi_ec_start(struct acpi_device *device);
-static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_add(struct acpi_device *device);
-
-static const struct acpi_device_id ec_device_ids[] = {
- {"PNP0C09", 0},
- {"", 0},
-};
-
-static struct acpi_driver acpi_ec_driver = {
- .name = "ec",
- .class = ACPI_EC_CLASS,
- .ids = ec_device_ids,
- .ops = {
- .add = acpi_ec_add,
- .remove = acpi_ec_remove,
- .start = acpi_ec_start,
- .stop = acpi_ec_stop,
- },
+ EC_FLAGS_NO_GPE, /* Don't use GPE mode */
+ EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -129,6 +105,8 @@ static struct acpi_ec {
struct mutex lock;
wait_queue_head_t wait;
struct list_head list;
+ struct delayed_work work;
+ atomic_t irq_count;
u8 handlers_installed;
} *boot_ec, *first_ec;
@@ -177,65 +155,52 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
return 0;
}
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
+static void ec_schedule_ec_poll(struct acpi_ec *ec)
{
- int ret = 0;
+ if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
+ schedule_delayed_work(&ec->work,
+ msecs_to_jiffies(ACPI_EC_DELAY));
+}
- if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
- test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
- test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
- test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
- force_poll = 1;
+static void ec_switch_to_poll_mode(struct acpi_ec *ec)
+{
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+}
+
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
+{
+ atomic_set(&ec->irq_count, 0);
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
msecs_to_jiffies(ACPI_EC_DELAY)))
- goto end;
+ return 0;
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (acpi_ec_check_status(ec, event)) {
- if (event == ACPI_EC_EVENT_OBF_1) {
- /* miss OBF_1 GPE, don't expect it */
- pr_info(PREFIX "missing OBF confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
- /* miss address GPE, don't expect it anymore */
- pr_info(PREFIX "missing address confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
- /* miss write data GPE, don't expect it */
- pr_info(PREFIX "missing write data confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
- } else {
- /* missing GPEs, switch back to poll mode */
- if (printk_ratelimit())
- pr_info(PREFIX "missing confirmations, "
+ /* missing GPEs, switch back to poll mode */
+ if (printk_ratelimit())
+ pr_info(PREFIX "missing confirmations, "
"switch off interrupt mode.\n");
- clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- }
- goto end;
+ ec_switch_to_poll_mode(ec);
+ ec_schedule_ec_poll(ec);
+ return 0;
}
} else {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
- goto end;
+ return 0;
+ udelay(ACPI_EC_UDELAY);
}
}
- pr_err(PREFIX "acpi_ec_wait timeout,"
- " status = %d, expect_event = %d\n",
- acpi_ec_read_status(ec), event);
- ret = -ETIME;
- end:
- clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
- return ret;
+ pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
+ acpi_ec_read_status(ec),
+ (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
+ return -ETIME;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -245,8 +210,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
{
int result = 0;
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- acpi_ec_write_cmd(ec, command);
pr_debug(PREFIX "transaction start\n");
+ acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
@@ -254,15 +219,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
"write_cmd timeout, command = %d\n", command);
goto end;
}
- /* mark the address byte written to EC */
- if (rdata_len + wdata_len > 1)
- set_bit(EC_FLAGS_ADDRESS, &ec->flags);
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
- set_bit(EC_FLAGS_WDATA, &ec->flags);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
pr_err(PREFIX
@@ -527,47 +488,51 @@ static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status status = AE_OK;
struct acpi_ec *ec = data;
+ u8 state = acpi_ec_read_status(ec);
pr_debug(PREFIX "~~~> interrupt\n");
+ atomic_inc(&ec->irq_count);
+ if (atomic_read(&ec->irq_count) > 5) {
+ pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+ ec_switch_to_poll_mode(ec);
+ goto end;
+ }
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {
+ if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
status = acpi_os_execute(OSL_EC_BURST_HANDLER,
acpi_ec_gpe_query, ec);
- } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
+ } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+ !test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
+ in_interrupt()) {
/* this is non-query, must be confirmation */
if (printk_ratelimit())
pr_info(PREFIX "non-query interrupt received,"
" switching to interrupt mode\n");
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
}
-
+end:
+ ec_schedule_ec_poll(ec);
return ACPI_SUCCESS(status) ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
+static void do_ec_poll(struct work_struct *work)
+{
+ struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
+ atomic_set(&ec->irq_count, 0);
+ (void)acpi_ec_gpe_handler(ec);
+}
+
/* --------------------------------------------------------------------------
Address Space Management
-------------------------------------------------------------------------- */
static acpi_status
-acpi_ec_space_setup(acpi_handle region_handle,
- u32 function, void *handler_context, void **return_context)
-{
- /*
- * The EC object is in the handler context and is needed
- * when calling the acpi_ec_space_handler.
- */
- *return_context = (function != ACPI_REGION_DEACTIVATE) ?
- handler_context : NULL;
-
- return AE_OK;
-}
-
-static acpi_status
acpi_ec_space_handler(u32 function, acpi_physical_address address,
u32 bits, acpi_integer *value,
void *handler_context, void *region_context)
@@ -709,6 +674,8 @@ static struct acpi_ec *make_acpi_ec(void)
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
+ INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
+ atomic_set(&ec->irq_count, 0);
return ec;
}
@@ -741,17 +708,21 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status))
return status;
- /* Find and register all query methods */
- acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
- acpi_ec_register_query_methods, ec, NULL);
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
ec->handle = handle;
return AE_CTRL_TERMINATE;
}
+static void ec_poll_stop(struct acpi_ec *ec)
+{
+ clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+ cancel_delayed_work(&ec->work);
+}
+
static void ec_remove_handlers(struct acpi_ec *ec)
{
+ ec_poll_stop(ec);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n");
@@ -771,31 +742,28 @@ static int acpi_ec_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
/* Check for boot EC */
- if (boot_ec) {
- if (boot_ec->handle == device->handle) {
- /* Pre-loaded EC from DSDT, just move pointer */
- ec = boot_ec;
- boot_ec = NULL;
- goto end;
- } else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
- /* ECDT-based EC, time to shut it down */
- ec_remove_handlers(boot_ec);
- kfree(boot_ec);
- first_ec = boot_ec = NULL;
+ if (boot_ec &&
+ (boot_ec->handle == device->handle ||
+ boot_ec->handle == ACPI_ROOT_OBJECT)) {
+ ec = boot_ec;
+ boot_ec = NULL;
+ } else {
+ ec = make_acpi_ec();
+ if (!ec)
+ return -ENOMEM;
+ if (ec_parse_device(device->handle, 0, ec, NULL) !=
+ AE_CTRL_TERMINATE) {
+ kfree(ec);
+ return -EINVAL;
}
}
- ec = make_acpi_ec();
- if (!ec)
- return -ENOMEM;
-
- if (ec_parse_device(device->handle, 0, ec, NULL) !=
- AE_CTRL_TERMINATE) {
- kfree(ec);
- return -EINVAL;
- }
ec->handle = device->handle;
- end:
+
+ /* Find and register all query methods */
+ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
+ acpi_ec_register_query_methods, ec, NULL);
+
if (!first_ec)
first_ec = ec;
acpi_driver_data(device) = ec;
@@ -870,7 +838,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
- &acpi_ec_space_setup, ec);
+ NULL, ec);
if (ACPI_FAILURE(status)) {
acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
return -ENODEV;
@@ -897,6 +865,7 @@ static int acpi_ec_start(struct acpi_device *device)
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ ec_schedule_ec_poll(ec);
return ret;
}
@@ -924,6 +893,11 @@ int __init acpi_boot_ec_enable(void)
return -EFAULT;
}
+static const struct acpi_device_id ec_device_ids[] = {
+ {"PNP0C09", 0},
+ {"", 0},
+};
+
int __init acpi_ec_ecdt_probe(void)
{
int ret;
@@ -944,6 +918,7 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
+ acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
} else {
/* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */
@@ -973,6 +948,39 @@ int __init acpi_ec_ecdt_probe(void)
return -ENODEV;
}
+static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Stop using GPE */
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static int acpi_ec_resume(struct acpi_device *device)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Enable use of GPE back */
+ clear_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static struct acpi_driver acpi_ec_driver = {
+ .name = "ec",
+ .class = ACPI_EC_CLASS,
+ .ids = ec_device_ids,
+ .ops = {
+ .add = acpi_ec_add,
+ .remove = acpi_ec_remove,
+ .start = acpi_ec_start,
+ .stop = acpi_ec_stop,
+ .suspend = acpi_ec_suspend,
+ .resume = acpi_ec_resume,
+ },
+};
+
static int __init acpi_ec_init(void)
{
int result = 0;
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 3048801a37b5..5d30e5be1b1c 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index cd06170e7871..5354be44f876 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 361ebe6c4a6f..e6c4d4c49e79 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 21cb749d0c75..2113e58e2221 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,22 +49,7 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evmisc")
-/* Names for Notify() values, used for debug output */
-#ifdef ACPI_DEBUG_OUTPUT
-static const char *acpi_notify_value_names[] = {
- "Bus Check",
- "Device Check",
- "Device Wake",
- "Eject Request",
- "Device Check Light",
- "Frequency Mismatch",
- "Bus Mode Mismatch",
- "Power Fault"
-};
-#endif
-
/* Pointer to FACS needed for the Global Lock */
-
static struct acpi_table_facs *facs = NULL;
/* Local prototypes */
@@ -94,7 +79,6 @@ u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
switch (node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL:
/*
* These are the ONLY objects that can receive ACPI notifications
@@ -139,17 +123,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
* initiate soft-off or sleep operation?
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Dispatching Notify(%X) on node %p\n", notify_value,
- node));
-
- if (notify_value <= 7) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n",
- acpi_notify_value_names[notify_value]));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Notify value: 0x%2.2X **Device Specific**\n",
- notify_value));
- }
+ "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
+ acpi_ut_get_node_name(node), node, notify_value,
+ acpi_ut_get_notify_name(notify_value)));
/* Get the notify object attached to the NS Node */
@@ -159,10 +135,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
/* We have the notify object, Get the right handler */
switch (node->type) {
+
+ /* Notify allowed only on these types */
+
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_POWER:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj =
@@ -179,8 +157,13 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
}
}
- /* If there is any handler to run, schedule the dispatcher */
-
+ /*
+ * If there is any handler to run, schedule the dispatcher.
+ * Check for:
+ * 1) Global system notify handler
+ * 2) Global device notify handler
+ * 3) Per-device notify handler
+ */
if ((acpi_gbl_system_notify.handler
&& (notify_value <= ACPI_MAX_SYS_NOTIFY))
|| (acpi_gbl_device_notify.handler
@@ -190,6 +173,13 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
return (AE_NO_MEMORY);
}
+ if (!handler_obj) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Executing system notify handler for Notify (%4.4s, %X) node %p\n",
+ acpi_ut_get_node_name(node),
+ notify_value, node));
+ }
+
notify_info->common.descriptor_type =
ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
@@ -202,15 +192,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
}
- }
-
- if (!handler_obj) {
+ } else {
/*
- * There is no per-device notify handler for this device.
- * This may or may not be a problem.
+ * There is no notify handler (per-device or system) for this device.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "No notify handler for Notify(%4.4s, %X) node %p\n",
+ "No notify handler for Notify (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));
}
@@ -349,9 +336,10 @@ acpi_status acpi_ev_init_global_lock_handler(void)
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -439,7 +427,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
* Only one thread can acquire the GL at a time, the global_lock_mutex
* enforces this. This interface releases the interpreter if we must wait.
*/
- status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, 0);
+ status = acpi_ex_system_wait_mutex(
+ acpi_gbl_global_lock_mutex->mutex.os_mutex, 0);
if (status == AE_TIME) {
if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) {
acpi_ev_global_lock_acquired++;
@@ -448,9 +437,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
}
if (ACPI_FAILURE(status)) {
- status =
- acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex,
- timeout);
+ status = acpi_ex_system_wait_mutex(
+ acpi_gbl_global_lock_mutex->mutex.os_mutex,
+ timeout);
}
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -460,6 +449,19 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
acpi_ev_global_lock_acquired++;
/*
+ * Update the global lock handle and check for wraparound. The handle is
+ * only used for the external global lock interfaces, but it is updated
+ * here to properly handle the case where a single thread may acquire the
+ * lock via both the AML and the acpi_acquire_global_lock interfaces. The
+ * handle is therefore updated on the first acquire from a given thread
+ * regardless of where the acquisition request originated.
+ */
+ acpi_gbl_global_lock_handle++;
+ if (acpi_gbl_global_lock_handle == 0) {
+ acpi_gbl_global_lock_handle = 1;
+ }
+
+ /*
* Make sure that a global lock actually exists. If not, just treat
* the lock as a standard mutex.
*/
@@ -555,7 +557,7 @@ acpi_status acpi_ev_release_global_lock(void)
/* Release the local GL mutex */
acpi_ev_global_lock_thread_id = NULL;
acpi_ev_global_lock_acquired = 0;
- acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 58ad09725dd2..1628f5934752 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -394,7 +394,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.handler->address_space, handler,
- ACPI_FORMAT_UINT64(address),
+ ACPI_FORMAT_NATIVE_UINT(address),
acpi_ut_get_region_name(region_obj->region.
space_id)));
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index b1aaa0e84588..2e3d2c5e4f4d 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 7e5d15ce2395..2a8b77877610 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 6d866a01f5f4..94a6efe020be 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -758,6 +758,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
*
* DESCRIPTION: Acquire the ACPI Global Lock
*
+ * Note: Allows callers with the same thread ID to acquire the global lock
+ * multiple times. In other words, externally, the behavior of the global lock
+ * is identical to an AML mutex. On the first acquire, a new handle is
+ * returned. On any subsequent calls to acquire by the same thread, the same
+ * handle is returned.
+ *
******************************************************************************/
acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
{
@@ -770,14 +776,19 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
/* Must lock interpreter to prevent race conditions */
acpi_ex_enter_interpreter();
- status = acpi_ev_acquire_global_lock(timeout);
- acpi_ex_exit_interpreter();
+
+ status = acpi_ex_acquire_mutex_object(timeout,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
if (ACPI_SUCCESS(status)) {
- acpi_gbl_global_lock_handle++;
+
+ /* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */
+
*handle = acpi_gbl_global_lock_handle;
}
+ acpi_ex_exit_interpreter();
return (status);
}
@@ -798,11 +809,11 @@ acpi_status acpi_release_global_lock(u32 handle)
{
acpi_status status;
- if (handle != acpi_gbl_global_lock_handle) {
+ if (!handle || (handle != acpi_gbl_global_lock_handle)) {
return (AE_NOT_ACQUIRED);
}
- status = acpi_ev_release_global_lock();
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
return (status);
}
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 9cbd3414a574..99a7502e6a87 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 7bf09c5fb242..e8750807e57d 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 25802f302ffe..24da921d13e3 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
#include <acpi/actables.h>
#include <acpi/acdispat.h>
@@ -138,6 +137,14 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE(ex_load_table_op);
+ /* Validate lengths for the signature_string, OEMIDString, OEMtable_iD */
+
+ if ((operand[0]->string.length > ACPI_NAME_SIZE) ||
+ (operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
+ (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
/* Find the ACPI table in the RSDT/XSDT */
status = acpi_tb_find_table(operand[0]->string.pointer,
@@ -229,11 +236,18 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
status = acpi_get_table_by_index(table_index, &table);
if (ACPI_SUCCESS(status)) {
ACPI_INFO((AE_INFO,
- "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+ "Dynamic OEM Table Load - [%.4s] OemId [%.6s] OemTableId [%.8s]",
table->signature, table->oem_id,
table->oem_table_id));
}
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
+ acpi_gbl_table_handler_context);
+ }
+
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
}
@@ -268,6 +282,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
struct acpi_table_desc table_desc;
acpi_native_uint table_index;
acpi_status status;
+ u32 length;
ACPI_FUNCTION_TRACE(ex_load_op);
@@ -278,16 +293,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
+ obj_desc,
+ acpi_ut_get_object_type_name(obj_desc)));
+
/* Region must be system_memory (from ACPI spec) */
if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
- obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
-
/*
* If the Region Address and Length have not been previously evaluated,
* evaluate them now and save the results.
@@ -299,6 +314,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
}
+ /*
+ * We will simply map the memory region for the table. However, the
+ * memory region is technically not guaranteed to remain stable and
+ * we may eventually have to copy the table to a local buffer.
+ */
table_desc.address = obj_desc->region.address;
table_desc.length = obj_desc->region.length;
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
@@ -306,18 +326,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
- /* Simply extract the buffer from the buffer object */
-
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Load from Buffer or Field %p %s\n", obj_desc,
acpi_ut_get_object_type_name(obj_desc)));
- table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
- obj_desc->buffer.pointer);
- table_desc.length = table_desc.pointer->length;
- table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+ length = obj_desc->buffer.length;
+
+ /* Must have at least an ACPI table header */
+
+ if (length < sizeof(struct acpi_table_header)) {
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
+
+ /* Validate checksum here. It won't get validated in tb_add_table */
- obj_desc->buffer.pointer = NULL;
+ status =
+ acpi_tb_verify_checksum(ACPI_CAST_PTR
+ (struct acpi_table_header,
+ obj_desc->buffer.pointer), length);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * We need to copy the buffer since the original buffer could be
+ * changed or deleted in the future
+ */
+ table_desc.pointer = ACPI_ALLOCATE(length);
+ if (!table_desc.pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer,
+ length);
+ table_desc.length = length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
break;
default:
@@ -333,7 +376,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
status =
- acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
+ acpi_ex_add_table(table_index, walk_state->scope_info->scope.node,
+ &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
@@ -349,11 +393,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* table_ptr was deallocated above */
+ acpi_ut_remove_reference(ddb_handle);
return_ACPI_STATUS(status);
}
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD,
+ table_desc.pointer,
+ acpi_gbl_table_handler_context);
+ }
+
cleanup:
if (ACPI_FAILURE(status)) {
+
+ /* Delete allocated buffer or mapping */
+
acpi_tb_delete_table(&table_desc);
}
return_ACPI_STATUS(status);
@@ -376,6 +432,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
acpi_status status = AE_OK;
union acpi_operand_object *table_desc = ddb_handle;
acpi_native_uint table_index;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -395,17 +452,25 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
table_index = (acpi_native_uint) table_desc->reference.object;
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_SUCCESS(status)) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD,
+ table,
+ acpi_gbl_table_handler_context);
+ }
+ }
+
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
acpi_tb_delete_namespace_by_owner(table_index);
- acpi_tb_release_owner_id(table_index);
+ (void)acpi_tb_release_owner_id(table_index);
acpi_tb_set_table_loaded_flag(table_index, FALSE);
- /* Delete the table descriptor (ddb_handle) */
-
- acpi_ut_remove_reference(table_desc);
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 79f2c0d42c06..fd954b4ed83d 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 6e9a23e47fef..60e62c4f0577 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -96,6 +96,9 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
* to the original Node.
*/
switch (target_node->type) {
+
+ /* For these types, the sub-object can change dynamically via a Store */
+
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
@@ -103,9 +106,18 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
case ACPI_TYPE_BUFFER_FIELD:
/*
+ * These types open a new scope, so we need the NS node in order to access
+ * any children.
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_LOCAL_SCOPE:
+
+ /*
* The new alias has the type ALIAS and points to the original
- * NS node, not the object itself. This is because for these
- * types, the object can change dynamically via a Store.
+ * NS node, not the object itself.
*/
alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
alias_node->object =
@@ -115,9 +127,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
case ACPI_TYPE_METHOD:
/*
- * The new alias has the type ALIAS and points to the original
- * NS node, not the object itself. This is because for these
- * types, the object can change dynamically via a Store.
+ * Control method aliases need to be differentiated
*/
alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
alias_node->object =
@@ -342,101 +352,6 @@ acpi_ex_create_region(u8 * aml_start,
/*******************************************************************************
*
- * FUNCTION: acpi_ex_create_table_region
- *
- * PARAMETERS: walk_state - Current state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create a new data_table_region object
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
-{
- acpi_status status;
- union acpi_operand_object **operand = &walk_state->operands[0];
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
- union acpi_operand_object *region_obj2;
- acpi_native_uint table_index;
- struct acpi_table_header *table;
-
- ACPI_FUNCTION_TRACE(ex_create_table_region);
-
- /* Get the Node from the object stack */
-
- node = walk_state->op->common.node;
-
- /*
- * If the region object is already attached to this node,
- * just return
- */
- if (acpi_ns_get_attached_object(node)) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Find the ACPI table */
-
- status = acpi_tb_find_table(operand[1]->string.pointer,
- operand[2]->string.pointer,
- operand[3]->string.pointer, &table_index);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Create the region descriptor */
-
- obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
- if (!obj_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- region_obj2 = obj_desc->common.next_object;
- region_obj2->extra.region_context = NULL;
-
- status = acpi_get_table_by_index(table_index, &table);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Init the region from the operands */
-
- obj_desc->region.space_id = REGION_DATA_TABLE;
- obj_desc->region.address =
- (acpi_physical_address) ACPI_TO_INTEGER(table);
- obj_desc->region.length = table->length;
- obj_desc->region.node = node;
- obj_desc->region.flags = AOPOBJ_DATA_VALID;
-
- /* Install the new region object in the parent Node */
-
- status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status = acpi_ev_initialize_region(obj_desc, FALSE);
- if (ACPI_FAILURE(status)) {
- if (status == AE_NOT_EXIST) {
- status = AE_OK;
- } else {
- goto cleanup;
- }
- }
-
- obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE;
-
- cleanup:
-
- /* Remove local reference to the object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_create_processor
*
* PARAMETERS: walk_state - Current state
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 51c9c29987c3..74f1b22601b3 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -500,25 +500,28 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
acpi_os_printf("Reference: Debug\n");
break;
- case AML_NAME_OP:
+ case AML_INDEX_OP:
- ACPI_DUMP_PATHNAME(obj_desc->reference.object,
- "Reference: Name: ", ACPI_LV_INFO,
- _COMPONENT);
- ACPI_DUMP_ENTRY(obj_desc->reference.object,
- ACPI_LV_INFO);
+ acpi_os_printf("Reference: Index %p\n",
+ obj_desc->reference.object);
break;
- case AML_INDEX_OP:
+ case AML_LOAD_OP:
- acpi_os_printf("Reference: Index %p\n",
+ acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n",
obj_desc->reference.object);
break;
case AML_REF_OF_OP:
- acpi_os_printf("Reference: (RefOf) %p\n",
- obj_desc->reference.object);
+ acpi_os_printf("Reference: (RefOf) %p [%s]\n",
+ obj_desc->reference.object,
+ acpi_ut_get_type_name(((union
+ acpi_operand_object
+ *)obj_desc->
+ reference.
+ object)->common.
+ type));
break;
case AML_ARG_OP:
@@ -559,8 +562,9 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case AML_INT_NAMEPATH_OP:
- acpi_os_printf("Reference.Node->Name %X\n",
- obj_desc->reference.node->name.integer);
+ acpi_os_printf("Reference: Namepath %X [%4.4s]\n",
+ obj_desc->reference.node->name.integer,
+ obj_desc->reference.node->name.ascii);
break;
default:
@@ -640,8 +644,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
acpi_os_printf("\n");
} else {
acpi_os_printf(" base %8.8X%8.8X Length %X\n",
- ACPI_FORMAT_UINT64(obj_desc->region.
- address),
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.
+ address),
obj_desc->region.length);
}
break;
@@ -877,20 +881,43 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) {
- acpi_os_printf("Named Object %p ", obj_desc->reference.node);
+ acpi_os_printf(" Named Object %p ", obj_desc->reference.node);
status =
acpi_ns_handle_to_pathname(obj_desc->reference.node,
&ret_buf);
if (ACPI_FAILURE(status)) {
- acpi_os_printf("Could not convert name to pathname\n");
+ acpi_os_printf(" Could not convert name to pathname\n");
} else {
acpi_os_printf("%s\n", (char *)ret_buf.pointer);
ACPI_FREE(ret_buf.pointer);
}
} else if (obj_desc->reference.object) {
- acpi_os_printf("\nReferenced Object: %p\n",
- obj_desc->reference.object);
+ if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) ==
+ ACPI_DESC_TYPE_OPERAND) {
+ acpi_os_printf(" Target: %p",
+ obj_desc->reference.object);
+ if (obj_desc->reference.opcode == AML_LOAD_OP) {
+ /*
+ * For DDBHandle reference,
+ * obj_desc->Reference.Object is the table index
+ */
+ acpi_os_printf(" [DDBHandle]\n");
+ } else {
+ acpi_os_printf(" [%s]\n",
+ acpi_ut_get_type_name(((union
+ acpi_operand_object
+ *)
+ obj_desc->
+ reference.
+ object)->
+ common.
+ type));
+ }
+ } else {
+ acpi_os_printf(" Target: %p\n",
+ obj_desc->reference.object);
+ }
}
}
@@ -976,7 +1003,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
case ACPI_TYPE_LOCAL_REFERENCE:
- acpi_os_printf("[Object Reference] ");
+ acpi_os_printf("[Object Reference] %s",
+ (acpi_ps_get_opcode_info
+ (obj_desc->reference.opcode))->name);
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 2d88a3d8d1ad..3e440d84226a 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,6 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
union acpi_operand_object *buffer_desc;
acpi_size length;
void *buffer;
- u8 locked;
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
@@ -111,9 +110,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.
- field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/*
* Perform the read.
@@ -125,7 +122,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
buffer.pointer),
ACPI_READ | (obj_desc->field.
attribute << 16));
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
goto exit;
}
@@ -175,13 +172,12 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Read from the field */
status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
exit:
if (ACPI_FAILURE(status)) {
@@ -214,10 +210,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
{
acpi_status status;
u32 length;
- u32 required_length;
void *buffer;
- void *new_buffer;
- u8 locked;
union acpi_operand_object *buffer_desc;
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -278,9 +271,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.
- field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/*
* Perform the write (returns status and perhaps data in the
@@ -291,7 +282,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
(acpi_integer *) buffer,
ACPI_WRITE | (obj_desc->field.
attribute << 16));
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
*result_desc = buffer_desc;
return_ACPI_STATUS(status);
@@ -319,35 +310,6 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /*
- * We must have a buffer that is at least as long as the field
- * we are writing to. This is because individual fields are
- * indivisible and partial writes are not supported -- as per
- * the ACPI specification.
- */
- new_buffer = NULL;
- required_length =
- ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
-
- if (length < required_length) {
-
- /* We need to create a new buffer */
-
- new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
- if (!new_buffer) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /*
- * Copy the original data to the new buffer, starting
- * at Byte zero. All unused (upper) bytes of the
- * buffer will be 0.
- */
- ACPI_MEMCPY((char *)new_buffer, (char *)buffer, length);
- buffer = new_buffer;
- length = required_length;
- }
-
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
source_desc,
@@ -366,19 +328,12 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Write to the field */
status = acpi_ex_insert_into_field(obj_desc, buffer, length);
- acpi_ex_release_global_lock(locked);
-
- /* Free temporary buffer if we used one */
-
- if (new_buffer) {
- ACPI_FREE(new_buffer);
- }
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 65a48b6170ee..e336b5dc7a50 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -263,7 +263,8 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
- field_datum_byte_offset, (void *)address));
+ field_datum_byte_offset, ACPI_CAST_PTR(void,
+ address)));
/* Invoke the appropriate address_space/op_region handler */
@@ -805,18 +806,39 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
u32 datum_count;
u32 field_datum_count;
u32 i;
+ u32 required_length;
+ void *new_buffer;
ACPI_FUNCTION_TRACE(ex_insert_into_field);
/* Validate input buffer */
- if (buffer_length <
- ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
- ACPI_ERROR((AE_INFO,
- "Field size %X (bits) is too large for buffer (%X)",
- obj_desc->common_field.bit_length, buffer_length));
+ new_buffer = NULL;
+ required_length =
+ ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
+ /*
+ * We must have a buffer that is at least as long as the field
+ * we are writing to. This is because individual fields are
+ * indivisible and partial writes are not supported -- as per
+ * the ACPI specification.
+ */
+ if (buffer_length < required_length) {
- return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
+ /* We need to create a new buffer */
+
+ new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
+ if (!new_buffer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the original data to the new buffer, starting
+ * at Byte zero. All unused (upper) bytes of the
+ * buffer will be 0.
+ */
+ ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length);
+ buffer = new_buffer;
+ buffer_length = required_length;
}
/*
@@ -866,7 +888,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
merged_datum,
field_offset);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
field_offset += obj_desc->common_field.access_byte_width;
@@ -924,5 +946,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
mask, merged_datum,
field_offset);
+ exit:
+ /* Free temporary buffer if we used one */
+
+ if (new_buffer) {
+ ACPI_FREE(new_buffer);
+ }
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index f13d1cec2d6d..cc956a5b5267 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 6748e3ef0997..c873ab40cd0e 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,6 +126,79 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
/*******************************************************************************
*
+ * FUNCTION: acpi_ex_acquire_mutex_object
+ *
+ * PARAMETERS: time_desc - Timeout in milliseconds
+ * obj_desc - Mutex object
+ * Thread - Current thread state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
+ * path that supports multiple acquires by the same thread.
+ *
+ * MUTEX: Interpreter must be locked
+ *
+ * NOTE: This interface is called from three places:
+ * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator
+ * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the
+ * global lock
+ * 3) From the external interface, acpi_acquire_global_lock
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_acquire_mutex_object(u16 timeout,
+ union acpi_operand_object *obj_desc,
+ acpi_thread_id thread_id)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc);
+
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Support for multiple acquires by the owning thread */
+
+ if (obj_desc->mutex.thread_id == thread_id) {
+ /*
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
+ */
+ obj_desc->mutex.acquisition_depth++;
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_acquire_global_lock(timeout);
+ } else {
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ timeout);
+ }
+
+ if (ACPI_FAILURE(status)) {
+
+ /* Includes failure from a timeout on time_desc */
+
+ return_ACPI_STATUS(status);
+ }
+
+ /* Acquired the mutex: update mutex object */
+
+ obj_desc->mutex.thread_id = thread_id;
+ obj_desc->mutex.acquisition_depth = 1;
+ obj_desc->mutex.original_sync_level = 0;
+ obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ex_acquire_mutex
*
* PARAMETERS: time_desc - Timeout integer
@@ -151,7 +224,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Sanity check: we must have a valid thread ID */
+ /* Must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -161,7 +234,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
}
/*
- * Current Sync must be less than or equal to the sync level of the
+ * Current sync level must be less than or equal to the sync level of the
* mutex. This mechanism provides some deadlock prevention
*/
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
@@ -172,51 +245,89 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Support for multiple acquires by the owning thread */
+ status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value,
+ obj_desc,
+ walk_state->thread->thread_id);
+ if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) {
- if (obj_desc->mutex.owner_thread) {
- if (obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->thread_id) {
- /*
- * The mutex is already owned by this thread, just increment the
- * acquisition depth
- */
- obj_desc->mutex.acquisition_depth++;
- return_ACPI_STATUS(AE_OK);
- }
+ /* Save Thread object, original/current sync levels */
+
+ obj_desc->mutex.owner_thread = walk_state->thread;
+ obj_desc->mutex.original_sync_level =
+ walk_state->thread->current_sync_level;
+ walk_state->thread->current_sync_level =
+ obj_desc->mutex.sync_level;
+
+ /* Link the mutex to the current thread for force-unlock at method exit */
+
+ acpi_ex_link_mutex(obj_desc, walk_state->thread);
}
- /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+ return_ACPI_STATUS(status);
+}
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- status =
- acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
- } else {
- status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
- (u16) time_desc->integer.
- value);
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_release_mutex_object
+ *
+ * PARAMETERS: obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release a previously acquired Mutex, low level interface.
+ * Provides a common path that supports multiple releases (after
+ * previous multiple acquires) by the same thread.
+ *
+ * MUTEX: Interpreter must be locked
+ *
+ * NOTE: This interface is called from three places:
+ * 1) From acpi_ex_release_mutex, via an AML Acquire() operator
+ * 2) From acpi_ex_release_global_lock when an AML Field access requires the
+ * global lock
+ * 3) From the external interface, acpi_release_global_lock
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ex_release_mutex_object);
+
+ if (obj_desc->mutex.acquisition_depth == 0) {
+ return (AE_NOT_ACQUIRED);
}
- if (ACPI_FAILURE(status)) {
+ /* Match multiple Acquires with multiple Releases */
- /* Includes failure from a timeout on time_desc */
+ obj_desc->mutex.acquisition_depth--;
+ if (obj_desc->mutex.acquisition_depth != 0) {
- return_ACPI_STATUS(status);
+ /* Just decrement the depth and return */
+
+ return_ACPI_STATUS(AE_OK);
}
- /* Have the mutex: update mutex and walk info and save the sync_level */
+ if (obj_desc->mutex.owner_thread) {
- obj_desc->mutex.owner_thread = walk_state->thread;
- obj_desc->mutex.acquisition_depth = 1;
- obj_desc->mutex.original_sync_level =
- walk_state->thread->current_sync_level;
+ /* Unlink the mutex from the owner's list */
- walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
+ acpi_ex_unlink_mutex(obj_desc);
+ obj_desc->mutex.owner_thread = NULL;
+ }
- /* Link the mutex to the current thread for force-unlock at method exit */
+ /* Release the mutex, special case for Global Lock */
- acpi_ex_link_mutex(obj_desc, walk_state->thread);
- return_ACPI_STATUS(AE_OK);
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ }
+
+ /* Clear mutex info */
+
+ obj_desc->mutex.thread_id = 0;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -253,22 +364,13 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Sanity check: we must have a valid thread ID */
-
- if (!walk_state->thread) {
- ACPI_ERROR((AE_INFO,
- "Cannot release Mutex [%4.4s], null thread info",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
- return_ACPI_STATUS(AE_AML_INTERNAL);
- }
-
/*
* The Mutex is owned, but this thread must be the owner.
* Special case for Global Lock, any thread can release
*/
if ((obj_desc->mutex.owner_thread->thread_id !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
+ && (obj_desc != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id,
@@ -278,45 +380,37 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
+ /* Must have a valid thread ID */
+
+ if (!walk_state->thread) {
+ ACPI_ERROR((AE_INFO,
+ "Cannot release Mutex [%4.4s], null thread info",
+ acpi_ut_get_node_name(obj_desc->mutex.node)));
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
/*
* The sync level of the mutex must be less than or equal to the current
* sync level
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
ACPI_ERROR((AE_INFO,
- "Cannot release Mutex [%4.4s], incorrect SyncLevel",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
+ "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
+ acpi_ut_get_node_name(obj_desc->mutex.node),
+ obj_desc->mutex.sync_level,
+ walk_state->thread->current_sync_level));
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Match multiple Acquires with multiple Releases */
-
- obj_desc->mutex.acquisition_depth--;
- if (obj_desc->mutex.acquisition_depth != 0) {
-
- /* Just decrement the depth and return */
-
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Unlink the mutex from the owner's list */
+ status = acpi_ex_release_mutex_object(obj_desc);
- acpi_ex_unlink_mutex(obj_desc);
+ if (obj_desc->mutex.acquisition_depth == 0) {
- /* Release the mutex, special case for Global Lock */
+ /* Restore the original sync_level */
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- status = acpi_ev_release_global_lock();
- } else {
- acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ walk_state->thread->current_sync_level =
+ obj_desc->mutex.original_sync_level;
}
-
- /* Update the mutex and restore sync_level */
-
- obj_desc->mutex.owner_thread = NULL;
- walk_state->thread->current_sync_level =
- obj_desc->mutex.original_sync_level;
-
return_ACPI_STATUS(status);
}
@@ -357,7 +451,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Release the mutex, special case for Global Lock */
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
/* Ignore errors */
@@ -369,6 +463,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Mark mutex unowned */
obj_desc->mutex.owner_thread = NULL;
+ obj_desc->mutex.thread_id = 0;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index 308eae52dc05..817e67be3697 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 252f10acbbcc..7c3bea575e02 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
if ((ACPI_FAILURE(status)) || walk_state->result_obj) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
} else {
/* Save the return value */
@@ -739,26 +740,38 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
value = acpi_gbl_integer_byte_width;
break;
- case ACPI_TYPE_BUFFER:
- value = temp_desc->buffer.length;
- break;
-
case ACPI_TYPE_STRING:
value = temp_desc->string.length;
break;
+ case ACPI_TYPE_BUFFER:
+
+ /* Buffer arguments may not be evaluated at this point */
+
+ status = acpi_ds_get_buffer_arguments(temp_desc);
+ value = temp_desc->buffer.length;
+ break;
+
case ACPI_TYPE_PACKAGE:
+
+ /* Package arguments may not be evaluated at this point */
+
+ status = acpi_ds_get_package_arguments(temp_desc);
value = temp_desc->package.count;
break;
default:
ACPI_ERROR((AE_INFO,
- "Operand is not Buf/Int/Str/Pkg - found type %s",
+ "Operand must be Buffer/Integer/String/Package - found type %s",
acpi_ut_get_type_name(type)));
status = AE_AML_OPERAND_TYPE;
goto cleanup;
}
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
/*
* Now that we have the size of the object, create a result
* object to hold the value
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 17e652e65379..8e8bbb6ccebd 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -241,10 +241,6 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
goto cleanup;
}
- /* Return the remainder */
-
- walk_state->result_obj = return_desc1;
-
cleanup:
/*
* Since the remainder is not returned indirectly, remove a reference to
@@ -259,6 +255,12 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
acpi_ut_remove_reference(return_desc1);
}
+ /* Save return object (the remainder) on success */
+
+ else {
+ walk_state->result_obj = return_desc1;
+ }
+
return_ACPI_STATUS(status);
}
@@ -490,6 +492,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
}
return_ACPI_STATUS(status);
@@ -583,8 +586,6 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
return_desc->integer.value = ACPI_INTEGER_MAX;
}
- walk_state->result_obj = return_desc;
-
cleanup:
/* Delete return object on error */
@@ -593,5 +594,11 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index 7fe67cf82cee..9cb4197681af 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -260,6 +260,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status) || walk_state->result_obj) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
}
/* Set the return object and exit */
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index bd80a9cb3d65..67d48737af53 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -322,8 +322,6 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
goto cleanup;
}
- walk_state->result_obj = return_desc;
-
cleanup:
/* Delete return object on error */
@@ -332,5 +330,11 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state)
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index efe5d4b461a4..3a2f8cd4c62a 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -412,6 +412,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *second_desc = NULL;
u32 type;
acpi_status status;
@@ -494,6 +495,20 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
obj_desc->field.access_byte_width,
obj_desc->bank_field.region_obj,
obj_desc->bank_field.bank_obj));
+
+ /*
+ * Remember location in AML stream of the field unit
+ * opcode and operands -- since the bank_value
+ * operands must be evaluated.
+ */
+ second_desc = obj_desc->common.next_object;
+ second_desc->extra.aml_start =
+ ((union acpi_parse_object *)(info->data_register_node))->
+ named.data;
+ second_desc->extra.aml_length =
+ ((union acpi_parse_object *)(info->data_register_node))->
+ named.length;
+
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3f51b7e84a17..7cd8bb54fa01 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -160,7 +160,7 @@ acpi_ex_system_memory_space_handler(u32 function,
if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
- ACPI_FORMAT_UINT64(address),
+ ACPI_FORMAT_NATIVE_UINT(address),
(u32) window_size));
mem_info->mapped_length = 0;
return_ACPI_STATUS(AE_NO_MEMORY);
@@ -182,7 +182,8 @@ acpi_ex_system_memory_space_handler(u32 function,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
- bit_width, function, ACPI_FORMAT_UINT64(address)));
+ bit_width, function,
+ ACPI_FORMAT_NATIVE_UINT(address)));
/*
* Perform the memory read or write
@@ -284,7 +285,8 @@ acpi_ex_system_io_space_handler(u32 function,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-IO (width %d) R/W %d Address=%8.8X%8.8X\n",
- bit_width, function, ACPI_FORMAT_UINT64(address)));
+ bit_width, function,
+ ACPI_FORMAT_NATIVE_UINT(address)));
/* Decode the function parameter */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 2b3a01cc4929..5596f42c9676 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,9 +116,11 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
* Several object types require no further processing:
* 1) Device/Thermal objects don't have a "real" subobject, return the Node
* 2) Method locals and arguments have a pseudo-Node
+ * 3) 10/2007: Added method type to assist with Package construction.
*/
if ((entry_type == ACPI_TYPE_DEVICE) ||
(entry_type == ACPI_TYPE_THERMAL) ||
+ (entry_type == ACPI_TYPE_METHOD) ||
(node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) {
return_ACPI_STATUS(AE_OK);
}
@@ -214,7 +216,6 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
/* For these objects, just return the object attached to the Node */
case ACPI_TYPE_MUTEX:
- case ACPI_TYPE_METHOD:
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_EVENT:
@@ -238,13 +239,12 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
case ACPI_TYPE_LOCAL_REFERENCE:
switch (source_desc->reference.opcode) {
- case AML_LOAD_OP:
+ case AML_LOAD_OP: /* This is a ddb_handle */
+ case AML_REF_OF_OP:
+ case AML_INDEX_OP:
- /* This is a ddb_handle */
/* Return an additional reference to the object */
- case AML_REF_OF_OP:
-
obj_desc = source_desc;
acpi_ut_add_reference(obj_desc);
break;
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6c64e55dab0e..b35f7c817acf 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -140,7 +140,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
{
acpi_status status = AE_OK;
union acpi_operand_object *stack_desc;
- void *temp_node;
union acpi_operand_object *obj_desc = NULL;
u16 opcode;
@@ -156,23 +155,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
opcode = stack_desc->reference.opcode;
switch (opcode) {
- case AML_NAME_OP:
-
- /*
- * Convert name reference to a namespace node
- * Then, acpi_ex_resolve_node_to_value can be used to get the value
- */
- temp_node = stack_desc->reference.object;
-
- /* Delete the Reference Object */
-
- acpi_ut_remove_reference(stack_desc);
-
- /* Return the namespace node */
-
- (*stack_ptr) = temp_node;
- break;
-
case AML_LOCAL_OP:
case AML_ARG_OP:
@@ -207,15 +189,25 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
switch (stack_desc->reference.target_type) {
case ACPI_TYPE_BUFFER_FIELD:
- /* Just return - leave the Reference on the stack */
+ /* Just return - do not dereference */
break;
case ACPI_TYPE_PACKAGE:
+ /* If method call or copy_object - do not dereference */
+
+ if ((walk_state->opcode ==
+ AML_INT_METHODCALL_OP)
+ || (walk_state->opcode == AML_COPY_OP)) {
+ break;
+ }
+
+ /* Otherwise, dereference the package_index to a package element */
+
obj_desc = *stack_desc->reference.where;
if (obj_desc) {
/*
- * Valid obj descriptor, copy pointer to return value
+ * Valid object descriptor, copy pointer to return value
* (i.e., dereference the package index)
* Delete the ref object, increment the returned object
*/
@@ -224,11 +216,11 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
*stack_ptr = obj_desc;
} else {
/*
- * A NULL object descriptor means an unitialized element of
+ * A NULL object descriptor means an uninitialized element of
* the package, can't dereference it
*/
ACPI_ERROR((AE_INFO,
- "Attempt to deref an Index to NULL pkg element Idx=%p",
+ "Attempt to dereference an Index to NULL package element Idx=%p",
stack_desc));
status = AE_AML_UNINITIALIZED_ELEMENT;
}
@@ -239,7 +231,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
/* Invalid reference object */
ACPI_ERROR((AE_INFO,
- "Unknown TargetType %X in Index/Reference obj %p",
+ "Unknown TargetType %X in Index/Reference object %p",
stack_desc->reference.target_type,
stack_desc));
status = AE_AML_INTERNAL;
@@ -251,7 +243,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
case AML_DEBUG_OP:
case AML_LOAD_OP:
- /* Just leave the object as-is */
+ /* Just leave the object as-is, do not dereference */
break;
@@ -390,10 +382,10 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
/*
- * For reference objects created via the ref_of or Index operators,
- * we need to get to the base object (as per the ACPI specification
- * of the object_type and size_of operators). This means traversing
- * the list of possibly many nested references.
+ * For reference objects created via the ref_of, Index, or Load/load_table
+ * operators, we need to get to the base object (as per the ACPI
+ * specification of the object_type and size_of operators). This means
+ * traversing the list of possibly many nested references.
*/
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
switch (obj_desc->reference.opcode) {
@@ -463,6 +455,11 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
}
break;
+ case AML_LOAD_OP:
+
+ type = ACPI_TYPE_DDB_HANDLE;
+ goto exit;
+
case AML_LOCAL_OP:
case AML_ARG_OP:
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 09d897b3f6d5..73e29e566a70 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -137,7 +137,6 @@ acpi_ex_resolve_operands(u16 opcode,
union acpi_operand_object *obj_desc;
acpi_status status = AE_OK;
u8 object_type;
- void *temp_node;
u32 arg_types;
const struct acpi_opcode_info *op_info;
u32 this_arg_type;
@@ -239,7 +238,6 @@ acpi_ex_resolve_operands(u16 opcode,
/*lint -fallthrough */
- case AML_NAME_OP:
case AML_INDEX_OP:
case AML_REF_OF_OP:
case AML_ARG_OP:
@@ -332,15 +330,6 @@ acpi_ex_resolve_operands(u16 opcode,
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
- if (obj_desc->reference.opcode == AML_NAME_OP) {
-
- /* Convert a named reference to the actual named object */
-
- temp_node = obj_desc->reference.object;
- acpi_ut_remove_reference(obj_desc);
- (*stack_ptr) = temp_node;
- }
goto next_operand;
case ARGI_DATAREFOBJ: /* Store operator only */
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index f4b69a637820..76c875bc3154 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,8 +84,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc);
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
- level, " "));
+ /* Print line header as long as we are not in the middle of an object display */
+
+ if (!((level > 0) && index == 0)) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
+ level, " "));
+ }
/* Display index for package output only */
@@ -95,12 +99,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
}
if (!source_desc) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "<Null Object>\n"));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[Null Object]\n"));
return_VOID;
}
if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s: ",
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s ",
acpi_ut_get_object_type_name
(source_desc)));
@@ -123,6 +127,8 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
return_VOID;
}
+ /* source_desc is of type ACPI_DESC_TYPE_OPERAND */
+
switch (ACPI_GET_OBJECT_TYPE(source_desc)) {
case ACPI_TYPE_INTEGER:
@@ -147,7 +153,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
(u32) source_desc->buffer.length));
ACPI_DUMP_BUFFER(source_desc->buffer.pointer,
(source_desc->buffer.length <
- 32) ? source_desc->buffer.length : 32);
+ 256) ? source_desc->buffer.length : 256);
break;
case ACPI_TYPE_STRING:
@@ -160,7 +166,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
case ACPI_TYPE_PACKAGE:
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
- "[0x%.2X Elements]\n",
+ "[Contains 0x%.2X Elements]\n",
source_desc->package.count));
/* Output the entire contents of the package */
@@ -180,12 +186,59 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
(source_desc->reference.opcode),
source_desc->reference.offset));
} else {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]\n",
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]",
acpi_ps_get_opcode_name
(source_desc->reference.opcode)));
}
- if (source_desc->reference.object) {
+ if (source_desc->reference.opcode == AML_LOAD_OP) { /* Load and load_table */
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ " Table OwnerId %p\n",
+ source_desc->reference.object));
+ break;
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, " "));
+
+ /* Check for valid node first, then valid object */
+
+ if (source_desc->reference.node) {
+ if (ACPI_GET_DESCRIPTOR_TYPE
+ (source_desc->reference.node) !=
+ ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ " %p - Not a valid namespace node\n",
+ source_desc->reference.
+ node));
+ } else {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ "Node %p [%4.4s] ",
+ source_desc->reference.
+ node,
+ (source_desc->reference.
+ node)->name.ascii));
+
+ switch ((source_desc->reference.node)->type) {
+
+ /* These types have no attached object */
+
+ case ACPI_TYPE_DEVICE:
+ acpi_os_printf("Device\n");
+ break;
+
+ case ACPI_TYPE_THERMAL:
+ acpi_os_printf("Thermal Zone\n");
+ break;
+
+ default:
+ acpi_ex_do_debug_object((source_desc->
+ reference.
+ node)->object,
+ level + 4, 0);
+ break;
+ }
+ }
+ } else if (source_desc->reference.object) {
if (ACPI_GET_DESCRIPTOR_TYPE
(source_desc->reference.object) ==
ACPI_DESC_TYPE_NAMED) {
@@ -198,18 +251,13 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
acpi_ex_do_debug_object(source_desc->reference.
object, level + 4, 0);
}
- } else if (source_desc->reference.node) {
- acpi_ex_do_debug_object((source_desc->reference.node)->
- object, level + 4, 0);
}
break;
default:
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p %s\n",
- source_desc,
- acpi_ut_get_object_type_name
- (source_desc)));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p\n",
+ source_desc));
break;
}
@@ -313,7 +361,6 @@ acpi_ex_store(union acpi_operand_object *source_desc,
* 4) Store to the debug object
*/
switch (ref_desc->reference.opcode) {
- case AML_NAME_OP:
case AML_REF_OF_OP:
/* Storing an object into a Name "container" */
@@ -415,11 +462,24 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
*/
obj_desc = *(index_desc->reference.where);
- status =
- acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
- walk_state);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if (ACPI_GET_OBJECT_TYPE(source_desc) ==
+ ACPI_TYPE_LOCAL_REFERENCE
+ && source_desc->reference.opcode == AML_LOAD_OP) {
+
+ /* This is a DDBHandle, just add a reference to it */
+
+ acpi_ut_add_reference(source_desc);
+ new_desc = source_desc;
+ } else {
+ /* Normal object, copy it */
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(source_desc,
+ &new_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
if (obj_desc) {
@@ -571,10 +631,17 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
/* If no implicit conversion, drop into the default case below */
- if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {
-
- /* Force execution of default (no implicit conversion) */
-
+ if ((!implicit_conversion) ||
+ ((walk_state->opcode == AML_COPY_OP) &&
+ (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) &&
+ (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) &&
+ (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) {
+ /*
+ * Force execution of default (no implicit conversion). Note:
+ * copy_object does not perform an implicit conversion, as per the ACPI
+ * spec -- except in case of region/bank/index fields -- because these
+ * objects must retain their original type permanently.
+ */
target_type = ACPI_TYPE_ANY;
}
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 1d622c625c64..a6d2168b81f9 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 8233d40178ee..9a75ff09fb0c 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 9460baff3032..68990f1df371 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
-#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exsystem")
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 6b0aeccbb69b..86c03880b523 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
-#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exutils")
@@ -217,9 +216,10 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
/*
* Object must be a valid number and we must be executing
- * a control method
+ * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
*/
if ((!obj_desc) ||
+ (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) ||
(ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) {
return;
}
@@ -240,72 +240,73 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
* PARAMETERS: field_flags - Flags with Lock rule:
* always_lock or never_lock
*
- * RETURN: TRUE/FALSE indicating whether the lock was actually acquired
+ * RETURN: None
*
- * DESCRIPTION: Obtain the global lock and keep track of this fact via two
- * methods. A global variable keeps the state of the lock, and
- * the state is returned to the caller.
+ * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
+ * flags specifiy that it is to be obtained before field access.
*
******************************************************************************/
-u8 acpi_ex_acquire_global_lock(u32 field_flags)
+void acpi_ex_acquire_global_lock(u32 field_flags)
{
- u8 locked = FALSE;
acpi_status status;
ACPI_FUNCTION_TRACE(ex_acquire_global_lock);
- /* Only attempt lock if the always_lock bit is set */
+ /* Only use the lock if the always_lock bit is set */
+
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
+ }
- if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
+ /* Attempt to get the global lock, wait forever */
- /* We should attempt to get the lock, wait forever */
+ status = acpi_ex_acquire_mutex_object(ACPI_WAIT_FOREVER,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
- status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
- if (ACPI_SUCCESS(status)) {
- locked = TRUE;
- } else {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire Global Lock"));
- }
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not acquire Global Lock"));
}
- return_UINT8(locked);
+ return_VOID;
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_release_global_lock
*
- * PARAMETERS: locked_by_me - Return value from corresponding call to
- * acquire_global_lock.
+ * PARAMETERS: field_flags - Flags with Lock rule:
+ * always_lock or never_lock
*
* RETURN: None
*
- * DESCRIPTION: Release the global lock if it is locked.
+ * DESCRIPTION: Release the ACPI hardware Global Lock
*
******************************************************************************/
-void acpi_ex_release_global_lock(u8 locked_by_me)
+void acpi_ex_release_global_lock(u32 field_flags)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ex_release_global_lock);
- /* Only attempt unlock if the caller locked it */
+ /* Only use the lock if the always_lock bit is set */
- if (locked_by_me) {
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
+ }
- /* OK, now release the lock */
+ /* Release the global lock */
- status = acpi_ev_release_global_lock();
- if (ACPI_FAILURE(status)) {
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
+ if (ACPI_FAILURE(status)) {
- /* Report the error, but there isn't much else we can do */
+ /* Report the error, but there isn't much else we can do */
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not release ACPI Global Lock"));
- }
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not release Global Lock"));
}
return_VOID;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index c8e3cba423ef..cf635cde836b 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -260,24 +260,23 @@ static int acpi_fan_add(struct acpi_device *device)
result = PTR_ERR(cdev);
goto end;
}
- if (cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev.bus_id, cdev->id);
-
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
-
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- return result;
- }
+
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, cdev->id);
+
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
result = acpi_fan_add_fs(device);
if (result)
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index eda0978b57c6..06f8634fe58b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -142,6 +142,7 @@ EXPORT_SYMBOL(acpi_get_physical_device);
static int acpi_bind_one(struct device *dev, acpi_handle handle)
{
+ struct acpi_device *acpi_dev;
acpi_status status;
if (dev->archdata.acpi_handle) {
@@ -157,6 +158,16 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
}
dev->archdata.acpi_handle = handle;
+ status = acpi_bus_get_device(handle, &acpi_dev);
+ if (!ACPI_FAILURE(status)) {
+ int ret;
+
+ ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
+ "firmware_node");
+ ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
+ "physical_node");
+ }
+
return 0;
}
@@ -165,8 +176,17 @@ static int acpi_unbind_one(struct device *dev)
if (!dev->archdata.acpi_handle)
return 0;
if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
+ struct acpi_device *acpi_dev;
+
/* acpi_get_physical_device increase refcnt by one */
put_device(dev);
+
+ if (!acpi_bus_get_device(dev->archdata.acpi_handle,
+ &acpi_dev)) {
+ sysfs_remove_link(&dev->kobj, "firmware_node");
+ sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
+ }
+
acpi_detach_data(dev->archdata.acpi_handle,
acpi_glue_data_handler);
dev->archdata.acpi_handle = NULL;
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index 6031ca13dd2f..816894ea839e 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 117a05cadaaa..14bc4f456ae8 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index 73f9c5fb1ba7..ddf792adcf96 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 4290e0193097..d9937e05ec6a 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,9 +70,10 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
/* Get the FACS */
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -124,9 +125,10 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
/* Get the FACS */
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c32eab696acd..b53d575491b9 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index 57faf598bad8..c39a7f68b889 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -208,8 +208,7 @@ acpi_status acpi_ns_root_initialize(void)
/* Special case for ACPI Global Lock */
if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
- acpi_gbl_global_lock_mutex =
- obj_desc->mutex.os_mutex;
+ acpi_gbl_global_lock_mutex = obj_desc;
/* Create additional counting semaphore for global lock */
@@ -582,44 +581,68 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
return_ACPI_STATUS(status);
}
- /*
- * Sanity typecheck of the target object:
- *
- * If 1) This is the last segment (num_segments == 0)
- * 2) And we are looking for a specific type
- * (Not checking for TYPE_ANY)
- * 3) Which is not an alias
- * 4) Which is not a local type (TYPE_SCOPE)
- * 5) And the type of target object is known (not TYPE_ANY)
- * 6) And target object does not match what we are looking for
- *
- * Then we have a type mismatch. Just warn and ignore it.
- */
- if ((num_segments == 0) &&
- (type_to_check_for != ACPI_TYPE_ANY) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) &&
- (this_node->type != ACPI_TYPE_ANY) &&
- (this_node->type != type_to_check_for)) {
-
- /* Complain about a type mismatch */
-
- ACPI_WARNING((AE_INFO,
- "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
- ACPI_CAST_PTR(char, &simple_name),
- acpi_ut_get_type_name(this_node->type),
- acpi_ut_get_type_name
- (type_to_check_for)));
+ /* More segments to follow? */
+
+ if (num_segments > 0) {
+ /*
+ * If we have an alias to an object that opens a scope (such as a
+ * device or processor), we need to dereference the alias here so that
+ * we can access any children of the original node (via the remaining
+ * segments).
+ */
+ if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) {
+ if (acpi_ns_opens_scope
+ (((struct acpi_namespace_node *)this_node->
+ object)->type)) {
+ this_node =
+ (struct acpi_namespace_node *)
+ this_node->object;
+ }
+ }
}
- /*
- * If this is the last name segment and we are not looking for a
- * specific type, but the type of found object is known, use that type
- * to see if it opens a scope.
- */
- if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) {
- type = this_node->type;
+ /* Special handling for the last segment (num_segments == 0) */
+
+ else {
+ /*
+ * Sanity typecheck of the target object:
+ *
+ * If 1) This is the last segment (num_segments == 0)
+ * 2) And we are looking for a specific type
+ * (Not checking for TYPE_ANY)
+ * 3) Which is not an alias
+ * 4) Which is not a local type (TYPE_SCOPE)
+ * 5) And the type of target object is known (not TYPE_ANY)
+ * 6) And target object does not match what we are looking for
+ *
+ * Then we have a type mismatch. Just warn and ignore it.
+ */
+ if ((type_to_check_for != ACPI_TYPE_ANY) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS)
+ && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE)
+ && (this_node->type != ACPI_TYPE_ANY)
+ && (this_node->type != type_to_check_for)) {
+
+ /* Complain about a type mismatch */
+
+ ACPI_WARNING((AE_INFO,
+ "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
+ ACPI_CAST_PTR(char, &simple_name),
+ acpi_ut_get_type_name(this_node->
+ type),
+ acpi_ut_get_type_name
+ (type_to_check_for)));
+ }
+
+ /*
+ * If this is the last name segment and we are not looking for a
+ * specific type, but the type of found object is known, use that type
+ * to (later) see if it opens a scope.
+ */
+ if (type == ACPI_TYPE_ANY) {
+ type = this_node->type;
+ }
}
/* Point to next name segment and make this node current */
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 1d693d8ad2d8..3a1740ac2edc 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index 1fc4f86676e1..5445751b8a3e 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -249,7 +249,9 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
acpi_os_printf("ID %X Len %.4X Addr %p\n",
obj_desc->processor.proc_id,
obj_desc->processor.length,
- (char *)obj_desc->processor.address);
+ ACPI_CAST_PTR(void,
+ obj_desc->processor.
+ address));
break;
case ACPI_TYPE_DEVICE:
@@ -320,9 +322,8 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
space_id));
if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n",
- ACPI_FORMAT_UINT64(obj_desc->
- region.
- address),
+ ACPI_FORMAT_NATIVE_UINT
+ (obj_desc->region.address),
obj_desc->region.length);
} else {
acpi_os_printf
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index 5097e167939e..428f50fde11a 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 97b2ac57c16b..14bdfa92bea0 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index 33db2241044e..6d6d930c8e18 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -244,6 +244,10 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
info->field_count++;
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ info->field_count++;
+ break;
+
case ACPI_TYPE_BUFFER:
info->buffer_count++;
break;
@@ -287,6 +291,12 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
status = acpi_ds_get_buffer_field_arguments(obj_desc);
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ info->field_init++;
+ status = acpi_ds_get_bank_field_arguments(obj_desc);
+ break;
+
case ACPI_TYPE_BUFFER:
info->buffer_init++;
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index d4f9654fd20f..2c92f6cf5ce1 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,11 +107,11 @@ acpi_ns_load_table(acpi_native_uint table_index,
goto unlock;
}
- status = acpi_ns_parse_table(table_index, node->child);
+ status = acpi_ns_parse_table(table_index, node);
if (ACPI_SUCCESS(status)) {
acpi_tb_set_table_loaded_flag(table_index, TRUE);
} else {
- acpi_tb_release_owner_id(table_index);
+ (void)acpi_tb_release_owner_id(table_index);
}
unlock:
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index cbd94af08cc5..cffef1bcbdbc 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -180,6 +180,12 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
next_node = node;
while (next_node && (next_node != acpi_gbl_root_node)) {
+ if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid NS Node (%p) while traversing path",
+ next_node));
+ return 0;
+ }
size += ACPI_PATH_SEGMENT_LENGTH;
next_node = acpi_ns_get_parent_node(next_node);
}
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index d9d7377bc6e6..15fe09e24f71 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index e696aa847990..46a79b0103b6 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,8 @@ ACPI_MODULE_NAME("nsparse")
******************************************************************************/
acpi_status
acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index)
+ acpi_native_uint table_index,
+ struct acpi_namespace_node * start_node)
{
union acpi_parse_object *parse_root;
acpi_status status;
@@ -111,14 +112,25 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number,
aml_start = (u8 *) table + sizeof(struct acpi_table_header);
aml_length = table->length - sizeof(struct acpi_table_header);
status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
- aml_start, aml_length, NULL,
- (u8) pass_number);
+ aml_start, (u32) aml_length,
+ NULL, (u8) pass_number);
}
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
- acpi_ps_delete_parse_tree(parse_root);
- return_ACPI_STATUS(status);
+ goto cleanup;
+ }
+
+ /* start_node is the default location to load the table */
+
+ if (start_node && start_node != acpi_gbl_root_node) {
+ status =
+ acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
}
/* Parse the AML */
@@ -127,6 +139,7 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number,
(unsigned)pass_number));
status = acpi_ps_parse_aml(walk_state);
+ cleanup:
acpi_ps_delete_parse_tree(parse_root);
return_ACPI_STATUS(status);
}
@@ -163,7 +176,9 @@ acpi_ns_parse_table(acpi_native_uint table_index,
* performs another complete parse of the AML.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
- status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
+ status =
+ acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index,
+ start_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -178,7 +193,9 @@ acpi_ns_parse_table(acpi_native_uint table_index,
* parse objects are all cached.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
- status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
+ status =
+ acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index,
+ start_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index e863be665ce8..8399276cba1e 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 90fd059615ff..64c039843ed2 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index 280b8357c46c..3c905ce26d7d 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,9 +77,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct
/* It's really the parent's _scope_ that we want */
- if (parent_node->child) {
- next_node = parent_node->child;
- }
+ next_node = parent_node->child;
}
else {
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index b92133faf5b7..a8d549187c84 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -467,10 +467,13 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
return (AE_CTRL_DEPTH);
}
- if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
-
- /* Don't examine children of the device if not present */
-
+ if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
+ !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
+ /*
+ * Don't examine the children of the device only when the
+ * device is neither present nor functional. See ACPI spec,
+ * description of _STA for more information.
+ */
return (AE_CTRL_DEPTH);
}
@@ -539,7 +542,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
* value is returned to the caller.
*
* This is a wrapper for walk_namespace, but the callback performs
- * additional filtering. Please see acpi_get_device_callback.
+ * additional filtering. Please see acpi_ns_get_device_callback.
*
******************************************************************************/
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index b489781b22a8..a287ed550f54 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index faa375887201..2b375ee80cef 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index a498a6cc68fe..235a1386888a 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -742,6 +742,7 @@ EXPORT_SYMBOL(acpi_os_execute);
void acpi_os_wait_events_complete(void *context)
{
flush_workqueue(kacpid_wq);
+ flush_workqueue(kacpi_notify_wq);
}
EXPORT_SYMBOL(acpi_os_wait_events_complete);
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index c2b9835c890b..f1e8bf65e24e 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -230,12 +230,12 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
struct acpi_parse_state *parser_state,
union acpi_parse_object *arg, u8 possible_method_call)
{
+ acpi_status status;
char *path;
union acpi_parse_object *name_op;
- acpi_status status;
union acpi_operand_object *method_desc;
struct acpi_namespace_node *node;
- union acpi_generic_state scope_info;
+ u8 *start = parser_state->aml;
ACPI_FUNCTION_TRACE(ps_get_next_namepath);
@@ -249,25 +249,18 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_OK);
}
- /* Setup search scope info */
-
- scope_info.scope.node = NULL;
- node = parser_state->start_node;
- if (node) {
- scope_info.scope.node = node;
- }
-
/*
- * Lookup the name in the internal namespace. We don't want to add
- * anything new to the namespace here, however, so we use MODE_EXECUTE.
+ * Lookup the name in the internal namespace, starting with the current
+ * scope. We don't want to add anything new to the namespace here,
+ * however, so we use MODE_EXECUTE.
* Allow searching of the parent tree, but don't open a new scope -
* we just want to lookup the object (must be mode EXECUTE to perform
* the upsearch)
*/
- status =
- acpi_ns_lookup(&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
- ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
- NULL, &node);
+ status = acpi_ns_lookup(walk_state->scope_info, path,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ NULL, &node);
/*
* If this name is a control method invocation, we must
@@ -275,6 +268,16 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
+ if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ /*
+ * acpi_ps_get_next_namestring has increased the AML pointer,
+ * so we need to restore the saved AML pointer for method call.
+ */
+ walk_state->parser_state.aml = start;
+ walk_state->arg_count = 1;
+ acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
+ return_ACPI_STATUS(AE_OK);
+ }
/* This name is actually a control method invocation */
@@ -686,9 +689,29 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status =
- acpi_ps_get_next_namepath(walk_state, parser_state,
- arg, 0);
+ /* To support super_name arg of Unload */
+
+ if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ parser_state, arg,
+ 1);
+
+ /*
+ * If the super_name arg of Unload is a method call,
+ * we have restored the AML pointer, just free this Arg
+ */
+ if (arg->common.aml_opcode ==
+ AML_INT_METHODCALL_OP) {
+ acpi_ps_free_op(arg);
+ arg = NULL;
+ }
+ } else {
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ parser_state, arg,
+ 0);
+ }
} else {
/* Single complex argument, nothing returned */
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index 773aee82fbb8..c06238e55d98 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -182,6 +182,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.arg_list_length = 0;
unnamed_op->common.aml_opcode = walk_state->opcode;
/*
@@ -241,7 +242,8 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
acpi_gbl_depth++;
- if ((*op)->common.aml_opcode == AML_REGION_OP) {
+ if ((*op)->common.aml_opcode == AML_REGION_OP ||
+ (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
/*
* Defer final parsing of an operation_region body, because we don't
* have enough info in the first pass to parse it correctly (i.e.,
@@ -280,6 +282,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
acpi_status status = AE_OK;
union acpi_parse_object *op;
union acpi_parse_object *named_op = NULL;
+ union acpi_parse_object *parent_scope;
+ u8 argument_count;
+ const struct acpi_opcode_info *op_info;
ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
@@ -320,8 +325,32 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
op->named.length = 0;
}
- acpi_ps_append_arg(acpi_ps_get_parent_scope
- (&(walk_state->parser_state)), op);
+ if (walk_state->opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+
+ parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
+ acpi_ps_append_arg(parent_scope, op);
+
+ if (parent_scope) {
+ op_info =
+ acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
+ if (op_info->flags & AML_HAS_TARGET) {
+ argument_count =
+ acpi_ps_get_argument_count(op_info->type);
+ if (parent_scope->common.arg_list_length >
+ argument_count) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ }
if (walk_state->descending_callback != NULL) {
/*
@@ -603,13 +632,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
acpi_ps_pop_scope(&(walk_state->parser_state), op,
&walk_state->arg_types,
&walk_state->arg_count);
-
- if ((*op)->common.aml_opcode != AML_WHILE_OP) {
- status2 = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
}
/* Close this iteration of the While loop */
@@ -640,10 +662,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
if (ACPI_FAILURE(status2)) {
return_ACPI_STATUS(status2);
}
- status2 = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
acpi_ut_delete_generic_state
(acpi_ut_pop_generic_state
@@ -1005,7 +1023,8 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
acpi_gbl_depth--;
}
- if (op->common.aml_opcode == AML_REGION_OP) {
+ if (op->common.aml_opcode == AML_REGION_OP ||
+ op->common.aml_opcode == AML_DATA_REGION_OP) {
/*
* Skip parsing of control method or opregion body,
* because we don't have enough info in the first pass
@@ -1030,6 +1049,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
(u32) (parser_state->aml - op->named.data);
}
+ if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ *
+ * body_length is unknown until we parse the body
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+
/* This op complete, notify the dispatcher */
if (walk_state->ascending_callback != NULL) {
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 9296e86761d7..f425ab30eae8 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,9 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psopcode")
+static const u8 acpi_gbl_argument_count[] =
+ { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
+
/*******************************************************************************
*
* NAME: acpi_gbl_aml_op_info
@@ -59,6 +62,7 @@ ACPI_MODULE_NAME("psopcode")
* the operand type.
*
******************************************************************************/
+
/*
* Summary of opcode types/flags
*
@@ -176,6 +180,7 @@ ACPI_MODULE_NAME("psopcode")
AML_CREATE_QWORD_FIELD_OP
******************************************************************************/
+
/*
* Master Opcode information table. A summary of everything we know about each
* opcode, all in one place.
@@ -515,9 +520,10 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
AML_TYPE_NAMED_FIELD,
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
/* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP,
- ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+ ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT,
AML_TYPE_NAMED_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD |
+ AML_DEFER),
/* Internal opcodes that map to invalid AML opcodes */
@@ -619,9 +625,9 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
/* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP,
ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ AML_NSNODE | AML_NAMED | AML_DEFER),
/* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
AML_TYPE_NAMED_NO_OBJ,
@@ -779,3 +785,25 @@ char *acpi_ps_get_opcode_name(u16 opcode)
#endif
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_argument_count
+ *
+ * PARAMETERS: op_type - Type associated with the AML opcode
+ *
+ * RETURN: Argument count
+ *
+ * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
+ *
+ ******************************************************************************/
+
+u8 acpi_ps_get_argument_count(u32 op_type)
+{
+
+ if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
+ return (acpi_gbl_argument_count[op_type]);
+ }
+
+ return (0);
+}
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index 5d63f48e56b5..15e1702e48d6 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,6 +205,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|| (op->common.parent->common.aml_opcode ==
AML_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)
+ || (op->common.parent->common.aml_opcode ==
AML_VAR_PACKAGE_OP)) {
replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
@@ -349,19 +351,13 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
parser_state->aml = walk_state->aml_last_while;
walk_state->control_state->common.value = FALSE;
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_BREAK;
- }
+ status = AE_CTRL_BREAK;
break;
case AE_CTRL_CONTINUE:
parser_state->aml = walk_state->aml_last_while;
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_CONTINUE;
- }
+ status = AE_CTRL_CONTINUE;
break;
case AE_CTRL_PENDING:
@@ -383,10 +379,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
* Just close out this package
*/
parser_state->aml = acpi_ps_get_next_package_end(parser_state);
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_PENDING;
- }
+ status = AE_CTRL_PENDING;
break;
case AE_CTRL_FALSE:
@@ -541,7 +534,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
if ((status == AE_ALREADY_EXISTS) &&
(!walk_state->method_desc->method.mutex)) {
ACPI_INFO((AE_INFO,
- "Marking method %4.4s as Serialized",
+ "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
walk_state->method_node->name.
ascii));
@@ -601,6 +594,30 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
* The object is deleted
*/
if (!previous_walk_state->return_desc) {
+ /*
+ * In slack mode execution, if there is no return value
+ * we should implicitly return zero (0) as a default value.
+ */
+ if (acpi_gbl_enable_interpreter_slack &&
+ !previous_walk_state->
+ implicit_return_obj) {
+ previous_walk_state->
+ implicit_return_obj =
+ acpi_ut_create_internal_object
+ (ACPI_TYPE_INTEGER);
+ if (!previous_walk_state->
+ implicit_return_obj) {
+ return_ACPI_STATUS
+ (AE_NO_MEMORY);
+ }
+
+ previous_walk_state->
+ implicit_return_obj->
+ integer.value = 0;
+ }
+
+ /* Restart the calling control method */
+
status =
acpi_ds_restart_control_method
(walk_state,
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index 77cfa4ed0cfe..ee50e67c9443 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 966e7ea2a0c4..1dd355ddd182 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -171,6 +171,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
while (arg) {
arg->common.parent = op;
arg = arg->common.next;
+
+ op->common.arg_list_length++;
}
}
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index 8ca52002db55..7cf1f65cd5bb 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index 49f9757434e4..8b86ad5a3201 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 94103bced75e..52581454c47c 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 76bf6d90c700..f2a76acecfcd 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -121,7 +121,7 @@ acpi_power_get_context(acpi_handle handle,
}
*resource = acpi_driver_data(device);
- if (!resource)
+ if (!*resource)
return -ENODEV;
return 0;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a825b431b64f..ea5f628dcc15 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -674,22 +674,21 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
result = PTR_ERR(pr->cdev);
goto end;
}
- if (pr->cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev.bus_id, pr->cdev->id);
-
- result = sysfs_create_link(&device->dev.kobj,
- &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
- result = sysfs_create_link(&pr->cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- return result;
- }
+
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports",
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 788da9781f80..55d69dce47c4 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -418,13 +418,12 @@ static void acpi_processor_idle(void)
cx = pr->power.state;
if (!cx || acpi_idle_suspend) {
- if (pm_idle_save)
- pm_idle_save();
- else
+ if (pm_idle_save) {
+ pm_idle_save(); /* enables IRQs */
+ } else {
acpi_safe_halt();
-
- if (irqs_disabled())
local_irq_enable();
+ }
return;
}
@@ -520,10 +519,12 @@ static void acpi_processor_idle(void)
* Use the appropriate idle routine, the one that would
* be used without acpi C-states.
*/
- if (pm_idle_save)
- pm_idle_save();
- else
+ if (pm_idle_save) {
+ pm_idle_save(); /* enables IRQs */
+ } else {
acpi_safe_halt();
+ local_irq_enable();
+ }
/*
* TBD: Can't get time duration while in C1, as resumes
@@ -534,8 +535,6 @@ static void acpi_processor_idle(void)
* skew otherwise.
*/
sleep_ticks = 0xFFFFFFFF;
- if (irqs_disabled())
- local_irq_enable();
break;
@@ -848,6 +847,7 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
/* all processors need to support C1 */
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
pr->power.states[ACPI_STATE_C1].valid = 1;
+ pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT;
}
/* the C0 state only exists as a filler in our array */
pr->power.states[ACPI_STATE_C0].valid = 1;
@@ -960,6 +960,9 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
cx.address);
}
+ if (cx.type == ACPI_STATE_C1) {
+ cx.valid = 1;
+ }
obj = &(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
@@ -1295,6 +1298,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int result = 0;
+ if (boot_option_idle_override)
+ return 0;
if (!pr)
return -EINVAL;
@@ -1734,6 +1739,9 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int ret;
+ if (boot_option_idle_override)
+ return 0;
+
if (!pr)
return -EINVAL;
@@ -1764,6 +1772,8 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct proc_dir_entry *entry = NULL;
unsigned int i;
+ if (boot_option_idle_override)
+ return 0;
if (!first_run) {
dmi_check_system(processor_power_dmi_table);
@@ -1799,7 +1809,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
* Note that we use previously set idle handler will be used on
* platforms that only support C1.
*/
- if ((pr->flags.power) && (!boot_option_idle_override)) {
+ if (pr->flags.power) {
#ifdef CONFIG_CPU_IDLE
acpi_processor_setup_cpuidle(pr);
pr->power.dev.cpu = pr->id;
@@ -1839,8 +1849,11 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
+ if (boot_option_idle_override)
+ return 0;
+
#ifdef CONFIG_CPU_IDLE
- if ((pr->flags.power) && (!boot_option_idle_override))
+ if (pr->flags.power)
cpuidle_unregister_device(&pr->power.dev);
#endif
pr->flags.power_setup_done = 0;
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 9cb43f52f7b6..649ae99b9216 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -97,7 +97,7 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
#define CPUFREQ_THERMAL_MIN_STEP 0
#define CPUFREQ_THERMAL_MAX_STEP 3
-static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
+static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
static unsigned int acpi_thermal_cpufreq_is_init = 0;
static int cpu_has_cpufreq(unsigned int cpu)
@@ -113,9 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu)
if (!cpu_has_cpufreq(cpu))
return -ENODEV;
- if (cpufreq_thermal_reduction_pctg[cpu] <
+ if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) <
CPUFREQ_THERMAL_MAX_STEP) {
- cpufreq_thermal_reduction_pctg[cpu]++;
+ per_cpu(cpufreq_thermal_reduction_pctg, cpu)++;
cpufreq_update_policy(cpu);
return 0;
}
@@ -128,14 +128,14 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
if (!cpu_has_cpufreq(cpu))
return -ENODEV;
- if (cpufreq_thermal_reduction_pctg[cpu] >
+ if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) >
(CPUFREQ_THERMAL_MIN_STEP + 1))
- cpufreq_thermal_reduction_pctg[cpu]--;
+ per_cpu(cpufreq_thermal_reduction_pctg, cpu)--;
else
- cpufreq_thermal_reduction_pctg[cpu] = 0;
+ per_cpu(cpufreq_thermal_reduction_pctg, cpu) = 0;
cpufreq_update_policy(cpu);
/* We reached max freq again and can leave passive mode */
- return !cpufreq_thermal_reduction_pctg[cpu];
+ return !per_cpu(cpufreq_thermal_reduction_pctg, cpu);
}
static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
@@ -147,9 +147,10 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
if (event != CPUFREQ_ADJUST)
goto out;
- max_freq =
- (policy->cpuinfo.max_freq *
- (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
+ max_freq = (
+ policy->cpuinfo.max_freq *
+ (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20)
+ ) / 100;
cpufreq_verify_within_limits(policy, 0, max_freq);
@@ -174,7 +175,7 @@ static int cpufreq_get_cur_state(unsigned int cpu)
if (!cpu_has_cpufreq(cpu))
return 0;
- return cpufreq_thermal_reduction_pctg[cpu];
+ return per_cpu(cpufreq_thermal_reduction_pctg, cpu);
}
static int cpufreq_set_cur_state(unsigned int cpu, int state)
@@ -182,7 +183,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
if (!cpu_has_cpufreq(cpu))
return 0;
- cpufreq_thermal_reduction_pctg[cpu] = state;
+ per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state;
cpufreq_update_policy(cpu);
return 0;
}
@@ -191,8 +192,9 @@ void acpi_thermal_cpufreq_init(void)
{
int i;
- for (i = 0; i < NR_CPUS; i++)
- cpufreq_thermal_reduction_pctg[i] = 0;
+ for (i = 0; i < nr_cpu_ids; i++)
+ if (cpu_present(i))
+ per_cpu(cpufreq_thermal_reduction_pctg, i) = 0;
i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 271e61509eeb..7f96332822bf 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index 0dd2ce8a3475..8a112d11d491 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,7 @@ acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length);
static u8 acpi_rs_count_set_bits(u16 bit_field)
{
- u8 bits_set;
+ acpi_native_uint bits_set;
ACPI_FUNCTION_ENTRY();
@@ -81,10 +81,10 @@ static u8 acpi_rs_count_set_bits(u16 bit_field)
/* Zero the least significant bit that is set */
- bit_field &= (bit_field - 1);
+ bit_field &= (u16) (bit_field - 1);
}
- return (bits_set);
+ return ((u8) bits_set);
}
/*******************************************************************************
@@ -211,6 +211,24 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
* variable-length fields
*/
switch (resource->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+
+ /* Length can be 3 or 2 */
+
+ if (resource->data.irq.descriptor_length == 2) {
+ total_size--;
+ }
+ break;
+
+ case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+
+ /* Length can be 1 or 0 */
+
+ if (resource->data.irq.descriptor_length == 0) {
+ total_size--;
+ }
+ break;
+
case ACPI_RESOURCE_TYPE_VENDOR:
/*
* Vendor Defined Resource:
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 50da494c3ee2..faddaee1bc07 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index 46da116a4030..6bbbb7b8941a 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,8 +87,10 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
*
******************************************************************************/
-struct acpi_rsdump_info acpi_rs_dump_irq[6] = {
+struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
+ "Descriptor Length", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
acpi_gbl_he_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
@@ -115,9 +117,11 @@ struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
NULL}
};
-struct acpi_rsdump_info acpi_rs_dump_start_dpf[3] = {
+struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
"Start-Dependent-Functions", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
+ "Descriptor Length", NULL},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
"Compatibility Priority", acpi_gbl_config_decode},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 2c2adb6292c1..3f0a1fedbe0e 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index b297bc3e4419..b66d42e7402e 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -185,7 +185,7 @@ struct acpi_rsconvert_info acpi_rs_convert_end_tag[2] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
+struct acpi_rsconvert_info acpi_rs_get_start_dpf[6] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT,
ACPI_RS_SIZE(struct acpi_resource_start_dependent),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_start_dpf)},
@@ -196,6 +196,12 @@ struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
ACPI_ACCEPTABLE_CONFIGURATION,
2},
+ /* Get the descriptor length (0 or 1 for Start Dpf descriptor) */
+
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ AML_OFFSET(start_dpf.descriptor_type),
+ 0},
+
/* All done if there is no flag byte present in the descriptor */
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1},
@@ -219,7 +225,9 @@ struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = {
+struct acpi_rsconvert_info acpi_rs_set_start_dpf[10] = {
+ /* Start with a default descriptor of length 1 */
+
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT,
sizeof(struct aml_resource_start_dependent),
ACPI_RSC_TABLE_SIZE(acpi_rs_set_start_dpf)},
@@ -236,6 +244,33 @@ struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = {
AML_OFFSET(start_dpf.flags),
2},
/*
+ * All done if the output descriptor length is required to be 1
+ * (i.e., optimization to 0 bytes cannot be attempted)
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ 1},
+
+ /* Set length to 0 bytes (no flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0,
+ sizeof(struct aml_resource_start_dependent_noprio)},
+
+ /*
+ * All done if the output descriptor length is required to be 0.
+ *
+ * TBD: Perhaps we should check for error if input flags are not
+ * compatible with a 0-byte descriptor.
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ 0},
+
+ /* Reset length to 1 byte (descriptor with flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_start_dependent)},
+
+ /*
* All done if flags byte is necessary -- if either priority value
* is not ACPI_ACCEPTABLE_CONFIGURATION
*/
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 5657f7b95039..a8805efc0366 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,7 @@ ACPI_MODULE_NAME("rsirq")
* acpi_rs_get_irq
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
+struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ,
ACPI_RS_SIZE(struct acpi_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)},
@@ -69,6 +69,12 @@ struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
ACPI_EDGE_SENSITIVE,
1},
+ /* Get the descriptor length (2 or 3 for IRQ descriptor) */
+
+ {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.irq.descriptor_length),
+ AML_OFFSET(irq.descriptor_type),
+ 0},
+
/* All done if no flag byte present in descriptor */
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3},
@@ -94,7 +100,9 @@ struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
+struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
+ /* Start with a default descriptor of length 3 */
+
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ,
sizeof(struct aml_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)},
@@ -105,7 +113,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
AML_OFFSET(irq.irq_mask),
ACPI_RS_OFFSET(data.irq.interrupt_count)},
- /* Set the flags byte by default */
+ /* Set the flags byte */
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
AML_OFFSET(irq.flags),
@@ -118,6 +126,33 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable),
AML_OFFSET(irq.flags),
4},
+
+ /*
+ * All done if the output descriptor length is required to be 3
+ * (i.e., optimization to 2 bytes cannot be attempted)
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.irq.descriptor_length),
+ 3},
+
+ /* Set length to 2 bytes (no flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)},
+
+ /*
+ * All done if the output descriptor length is required to be 2.
+ *
+ * TBD: Perhaps we should check for error if input flags are not
+ * compatible with a 2-byte descriptor.
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.irq.descriptor_length),
+ 2},
+
+ /* Reset length to 3 bytes (descriptor with flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)},
+
/*
* Check if the flags byte is necessary. Not needed if the flags are:
* ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE
@@ -134,7 +169,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
ACPI_RS_OFFSET(data.irq.sharable),
ACPI_EXCLUSIVE},
- /* irq_no_flags() descriptor can be used */
+ /* We can optimize to a 2-byte irq_no_flags() descriptor */
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)}
};
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index ca21e4660c79..b78c7e797a19 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index 521eab7dd8df..63b21abd90bb 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index c7081afa893a..de1ac3881b22 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -497,6 +497,17 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
}
break;
+ case ACPI_RSC_EXIT_EQ:
+ /*
+ * Control - Exit conversion if equal
+ */
+ if (*ACPI_ADD_PTR(u8, resource,
+ COMPARE_TARGET(info)) ==
+ COMPARE_VALUE(info)) {
+ goto exit;
+ }
+ break;
+
default:
ACPI_ERROR((AE_INFO, "Invalid conversion opcode"));
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index 11c0bd7b9cfd..befe2302f41b 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,17 +97,17 @@ u8 acpi_rs_decode_bitmask(u16 mask, u8 * list)
u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
{
acpi_native_uint i;
- u16 mask;
+ acpi_native_uint mask;
ACPI_FUNCTION_ENTRY();
/* Encode the list into a single bitmask */
for (i = 0, mask = 0; i < count; i++) {
- mask |= (0x0001 << list[i]);
+ mask |= (0x1 << list[i]);
}
- return (mask);
+ return ((u16) mask);
}
/*******************************************************************************
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 4c3fd4cdaf73..f59f4c4e034c 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e6ce262b5d44..6d85289f1c12 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -677,9 +677,8 @@ acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
device->wakeup.resources.count = package->package.count - 2;
for (i = 0; i < device->wakeup.resources.count; i++) {
element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
return AE_BAD_DATA;
- }
device->wakeup.resources.handles[i] = element->reference.handle;
}
@@ -692,6 +691,9 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
+ union acpi_object in_arg[3];
+ struct acpi_object_list arg_list = { 3, in_arg };
+ acpi_status psw_status = AE_OK;
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
@@ -700,7 +702,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{"", 0},
};
-
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -718,6 +719,45 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ /* Call _PSW/_DSW object to disable its ability to wake the sleeping
+ * system for the ACPI device with the _PRW object.
+ * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+ * So it is necessary to call _DSW object first. Only when it is not
+ * present will the _PSW object used.
+ */
+ /*
+ * Three agruments are needed for the _DSW object.
+ * Argument 0: enable/disable the wake capabilities
+ * When _DSW object is called to disable the wake capabilities, maybe
+ * the first argument is filled. The value of the other two agruments
+ * is meaningless.
+ */
+ in_arg[0].type = ACPI_TYPE_INTEGER;
+ in_arg[0].integer.value = 0;
+ in_arg[1].type = ACPI_TYPE_INTEGER;
+ in_arg[1].integer.value = 0;
+ in_arg[2].type = ACPI_TYPE_INTEGER;
+ in_arg[2].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_DSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
+ /*
+ * When the _DSW object is not present, OSPM will call _PSW object.
+ */
+ if (psw_status == AE_NOT_FOUND) {
+ /*
+ * Only one agruments is required for the _PSW object.
+ * agrument 0: enable/disable the wake capabilities
+ */
+ arg_list.count = 1;
+ in_arg[0].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_PSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
+ "evaluate _PSW\n"));
+ }
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
@@ -882,10 +922,7 @@ static void acpi_device_get_busid(struct acpi_device *device,
static int
acpi_video_bus_match(struct acpi_device *device)
{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
+ acpi_handle h_dummy;
if (!device)
return -EINVAL;
@@ -895,18 +932,18 @@ acpi_video_bus_match(struct acpi_device *device)
*/
/* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
return 0;
/* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
return 0;
/* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
return 0;
return -ENODEV;
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 71183eea7906..c3b0cd88d09f 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -51,7 +51,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
}
#ifdef CONFIG_SUSPEND
-static struct platform_suspend_ops acpi_pm_ops;
+static struct platform_suspend_ops acpi_suspend_ops;
extern void do_suspend_lowlevel(void);
@@ -65,11 +65,11 @@ static u32 acpi_suspend_states[] = {
static int init_8259A_after_S1;
/**
- * acpi_pm_begin - Set the target system sleep state to the state
+ * acpi_suspend_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported.
*/
-static int acpi_pm_begin(suspend_state_t pm_state)
+static int acpi_suspend_begin(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
@@ -85,13 +85,13 @@ static int acpi_pm_begin(suspend_state_t pm_state)
}
/**
- * acpi_pm_prepare - Do preliminary suspend work.
+ * acpi_suspend_prepare - Do preliminary suspend work.
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
-static int acpi_pm_prepare(void)
+static int acpi_suspend_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
@@ -104,7 +104,7 @@ static int acpi_pm_prepare(void)
}
/**
- * acpi_pm_enter - Actually enter a sleep state.
+ * acpi_suspend_enter - Actually enter a sleep state.
* @pm_state: ignored
*
* Flush caches and go to sleep. For STR we have to call arch-specific
@@ -112,7 +112,7 @@ static int acpi_pm_prepare(void)
* It's unfortunate, but it works. Please fix if you're feeling frisky.
*/
-static int acpi_pm_enter(suspend_state_t pm_state)
+static int acpi_suspend_enter(suspend_state_t pm_state)
{
acpi_status status = AE_OK;
unsigned long flags = 0;
@@ -169,13 +169,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
}
/**
- * acpi_pm_finish - Instruct the platform to leave a sleep state.
+ * acpi_suspend_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
-static void acpi_pm_finish(void)
+static void acpi_suspend_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
@@ -196,19 +196,19 @@ static void acpi_pm_finish(void)
}
/**
- * acpi_pm_end - Finish up suspend sequence.
+ * acpi_suspend_end - Finish up suspend sequence.
*/
-static void acpi_pm_end(void)
+static void acpi_suspend_end(void)
{
/*
- * This is necessary in case acpi_pm_finish() is not called during a
+ * This is necessary in case acpi_suspend_finish() is not called during a
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
}
-static int acpi_pm_state_valid(suspend_state_t pm_state)
+static int acpi_suspend_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -224,13 +224,13 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
}
}
-static struct platform_suspend_ops acpi_pm_ops = {
- .valid = acpi_pm_state_valid,
- .begin = acpi_pm_begin,
- .prepare = acpi_pm_prepare,
- .enter = acpi_pm_enter,
- .finish = acpi_pm_finish,
- .end = acpi_pm_end,
+static struct platform_suspend_ops acpi_suspend_ops = {
+ .valid = acpi_suspend_state_valid,
+ .begin = acpi_suspend_begin,
+ .prepare = acpi_suspend_prepare,
+ .enter = acpi_suspend_enter,
+ .finish = acpi_suspend_finish,
+ .end = acpi_suspend_end,
};
/*
@@ -492,7 +492,7 @@ int __init acpi_sleep_init(void)
}
}
- suspend_set_ops(&acpi_pm_ops);
+ suspend_set_ops(&acpi_suspend_ops);
#endif
#ifdef CONFIG_HIBERNATION
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 002bb33003af..949d4114eb9f 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
index 058c064948e1..9ca3afc98c80 100644
--- a/drivers/acpi/tables/tbfind.c
+++ b/drivers/acpi/tables/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,12 +70,22 @@ acpi_tb_find_table(char *signature,
{
acpi_native_uint i;
acpi_status status;
+ struct acpi_table_header header;
ACPI_FUNCTION_TRACE(tb_find_table);
+ /* Normalize the input strings */
+
+ ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header));
+ ACPI_STRNCPY(header.signature, signature, ACPI_NAME_SIZE);
+ ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE);
+ ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+
+ /* Search for the table */
+
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
- signature, ACPI_NAME_SIZE)) {
+ header.signature, ACPI_NAME_SIZE)) {
/* Not the requested table */
@@ -104,20 +114,24 @@ acpi_tb_find_table(char *signature,
if (!ACPI_MEMCMP
(acpi_gbl_root_table_list.tables[i].pointer->signature,
- signature, ACPI_NAME_SIZE) && (!oem_id[0]
- ||
- !ACPI_MEMCMP
- (acpi_gbl_root_table_list.
- tables[i].pointer->oem_id,
- oem_id, ACPI_OEM_ID_SIZE))
+ header.signature, ACPI_NAME_SIZE) && (!oem_id[0]
+ ||
+ !ACPI_MEMCMP
+ (acpi_gbl_root_table_list.
+ tables[i].pointer->
+ oem_id,
+ header.oem_id,
+ ACPI_OEM_ID_SIZE))
&& (!oem_table_id[0]
|| !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
- pointer->oem_table_id, oem_table_id,
+ pointer->oem_table_id,
+ header.oem_table_id,
ACPI_OEM_TABLE_ID_SIZE))) {
*table_index = i;
ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Found table [%4.4s]\n", signature));
+ "Found table [%4.4s]\n",
+ header.signature));
return_ACPI_STATUS(AE_OK);
}
}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 3bc0c67a9283..402f93e1ff20 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,13 +125,20 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc,
/* The table must be either an SSDT or a PSDT or an OEMx */
- if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
- &&
- (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
- && (strncmp(table_desc->pointer->signature, "OEM", 3))) {
- ACPI_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s], must be SSDT, PSDT or OEMx",
- table_desc->pointer->signature));
+ if (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)&&
+ !ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)&&
+ strncmp(table_desc->pointer->signature, "OEM", 3)) {
+ /* Check for a printable name */
+ if (acpi_ut_valid_acpi_name(
+ *(u32 *) table_desc->pointer->signature)) {
+ ACPI_ERROR((AE_INFO, "Table has invalid signature "
+ "[%4.4s], must be SSDT or PSDT",
+ table_desc->pointer->signature));
+ } else {
+ ACPI_ERROR((AE_INFO, "Table has invalid signature "
+ "(0x%8.8X), must be SSDT or PSDT",
+ *(u32 *) table_desc->pointer->signature));
+ }
return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
@@ -162,6 +169,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc,
acpi_tb_delete_table(table_desc);
*table_index = i;
+ status = AE_ALREADY_EXISTS;
goto release;
}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 010f19652f80..bc019b9b6a68 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -212,7 +212,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
if (checksum) {
ACPI_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
+ "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
table->signature, table->checksum,
(u8) (table->checksum - checksum)));
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index a9e3331fee5d..fb57b93c2495 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -635,6 +635,95 @@ acpi_status acpi_load_tables(void)
ACPI_EXPORT_SYMBOL(acpi_load_tables)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_table_handler
+ *
+ * PARAMETERS: Handler - Table event handler
+ * Context - Value passed to the handler on each event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install table event handler
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_table_handler(acpi_tbl_handler handler, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_table_handler);
+
+ if (!handler) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow more than one handler */
+
+ if (acpi_gbl_table_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ /* Install the handler */
+
+ acpi_gbl_table_handler = handler;
+ acpi_gbl_table_handler_context = context;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_table_handler)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_table_handler
+ *
+ * PARAMETERS: Handler - Table event handler that was installed
+ * previously.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove table event handler
+ *
+ ******************************************************************************/
+acpi_status acpi_remove_table_handler(acpi_tbl_handler handler)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_remove_table_handler);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Make sure that the installed handler is the same */
+
+ if (!handler || handler != acpi_gbl_table_handler) {
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Remove the handler */
+
+ acpi_gbl_table_handler = NULL;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_table_handler)
+
+
static int __init acpi_no_auto_ssdt_setup(char *s) {
printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index 9ecb4b6c1e7d..b8c0dfa084f6 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 1bcecc7dd2ca..782c2250443e 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -884,10 +884,15 @@ static void acpi_thermal_check(void *data)
static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
+ int result;
if (!tz)
return -EINVAL;
+ result = acpi_thermal_get_temperature(tz);
+ if (result)
+ return result;
+
return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
}
@@ -1012,6 +1017,18 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
return -EINVAL;
}
+static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temperature) {
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (tz->trips.critical.flags.valid) {
+ *temperature = KELVIN_TO_MILLICELSIUS(
+ tz->trips.critical.temperature);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1103,6 +1120,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.set_mode = thermal_set_mode,
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
+ .get_crit_temp = thermal_get_crit_temp,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
@@ -1123,7 +1141,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
- tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+ tz->thermal_zone = thermal_zone_device_register("acpitz",
trips, tz, &acpi_thermal_zone_ops);
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
@@ -1710,7 +1728,6 @@ static int acpi_thermal_resume(struct acpi_device *device)
return AE_OK;
}
-#ifdef CONFIG_DMI
static int thermal_act(const struct dmi_system_id *d) {
if (act == 0) {
@@ -1785,7 +1802,6 @@ static struct dmi_system_id thermal_dmi_table[] __initdata = {
},
{}
};
-#endif /* CONFIG_DMI */
static int __init acpi_thermal_init(void)
{
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 6e56d5f7c43a..ede084829a70 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,7 @@ acpi_status acpi_ut_delete_caches(void)
if (acpi_gbl_display_final_mem_stats) {
ACPI_STRCPY(buffer, "MEMORY");
- acpi_db_display_statistics(buffer);
+ (void)acpi_db_display_statistics(buffer);
}
#endif
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 285a0f531760..245fa80cf600 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 879eaa10d3ae..655c290aca7b 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,8 @@
#include <acpi/acpi.h>
#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utcopy")
@@ -172,22 +174,21 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
case ACPI_TYPE_LOCAL_REFERENCE:
- /*
- * This is an object reference. Attempt to dereference it.
- */
+ /* This is an object reference. */
+
switch (internal_object->reference.opcode) {
case AML_INT_NAMEPATH_OP:
/* For namepath, return the object handle ("reference") */
default:
- /*
- * Use the object type of "Any" to indicate a reference
- * to object containing a handle to an ACPI named object.
- */
- external_object->type = ACPI_TYPE_ANY;
+
+ /* We are referring to the namespace node */
+
external_object->reference.handle =
internal_object->reference.node;
+ external_object->reference.actual_type =
+ acpi_ns_get_type(internal_object->reference.node);
break;
}
break;
@@ -215,6 +216,11 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
/*
* There is no corresponding external object type
*/
+ ACPI_ERROR((AE_INFO,
+ "Unsupported object type, cannot convert to external object: %s",
+ acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE
+ (internal_object))));
+
return_ACPI_STATUS(AE_SUPPORT);
}
@@ -455,6 +461,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_LOCAL_REFERENCE:
internal_object = acpi_ut_create_internal_object((u8)
external_object->
@@ -464,9 +471,18 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
}
break;
+ case ACPI_TYPE_ANY: /* This is the case for a NULL object */
+
+ *ret_internal_object = NULL;
+ return_ACPI_STATUS(AE_OK);
+
default:
/* All other types are not supported */
+ ACPI_ERROR((AE_INFO,
+ "Unsupported object type, cannot convert to internal object: %s",
+ acpi_ut_get_type_name(external_object->type)));
+
return_ACPI_STATUS(AE_SUPPORT);
}
@@ -502,6 +518,10 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
external_object->buffer.length);
internal_object->buffer.length = external_object->buffer.length;
+
+ /* Mark buffer data valid */
+
+ internal_object->buffer.flags |= AOPOBJ_DATA_VALID;
break;
case ACPI_TYPE_INTEGER:
@@ -509,6 +529,15 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
internal_object->integer.value = external_object->integer.value;
break;
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ /* TBD: should validate incoming handle */
+
+ internal_object->reference.opcode = AML_INT_NAMEPATH_OP;
+ internal_object->reference.node =
+ external_object->reference.handle;
+ break;
+
default:
/* Other types can't get here */
break;
@@ -570,13 +599,17 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object,
/* Truncate package and delete it */
- package_object->package.count = i;
+ package_object->package.count = (u32) i;
package_elements[i] = NULL;
acpi_ut_remove_reference(package_object);
return_ACPI_STATUS(status);
}
}
+ /* Mark package data valid */
+
+ package_object->package.flags |= AOPOBJ_DATA_VALID;
+
*internal_object = package_object;
return_ACPI_STATUS(status);
}
@@ -709,7 +742,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
/*
* We copied the reference object, so we now must add a reference
* to the object pointed to by the reference
+ *
+ * DDBHandle reference (from Load/load_table is a special reference,
+ * it's Reference.Object is the table index, so does not need to
+ * increase the reference count
*/
+ if (source_desc->reference.opcode == AML_LOAD_OP) {
+ break;
+ }
+
acpi_ut_add_reference(source_desc->reference.object);
break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 7361204b1eef..f938f465efa4 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -68,9 +68,9 @@ static const char *acpi_ut_trim_function_name(const char *function_name);
void acpi_ut_init_stack_ptr_trace(void)
{
- u32 current_sp;
+ acpi_size current_sp;
- acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF(&current_sp, NULL);
+ acpi_gbl_entry_stack_pointer = &current_sp;
}
/*******************************************************************************
@@ -89,10 +89,8 @@ void acpi_ut_track_stack_ptr(void)
{
acpi_size current_sp;
- current_sp = ACPI_PTR_DIFF(&current_sp, NULL);
-
- if (current_sp < acpi_gbl_lowest_stack_pointer) {
- acpi_gbl_lowest_stack_pointer = current_sp;
+ if (&current_sp < acpi_gbl_lowest_stack_pointer) {
+ acpi_gbl_lowest_stack_pointer = &current_sp;
}
if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) {
@@ -203,6 +201,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
va_start(args, format);
acpi_os_vprintf(format, args);
+ va_end(args);
}
ACPI_EXPORT_SYMBOL(acpi_ut_debug_print)
@@ -240,6 +239,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level,
va_start(args, format);
acpi_os_vprintf(format, args);
+ va_end(args);
}
ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw)
@@ -524,6 +524,11 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
u32 temp32;
u8 buf_char;
+ if (!buffer) {
+ acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
+ return;
+ }
+
if ((count < 4) || (count & 0x01)) {
display = DB_BYTE_DISPLAY;
}
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index f777cebdc46d..1fbc35139e84 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,7 +158,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
"***** Mutex %p, OS Mutex %p\n",
object, object->mutex.os_mutex));
- if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ if (object == acpi_gbl_global_lock_mutex) {
/* Global Lock has extra semaphore */
@@ -252,6 +252,17 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
}
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
+ "***** Bank Field %p\n", object));
+
+ second_desc = acpi_ns_get_secondary_object(object);
+ if (second_desc) {
+ acpi_ut_delete_object_desc(second_desc);
+ }
+ break;
+
default:
break;
}
@@ -524,10 +535,12 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_LOCAL_REFERENCE:
/*
- * The target of an Index (a package, string, or buffer) must track
- * changes to the ref count of the index.
+ * The target of an Index (a package, string, or buffer) or a named
+ * reference must track changes to the ref count of the index or
+ * target object.
*/
- if (object->reference.opcode == AML_INDEX_OP) {
+ if ((object->reference.opcode == AML_INDEX_OP) ||
+ (object->reference.opcode == AML_INT_NAMEPATH_OP)) {
next_object = object->reference.object;
}
break;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 0042b7e78b26..05e61be267d5 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 630c9a2c5b7b..a6e71b801d2d 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -602,6 +602,48 @@ char *acpi_ut_get_mutex_name(u32 mutex_id)
return (acpi_gbl_mutex_names[mutex_id]);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_notify_name
+ *
+ * PARAMETERS: notify_value - Value from the Notify() request
+ *
+ * RETURN: String corresponding to the Notify Value.
+ *
+ * DESCRIPTION: Translate a Notify Value to a notify namestring.
+ *
+ ******************************************************************************/
+
+/* Names for Notify() values, used for debug output */
+
+static const char *acpi_gbl_notify_value_names[] = {
+ "Bus Check",
+ "Device Check",
+ "Device Wake",
+ "Eject Request",
+ "Device Check Light",
+ "Frequency Mismatch",
+ "Bus Mode Mismatch",
+ "Power Fault",
+ "Capabilities Check",
+ "Device PLD Check",
+ "Reserved",
+ "System Locality Update"
+};
+
+const char *acpi_ut_get_notify_name(u32 notify_value)
+{
+
+ if (notify_value <= ACPI_NOTIFY_MAX) {
+ return (acpi_gbl_notify_value_names[notify_value]);
+ } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+ return ("Reserved");
+ } else { /* Greater or equal to 0x80 */
+
+ return ("**Device Specific**");
+ }
+}
#endif
/*******************************************************************************
@@ -675,12 +717,13 @@ void acpi_ut_init_globals(void)
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
- /* Global notify handlers */
+ /* Global handlers */
acpi_gbl_system_notify.handler = NULL;
acpi_gbl_device_notify.handler = NULL;
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
+ acpi_gbl_table_handler = NULL;
/* Global Lock support */
@@ -722,7 +765,7 @@ void acpi_ut_init_globals(void)
acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
#ifdef ACPI_DEBUG_OUTPUT
- acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
+ acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
#endif
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ad3c0d0a5cf8..cae515fc02d3 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,9 +125,12 @@ void acpi_ut_subsystem_shutdown(void)
acpi_gbl_startup_flags = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+#ifndef ACPI_ASL_COMPILER
+
/* Close the acpi_event Handling */
acpi_ev_terminate();
+#endif
/* Close the Namespace */
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 0c56a0d20b29..c927324fdd26 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,7 @@ acpi_ut_short_divide(acpi_integer in_dividend,
*out_quotient = in_dividend / divisor;
}
if (out_remainder) {
- *out_remainder = (u32) in_dividend % divisor;
+ *out_remainder = (u32) (in_dividend % divisor);
}
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 2d19f71e9cfa..e4ba7192cd15 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1033,6 +1033,7 @@ acpi_ut_error(char *module_name, u32 line_number, char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
@@ -1061,6 +1062,8 @@ acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
+ va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
@@ -1077,4 +1080,5 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf("\n");
+ va_end(args);
}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 4820bc86d1f5..f7d602b1a894 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index e08b3fa6639f..e68466de8044 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,6 +107,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name,
switch (type) {
case ACPI_TYPE_REGION:
case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
/* These types require a secondary object */
@@ -469,9 +470,8 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_POWER:
- /*
- * No extra data for these types
- */
+ /* No extra data for these types */
+
break;
case ACPI_TYPE_LOCAL_REFERENCE:
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index b630ee137ee1..c3e3e1308edc 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index edcaafad0a31..63a6d3d77d88 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index df41312733c2..f8bdadf3c32f 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxface")
+#ifndef ACPI_ASL_COMPILER
/*******************************************************************************
*
* FUNCTION: acpi_initialize_subsystem
@@ -291,6 +292,7 @@ acpi_status acpi_initialize_objects(u32 flags)
ACPI_EXPORT_SYMBOL(acpi_initialize_objects)
+#endif
/*******************************************************************************
*
* FUNCTION: acpi_terminate
@@ -334,6 +336,7 @@ acpi_status acpi_terminate(void)
}
ACPI_EXPORT_SYMBOL(acpi_terminate)
+#ifndef ACPI_ASL_COMPILER
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -489,3 +492,4 @@ acpi_status acpi_purge_cached_objects(void)
}
ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
+#endif
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 44ea60cf21c0..100926143818 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -398,7 +398,7 @@ acpi_evaluate_reference(acpi_handle handle,
element = &(package->package.elements[i]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
status = AE_BAD_DATA;
printk(KERN_ERR PREFIX
"Expecting a [Reference] package element, found type %X\n",
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 980a74188781..33c502e56026 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -57,8 +57,6 @@
#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
-#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
-#define ACPI_VIDEO_HEAD_END (~0u)
#define MAX_NAME_LEN 20
#define ACPI_VIDEO_DISPLAY_CRT 1
@@ -734,21 +732,19 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (IS_ERR(device->cdev))
return;
- if (device->cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev->dev.bus_id, device->cdev->id);
- result = sysfs_create_link(&device->dev->dev.kobj,
- &device->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&device->cdev->device.kobj,
- &device->dev->dev.kobj,
- "device");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- }
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev->dev.bus_id, device->cdev->id);
+ result = sysfs_create_link(&device->dev->dev.kobj,
+ &device->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&device->cdev->device.kobj,
+ &device->dev->dev.kobj, "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+
}
if (device->cap._DCS && device->cap._DSS){
static int count = 0;
@@ -1050,87 +1046,90 @@ acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
static int acpi_video_device_add_fs(struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
+ struct proc_dir_entry *entry, *device_dir;
struct acpi_video_device *vid_dev;
-
- if (!device)
- return -ENODEV;
-
vid_dev = acpi_driver_data(device);
if (!vid_dev)
return -ENODEV;
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- vid_dev->video->dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- acpi_device_dir(device)->owner = THIS_MODULE;
- }
+ device_dir = proc_mkdir(acpi_device_bid(device),
+ vid_dev->video->dir);
+ if (!device_dir)
+ return -ENOMEM;
+
+ device_dir->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ entry = create_proc_entry("info", S_IRUGO, device_dir);
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_device_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_dir;
+
+ entry->proc_fops = &acpi_video_device_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'state' [R/W] */
- entry =
- create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir);
if (!entry)
- return -ENODEV;
- else {
- acpi_video_device_state_fops.write = acpi_video_device_write_state;
- entry->proc_fops = &acpi_video_device_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_info;
+
+ acpi_video_device_state_fops.write = acpi_video_device_write_state;
+ entry->proc_fops = &acpi_video_device_state_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'brightness' [R/W] */
- entry =
- create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir);
if (!entry)
- return -ENODEV;
- else {
- acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
- entry->proc_fops = &acpi_video_device_brightness_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_state;
+
+ acpi_video_device_brightness_fops.write =
+ acpi_video_device_write_brightness;
+ entry->proc_fops = &acpi_video_device_brightness_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'EDID' [R] */
- entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
+ entry = create_proc_entry("EDID", S_IRUGO, device_dir);
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_device_EDID_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_brightness;
+ entry->proc_fops = &acpi_video_device_EDID_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+
+ acpi_device_dir(device) = device_dir;
return 0;
+
+ err_remove_brightness:
+ remove_proc_entry("brightness", device_dir);
+ err_remove_state:
+ remove_proc_entry("state", device_dir);
+ err_remove_info:
+ remove_proc_entry("info", device_dir);
+ err_remove_dir:
+ remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
+ return -ENOMEM;
}
static int acpi_video_device_remove_fs(struct acpi_device *device)
{
struct acpi_video_device *vid_dev;
+ struct proc_dir_entry *device_dir;
vid_dev = acpi_driver_data(device);
if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
return -ENODEV;
- if (acpi_device_dir(device)) {
- remove_proc_entry("info", acpi_device_dir(device));
- remove_proc_entry("state", acpi_device_dir(device));
- remove_proc_entry("brightness", acpi_device_dir(device));
- remove_proc_entry("EDID", acpi_device_dir(device));
+ device_dir = acpi_device_dir(device);
+ if (device_dir) {
+ remove_proc_entry("info", device_dir);
+ remove_proc_entry("state", device_dir);
+ remove_proc_entry("brightness", device_dir);
+ remove_proc_entry("EDID", device_dir);
remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
acpi_device_dir(device) = NULL;
}
@@ -1337,94 +1336,91 @@ acpi_video_bus_write_DOS(struct file *file,
static int acpi_video_bus_add_fs(struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
- struct acpi_video_bus *video;
-
+ struct acpi_video_bus *video = acpi_driver_data(device);
+ struct proc_dir_entry *device_dir;
+ struct proc_dir_entry *entry;
- video = acpi_driver_data(device);
+ device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
+ if (!device_dir)
+ return -ENOMEM;
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_video_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- video->dir = acpi_device_dir(device);
- acpi_device_dir(device)->owner = THIS_MODULE;
- }
+ device_dir->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ entry = create_proc_entry("info", S_IRUGO, device_dir);
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_dir;
+
+ entry->proc_fops = &acpi_video_bus_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'ROM' [R] */
- entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
+ entry = create_proc_entry("ROM", S_IRUGO, device_dir);
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_ROM_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_info;
+
+ entry->proc_fops = &acpi_video_bus_ROM_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'POST_info' [R] */
- entry =
- create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
+ entry = create_proc_entry("POST_info", S_IRUGO, device_dir);
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_POST_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_rom;
+
+ entry->proc_fops = &acpi_video_bus_POST_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'POST' [R/W] */
- entry =
- create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
- acpi_device_dir(device));
+ entry = create_proc_entry("POST", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir);
if (!entry)
- return -ENODEV;
- else {
- acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
- entry->proc_fops = &acpi_video_bus_POST_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_post_info;
+
+ acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
+ entry->proc_fops = &acpi_video_bus_POST_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
/* 'DOS' [R/W] */
- entry =
- create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
- acpi_device_dir(device));
+ entry = create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir);
if (!entry)
- return -ENODEV;
- else {
- acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
- entry->proc_fops = &acpi_video_bus_DOS_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_post;
+
+ acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
+ entry->proc_fops = &acpi_video_bus_DOS_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ video->dir = acpi_device_dir(device) = device_dir;
return 0;
+
+ err_remove_post:
+ remove_proc_entry("POST", device_dir);
+ err_remove_post_info:
+ remove_proc_entry("POST_info", device_dir);
+ err_remove_rom:
+ remove_proc_entry("ROM", device_dir);
+ err_remove_info:
+ remove_proc_entry("info", device_dir);
+ err_remove_dir:
+ remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
+ return -ENOMEM;
}
static int acpi_video_bus_remove_fs(struct acpi_device *device)
{
- struct acpi_video_bus *video;
-
-
- video = acpi_driver_data(device);
+ struct proc_dir_entry *device_dir = acpi_device_dir(device);
- if (acpi_device_dir(device)) {
- remove_proc_entry("info", acpi_device_dir(device));
- remove_proc_entry("ROM", acpi_device_dir(device));
- remove_proc_entry("POST_info", acpi_device_dir(device));
- remove_proc_entry("POST", acpi_device_dir(device));
- remove_proc_entry("DOS", acpi_device_dir(device));
+ if (device_dir) {
+ remove_proc_entry("info", device_dir);
+ remove_proc_entry("ROM", device_dir);
+ remove_proc_entry("POST_info", device_dir);
+ remove_proc_entry("POST", device_dir);
+ remove_proc_entry("DOS", device_dir);
remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
acpi_device_dir(device) = NULL;
}
@@ -1440,11 +1436,15 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
static struct acpi_video_device_attrib*
acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
{
- int count;
+ struct acpi_video_enumerated_device *ids;
+ int i;
+
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if ((ids->value.int_val & 0xffff) == device_id)
+ return &ids->value.attrib;
+ }
- for(count = 0; count < video->attached_count; count++)
- if((video->attached_array[count].value.int_val & 0xffff) == device_id)
- return &(video->attached_array[count].value.attrib);
return NULL;
}
@@ -1571,20 +1571,16 @@ static void
acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device)
{
+ struct acpi_video_enumerated_device *ids;
int i;
-#define IDS_VAL(i) video->attached_array[i].value.int_val
-#define IDS_BIND(i) video->attached_array[i].bind_info
-
- for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
- i < video->attached_count; i++) {
- if (device->device_id == (IDS_VAL(i) & 0xffff)) {
- IDS_BIND(i) = device;
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if (device->device_id == (ids->value.int_val & 0xffff)) {
+ ids->bind_info = device;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
}
}
-#undef IDS_VAL
-#undef IDS_BIND
}
/*
@@ -1603,7 +1599,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
int status;
int count;
int i;
- struct acpi_video_enumerated_device *active_device_list;
+ struct acpi_video_enumerated_device *active_list;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *dod = NULL;
union acpi_object *obj;
@@ -1624,13 +1620,10 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
dod->package.count));
- active_device_list = kmalloc((1 +
- dod->package.count) *
- sizeof(struct
- acpi_video_enumerated_device),
- GFP_KERNEL);
-
- if (!active_device_list) {
+ active_list = kcalloc(1 + dod->package.count,
+ sizeof(struct acpi_video_enumerated_device),
+ GFP_KERNEL);
+ if (!active_list) {
status = -ENOMEM;
goto out;
}
@@ -1640,23 +1633,24 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
obj = &dod->package.elements[i];
if (obj->type != ACPI_TYPE_INTEGER) {
- printk(KERN_ERR PREFIX "Invalid _DOD data\n");
- active_device_list[i].value.int_val =
- ACPI_VIDEO_HEAD_INVALID;
+ printk(KERN_ERR PREFIX
+ "Invalid _DOD data in element %d\n", i);
+ continue;
}
- active_device_list[i].value.int_val = obj->integer.value;
- active_device_list[i].bind_info = NULL;
+
+ active_list[count].value.int_val = obj->integer.value;
+ active_list[count].bind_info = NULL;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
(int)obj->integer.value));
count++;
}
- active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
kfree(video->attached_array);
- video->attached_array = active_device_list;
+ video->attached_array = active_list;
video->attached_count = count;
- out:
+
+ out:
kfree(buffer.pointer);
return status;
}
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 986e3324e302..7c4f886f1f16 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -556,16 +556,27 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
static void ahci_enable_ahci(void __iomem *mmio)
{
+ int i;
u32 tmp;
/* turn on AHCI_EN */
tmp = readl(mmio + HOST_CTL);
- if (!(tmp & HOST_AHCI_EN)) {
+ if (tmp & HOST_AHCI_EN)
+ return;
+
+ /* Some controllers need AHCI_EN to be written multiple times.
+ * Try a few times before giving up.
+ */
+ for (i = 0; i < 5; i++) {
tmp |= HOST_AHCI_EN;
writel(tmp, mmio + HOST_CTL);
tmp = readl(mmio + HOST_CTL); /* flush && sanity check */
- WARN_ON(!(tmp & HOST_AHCI_EN));
+ if (tmp & HOST_AHCI_EN)
+ return;
+ msleep(10);
}
+
+ WARN_ON(1);
}
/**
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b7c38eeb498f..ea2c7649d399 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -573,6 +573,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
+ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
/* end marker */
{ 0, }
};
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 8c1cfc645c85..70b77e0899a8 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -227,11 +227,9 @@ void ata_acpi_associate(struct ata_host *host)
acpi_install_notify_handler(ap->acpi_handle,
ACPI_SYSTEM_NOTIFY,
ata_acpi_ap_notify, ap);
-#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
/* we might be on a docking station */
register_hotplug_dock_device(ap->acpi_handle,
ata_acpi_ap_notify, ap);
-#endif
}
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
@@ -241,11 +239,9 @@ void ata_acpi_associate(struct ata_host *host)
acpi_install_notify_handler(dev->acpi_handle,
ACPI_SYSTEM_NOTIFY,
ata_acpi_dev_notify, dev);
-#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
/* we might be on a docking station */
register_hotplug_dock_device(dev->acpi_handle,
ata_acpi_dev_notify, dev);
-#endif
}
}
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b0b00af90d0e..51b7d2fad36a 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2616,7 +2616,7 @@ void ata_port_probe(struct ata_port *ap)
* LOCKING:
* None.
*/
-void sata_print_link_status(struct ata_link *link)
+static void sata_print_link_status(struct ata_link *link)
{
u32 sstatus, scontrol, tmp;
@@ -2772,7 +2772,7 @@ static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
* RETURNS:
* 1 if SATA spd configuration is needed, 0 otherwise.
*/
-int sata_set_spd_needed(struct ata_link *link)
+static int sata_set_spd_needed(struct ata_link *link)
{
u32 scontrol;
@@ -3377,7 +3377,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
* RETURNS:
* 0 if @linke is ready before @deadline; otherwise, -errno.
*/
-extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
+int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
int (*check_ready)(struct ata_link *link))
{
msleep(ATA_WAIT_AFTER_RESET_MSECS);
@@ -6208,7 +6208,6 @@ EXPORT_SYMBOL_GPL(ata_host_detach);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_qc_complete);
EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
-EXPORT_SYMBOL_GPL(sata_print_link_status);
EXPORT_SYMBOL_GPL(atapi_cmd_type);
EXPORT_SYMBOL_GPL(ata_tf_to_fis);
EXPORT_SYMBOL_GPL(ata_tf_from_fis);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d94359a24d41..61dcd0026c64 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1402,6 +1402,7 @@ static void ata_eh_analyze_ncq_error(struct ata_link *link)
/* we've got the perpetrator, condemn it */
qc = __ata_qc_from_tag(ap, tag);
memcpy(&qc->result_tf, &tf, sizeof(tf));
+ qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
ehc->i.err_mask &= ~AC_ERR_DEV;
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 15499522e642..2ec65a8fda79 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1208,7 +1208,7 @@ fsm_start:
DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
ap->print_id, qc->dev->devno, status);
- WARN_ON(qc->err_mask);
+ WARN_ON(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM));
ap->hsm_task_state = HSM_ST_IDLE;
@@ -1222,7 +1222,7 @@ fsm_start:
/* make sure qc->err_mask is available to
* know what's wrong and recover
*/
- WARN_ON(qc->err_mask == 0);
+ WARN_ON(!(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)));
ap->hsm_task_state = HSM_ST_IDLE;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4aeeabb10a47..ae2cfd95d43e 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -101,7 +101,6 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
unsigned int readid_flags);
extern int ata_dev_configure(struct ata_device *dev);
extern int sata_down_spd_limit(struct ata_link *link);
-extern int sata_set_spd_needed(struct ata_link *link);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 3e8651d78952..5e104385d6a3 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -381,6 +381,9 @@ static int __exit pata_at32_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:at32_ide");
+
static struct platform_driver pata_at32_driver = {
.remove = __exit_p(pata_at32_remove),
.driver = {
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 0a5ad98635b1..a75de0684c15 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1417,7 +1417,7 @@ static int bfin_reset_controller(struct ata_host *host)
count = 10000000;
do {
status = read_atapi_register(base, ATA_REG_STATUS);
- } while (count-- && (status & ATA_BUSY));
+ } while (--count && (status & ATA_BUSY));
/* Enable only ATAPI Device interrupt */
ATAPI_SET_INT_MASK(base, 1);
@@ -1601,3 +1601,4 @@ MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 8a175f23b907..de8d186f5abf 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -221,6 +221,7 @@ MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
module_init(ixp4xx_pata_init);
module_exit(ixp4xx_pata_exit);
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 6527c56c34a3..8f65ad61b8af 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -277,3 +277,4 @@ MODULE_AUTHOR("Paul Mundt");
MODULE_DESCRIPTION("low-level driver for platform device ATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb500_cf.c
index 800ae4601f44..4345174aaeec 100644
--- a/drivers/ata/pata_rb500_cf.c
+++ b/drivers/ata/pata_rb500_cf.c
@@ -239,6 +239,9 @@ static __devexit int rb500_pata_driver_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" DRV_NAME);
+
static struct platform_driver rb500_pata_platform_driver = {
.probe = rb500_pata_driver_probe,
.remove = __devexit_p(rb500_pata_driver_remove),
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index fddd346b1d57..853559e32315 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -678,7 +678,7 @@ static unsigned int sata_fsl_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static int sata_fsl_prereset(struct ata_linke *link, unsigned long deadline)
+static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline)
{
/* FIXME: Never skip softreset, sata_fsl_softreset() is
* combination of soft and hard resets. sata_fsl_softreset()
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index d52ce1188327..26a6337195b3 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -23,46 +23,34 @@
*/
/*
- sata_mv TODO list:
-
- 1) Needs a full errata audit for all chipsets. I implemented most
- of the errata workarounds found in the Marvell vendor driver, but
- I distinctly remember a couple workarounds (one related to PCI-X)
- are still needed.
-
- 2) Improve/fix IRQ and error handling sequences.
-
- 3) ATAPI support (Marvell claims the 60xx/70xx chips can do it).
-
- 4) Think about TCQ support here, and for libata in general
- with controllers that suppport it via host-queuing hardware
- (a software-only implementation could be a nightmare).
-
- 5) Investigate problems with PCI Message Signalled Interrupts (MSI).
-
- 6) Cache frequently-accessed registers in mv_port_priv to reduce overhead.
-
- 7) Fix/reenable hot plug/unplug (should happen as a side-effect of (2) above).
-
- 8) Develop a low-power-consumption strategy, and implement it.
-
- 9) [Experiment, low priority] See if ATAPI can be supported using
- "unknown FIS" or "vendor-specific FIS" support, or something creative
- like that.
-
- 10) [Experiment, low priority] Investigate interrupt coalescing.
- Quite often, especially with PCI Message Signalled Interrupts (MSI),
- the overhead reduced by interrupt mitigation is quite often not
- worth the latency cost.
-
- 11) [Experiment, Marvell value added] Is it possible to use target
- mode to cross-connect two Linux boxes with Marvell cards? If so,
- creating LibATA target mode support would be very interesting.
-
- Target mode, for those without docs, is the ability to directly
- connect two SATA controllers.
-
-*/
+ * sata_mv TODO list:
+ *
+ * --> Errata workaround for NCQ device errors.
+ *
+ * --> More errata workarounds for PCI-X.
+ *
+ * --> Complete a full errata audit for all chipsets to identify others.
+ *
+ * --> ATAPI support (Marvell claims the 60xx/70xx chips can do it).
+ *
+ * --> Investigate problems with PCI Message Signalled Interrupts (MSI).
+ *
+ * --> Cache frequently-accessed registers in mv_port_priv to reduce overhead.
+ *
+ * --> Develop a low-power-consumption strategy, and implement it.
+ *
+ * --> [Experiment, low priority] Investigate interrupt coalescing.
+ * Quite often, especially with PCI Message Signalled Interrupts (MSI),
+ * the overhead reduced by interrupt mitigation is quite often not
+ * worth the latency cost.
+ *
+ * --> [Experiment, Marvell value added] Is it possible to use target
+ * mode to cross-connect two Linux boxes with Marvell cards? If so,
+ * creating LibATA target mode support would be very interesting.
+ *
+ * Target mode, for those without docs, is the ability to directly
+ * connect two SATA ports.
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -124,11 +112,11 @@ enum {
MV_MAX_SG_CT = 256,
MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
- MV_PORTS_PER_HC = 4,
- /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+ /* Determine hc from 0-7 port: hc = port >> MV_PORT_HC_SHIFT */
MV_PORT_HC_SHIFT = 2,
- /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
- MV_PORT_MASK = 3,
+ MV_PORTS_PER_HC = (1 << MV_PORT_HC_SHIFT), /* 4 */
+ /* Determine hc port from 0-7 port: hardport = port & MV_PORT_MASK */
+ MV_PORT_MASK = (MV_PORTS_PER_HC - 1), /* 3 */
/* Host Flags */
MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
@@ -188,8 +176,8 @@ enum {
HC_MAIN_IRQ_MASK_OFS = 0x1d64,
HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
- PORT0_ERR = (1 << 0), /* shift by port # */
- PORT0_DONE = (1 << 1), /* shift by port # */
+ ERR_IRQ = (1 << 0), /* shift by port # */
+ DONE_IRQ = (1 << 1), /* shift by port # */
HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
PCI_ERR = (1 << 18),
@@ -205,6 +193,7 @@ enum {
HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */
HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
+ PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
HC_MAIN_RSVD),
HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
@@ -215,8 +204,8 @@ enum {
HC_CFG_OFS = 0,
HC_IRQ_CAUSE_OFS = 0x14,
- CRPB_DMA_DONE = (1 << 0), /* shift by port # */
- HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
+ DMA_IRQ = (1 << 0), /* shift by port # */
+ HC_COAL_IRQ = (1 << 4), /* IRQ coalescing */
DEV_IRQ = (1 << 8), /* shift by port # */
/* Shadow block registers */
@@ -299,9 +288,7 @@ enum {
EDMA_ERR_IRQ_TRANSIENT = EDMA_ERR_LNK_CTRL_RX_0 |
EDMA_ERR_LNK_CTRL_RX_1 |
EDMA_ERR_LNK_CTRL_RX_3 |
- EDMA_ERR_LNK_CTRL_TX |
- /* temporary, until we fix hotplug: */
- (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON),
+ EDMA_ERR_LNK_CTRL_TX,
EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
EDMA_ERR_PRD_PAR |
@@ -349,6 +336,8 @@ enum {
EDMA_IORDY_TMOUT = 0x34,
EDMA_ARB_CFG = 0x38,
+ GEN_II_NCQ_MAX_SECTORS = 256, /* max sects/io on Gen2 w/NCQ */
+
/* Host private flags (hp_flags) */
MV_HP_FLAG_MSI = (1 << 0),
MV_HP_ERRATA_50XXB0 = (1 << 1),
@@ -722,11 +711,6 @@ static inline void writelfl(unsigned long data, void __iomem *addr)
(void) readl(addr); /* flush to avoid PCI posted write */
}
-static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
-{
- return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
-}
-
static inline unsigned int mv_hc_from_port(unsigned int port)
{
return port >> MV_PORT_HC_SHIFT;
@@ -737,6 +721,29 @@ static inline unsigned int mv_hardport_from_port(unsigned int port)
return port & MV_PORT_MASK;
}
+/*
+ * Consolidate some rather tricky bit shift calculations.
+ * This is hot-path stuff, so not a function.
+ * Simple code, with two return values, so macro rather than inline.
+ *
+ * port is the sole input, in range 0..7.
+ * shift is one output, for use with the main_cause and main_mask registers.
+ * hardport is the other output, in range 0..3
+ *
+ * Note that port and hardport may be the same variable in some cases.
+ */
+#define MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport) \
+{ \
+ shift = mv_hc_from_port(port) * HC_SHIFT; \
+ hardport = mv_hardport_from_port(port); \
+ shift += hardport * 2; \
+}
+
+static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
+{
+ return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
+}
+
static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
unsigned int port)
{
@@ -783,7 +790,8 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
/*
* initialize request queue
*/
- index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
+ pp->req_idx &= MV_MAX_Q_DEPTH_MASK; /* paranoia */
+ index = pp->req_idx << EDMA_REQ_Q_PTR_SHIFT;
WARN_ON(pp->crqb_dma & 0x3ff);
writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
@@ -799,7 +807,8 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
/*
* initialize response queue
*/
- index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
+ pp->resp_idx &= MV_MAX_Q_DEPTH_MASK; /* paranoia */
+ index = pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT;
WARN_ON(pp->crpb_dma & 0xff);
writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
@@ -837,9 +846,9 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
}
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
struct mv_host_priv *hpriv = ap->host->private_data;
- int hard_port = mv_hardport_from_port(ap->port_no);
+ int hardport = mv_hardport_from_port(ap->port_no);
void __iomem *hc_mmio = mv_hc_base_from_port(
- mv_host_base(ap->host), hard_port);
+ mv_host_base(ap->host), hardport);
u32 hc_irq_cause, ipending;
/* clear EDMA event indicators, if any */
@@ -847,8 +856,7 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
/* clear EDMA interrupt indicator, if any */
hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- ipending = (DEV_IRQ << hard_port) |
- (CRPB_DMA_DONE << hard_port);
+ ipending = (DEV_IRQ | DMA_IRQ) << hardport;
if (hc_irq_cause & ipending) {
writelfl(hc_irq_cause & ~ipending,
hc_mmio + HC_IRQ_CAUSE_OFS);
@@ -864,7 +872,6 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
}
- WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
}
/**
@@ -1036,10 +1043,16 @@ static void mv6_dev_config(struct ata_device *adev)
* See mv_qc_prep() for more info.
*/
if (adev->flags & ATA_DFLAG_NCQ) {
- if (sata_pmp_attached(adev->link->ap))
+ if (sata_pmp_attached(adev->link->ap)) {
adev->flags &= ~ATA_DFLAG_NCQ;
- else if (adev->max_sectors > ATA_MAX_SECTORS)
- adev->max_sectors = ATA_MAX_SECTORS;
+ ata_dev_printk(adev, KERN_INFO,
+ "NCQ disabled for command-based switching\n");
+ } else if (adev->max_sectors > GEN_II_NCQ_MAX_SECTORS) {
+ adev->max_sectors = GEN_II_NCQ_MAX_SECTORS;
+ ata_dev_printk(adev, KERN_INFO,
+ "max_sectors limited to %u for NCQ\n",
+ adev->max_sectors);
+ }
}
}
@@ -1287,7 +1300,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT;
/* get current queue index from software */
- in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+ in_index = pp->req_idx;
pp->crqb[in_index].sg_addr =
cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
@@ -1379,7 +1392,7 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT;
/* get current queue index from software */
- in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+ in_index = pp->req_idx;
crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
@@ -1446,9 +1459,8 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
- pp->req_idx++;
-
- in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
+ pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK;
+ in_index = pp->req_idx << EDMA_REQ_Q_PTR_SHIFT;
/* and write the request in pointer to kick the EDMA to life */
writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
@@ -1457,16 +1469,51 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
return 0;
}
+static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
+
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
+ return NULL;
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
+ qc = NULL;
+ return qc;
+}
+
+static void mv_unexpected_intr(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ char *when = "";
+
+ /*
+ * We got a device interrupt from something that
+ * was supposed to be using EDMA or polling.
+ */
+ ata_ehi_clear_desc(ehi);
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+ when = " while EDMA enabled";
+ } else {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
+ when = " while polling";
+ }
+ ata_ehi_push_desc(ehi, "unexpected device interrupt%s", when);
+ ehi->err_mask |= AC_ERR_OTHER;
+ ehi->action |= ATA_EH_RESET;
+ ata_port_freeze(ap);
+}
+
/**
* mv_err_intr - Handle error interrupts on the port
* @ap: ATA channel to manipulate
- * @reset_allowed: bool: 0 == don't trigger from reset here
+ * @qc: affected command (non-NCQ), or NULL
*
- * In most cases, just clear the interrupt and move on. However,
- * some cases require an eDMA reset, which also performs a COMRESET.
- * The SERR case requires a clear of pending errors in the SATA
- * SERROR register. Finally, if the port disabled DMA,
- * update our cached copy to match.
+ * Most cases require a full reset of the chip's state machine,
+ * which also performs a COMRESET.
+ * Also, if the port disabled DMA, update our cached copy to match.
*
* LOCKING:
* Inherited from caller.
@@ -1477,28 +1524,24 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
u32 edma_err_cause, eh_freeze_mask, serr = 0;
struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
unsigned int action = 0, err_mask = 0;
struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
- if (!edma_enabled) {
- /* just a guess: do we need to do this? should we
- * expand this, and do it in all cases?
- */
- sata_scr_read(&ap->link, SCR_ERROR, &serr);
- sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
- }
-
+ /*
+ * Read and clear the err_cause bits. This won't actually
+ * clear for some errors (eg. SError), but we will be doing
+ * a hard reset in those cases regardless, which *will* clear it.
+ */
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
+ ata_ehi_push_desc(ehi, "edma_err_cause=%08x", edma_err_cause);
/*
- * all generations share these EDMA error cause bits
+ * All generations share these EDMA error cause bits:
*/
-
if (edma_err_cause & EDMA_ERR_DEV)
err_mask |= AC_ERR_DEV;
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
@@ -1515,34 +1558,36 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
action |= ATA_EH_RESET;
}
+ /*
+ * Gen-I has a different SELF_DIS bit,
+ * different FREEZE bits, and no SERR bit:
+ */
if (IS_GEN_I(hpriv)) {
eh_freeze_mask = EDMA_EH_FREEZE_5;
-
if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
- pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
} else {
eh_freeze_mask = EDMA_EH_FREEZE;
-
if (edma_err_cause & EDMA_ERR_SELF_DIS) {
- pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
-
if (edma_err_cause & EDMA_ERR_SERR) {
- sata_scr_read(&ap->link, SCR_ERROR, &serr);
- sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
- err_mask = AC_ERR_ATA_BUS;
+ /*
+ * Ensure that we read our own SCR, not a pmp link SCR:
+ */
+ ap->ops->scr_read(ap, SCR_ERROR, &serr);
+ /*
+ * Don't clear SError here; leave it for libata-eh:
+ */
+ ata_ehi_push_desc(ehi, "SError=%08x", serr);
+ err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
}
}
- /* Clear EDMA now that SERR cleanup done */
- writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
if (!err_mask) {
err_mask = AC_ERR_OTHER;
action |= ATA_EH_RESET;
@@ -1562,178 +1607,151 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ata_port_abort(ap);
}
-static void mv_intr_pio(struct ata_port *ap)
+static void mv_process_crpb_response(struct ata_port *ap,
+ struct mv_crpb *response, unsigned int tag, int ncq_enabled)
{
- struct ata_queued_cmd *qc;
- u8 ata_status;
-
- /* ignore spurious intr if drive still BUSY */
- ata_status = readb(ap->ioaddr.status_addr);
- if (unlikely(ata_status & ATA_BUSY))
- return;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
- /* get active ATA command */
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (unlikely(!qc)) /* no active tag */
- return;
- if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */
- return;
-
- /* and finally, complete the ATA command */
- qc->err_mask |= ac_err_mask(ata_status);
- ata_qc_complete(qc);
+ if (qc) {
+ u8 ata_status;
+ u16 edma_status = le16_to_cpu(response->flags);
+ /*
+ * edma_status from a response queue entry:
+ * LSB is from EDMA_ERR_IRQ_CAUSE_OFS (non-NCQ only).
+ * MSB is saved ATA status from command completion.
+ */
+ if (!ncq_enabled) {
+ u8 err_cause = edma_status & 0xff & ~EDMA_ERR_DEV;
+ if (err_cause) {
+ /*
+ * Error will be seen/handled by mv_err_intr().
+ * So do nothing at all here.
+ */
+ return;
+ }
+ }
+ ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
+ qc->err_mask |= ac_err_mask(ata_status);
+ ata_qc_complete(qc);
+ } else {
+ ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
+ __func__, tag);
+ }
}
-static void mv_intr_edma(struct ata_port *ap)
+static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_host_priv *hpriv = ap->host->private_data;
- struct mv_port_priv *pp = ap->private_data;
- struct ata_queued_cmd *qc;
- u32 out_index, in_index;
+ u32 in_index;
bool work_done = false;
+ int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN);
- /* get h/w response queue pointer */
+ /* Get the hardware queue position index */
in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
- while (1) {
- u16 status;
+ /* Process new responses from since the last time we looked */
+ while (in_index != pp->resp_idx) {
unsigned int tag;
+ struct mv_crpb *response = &pp->crpb[pp->resp_idx];
- /* get s/w response queue last-read pointer, and compare */
- out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
- if (in_index == out_index)
- break;
+ pp->resp_idx = (pp->resp_idx + 1) & MV_MAX_Q_DEPTH_MASK;
- /* 50xx: get active ATA command */
- if (IS_GEN_I(hpriv))
+ if (IS_GEN_I(hpriv)) {
+ /* 50xx: no NCQ, only one command active at a time */
tag = ap->link.active_tag;
-
- /* Gen II/IIE: get active ATA command via tag, to enable
- * support for queueing. this works transparently for
- * queued and non-queued modes.
- */
- else
- tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f;
-
- qc = ata_qc_from_tag(ap, tag);
-
- /* For non-NCQ mode, the lower 8 bits of status
- * are from EDMA_ERR_IRQ_CAUSE_OFS,
- * which should be zero if all went well.
- */
- status = le16_to_cpu(pp->crpb[out_index].flags);
- if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
- mv_err_intr(ap, qc);
- return;
- }
-
- /* and finally, complete the ATA command */
- if (qc) {
- qc->err_mask |=
- ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
- ata_qc_complete(qc);
+ } else {
+ /* Gen II/IIE: get command tag from CRPB entry */
+ tag = le16_to_cpu(response->id) & 0x1f;
}
-
- /* advance software response queue pointer, to
- * indicate (after the loop completes) to hardware
- * that we have consumed a response queue entry.
- */
+ mv_process_crpb_response(ap, response, tag, ncq_enabled);
work_done = true;
- pp->resp_idx++;
}
+ /* Update the software queue position index in hardware */
if (work_done)
writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
- (out_index << EDMA_RSP_Q_PTR_SHIFT),
+ (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT),
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
/**
* mv_host_intr - Handle all interrupts on the given host controller
* @host: host specific structure
- * @relevant: port error bits relevant to this host controller
- * @hc: which host controller we're to look at
- *
- * Read then write clear the HC interrupt status then walk each
- * port connected to the HC and see if it needs servicing. Port
- * success ints are reported in the HC interrupt status reg, the
- * port error ints are reported in the higher level main
- * interrupt status register and thus are passed in via the
- * 'relevant' argument.
+ * @main_cause: Main interrupt cause register for the chip.
*
* LOCKING:
* Inherited from caller.
*/
-static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
+static int mv_host_intr(struct ata_host *host, u32 main_cause)
{
struct mv_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->base;
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
- u32 hc_irq_cause;
- int port, port0, last_port;
+ void __iomem *mmio = hpriv->base, *hc_mmio = NULL;
+ u32 hc_irq_cause = 0;
+ unsigned int handled = 0, port;
- if (hc == 0)
- port0 = 0;
- else
- port0 = MV_PORTS_PER_HC;
-
- if (HAS_PCI(host))
- last_port = port0 + MV_PORTS_PER_HC;
- else
- last_port = port0 + hpriv->n_ports;
- /* we'll need the HC success int register in most cases */
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- if (!hc_irq_cause)
- return;
-
- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
-
- VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
- hc, relevant, hc_irq_cause);
-
- for (port = port0; port < last_port; port++) {
+ for (port = 0; port < hpriv->n_ports; port++) {
struct ata_port *ap = host->ports[port];
struct mv_port_priv *pp;
- int have_err_bits, hard_port, shift;
-
- if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
+ unsigned int shift, hardport, port_cause;
+ /*
+ * When we move to the second hc, flag our cached
+ * copies of hc_mmio (and hc_irq_cause) as invalid again.
+ */
+ if (port == MV_PORTS_PER_HC)
+ hc_mmio = NULL;
+ /*
+ * Do nothing if port is not interrupting or is disabled:
+ */
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+ port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ);
+ if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED))
continue;
-
+ /*
+ * Each hc within the host has its own hc_irq_cause register.
+ * We defer reading it until we know we need it, right now:
+ *
+ * FIXME later: we don't really need to read this register
+ * (some logic changes required below if we go that way),
+ * because it doesn't tell us anything new. But we do need
+ * to write to it, outside the top of this loop,
+ * to reset the interrupt triggers for next time.
+ */
+ if (!hc_mmio) {
+ hc_mmio = mv_hc_base_from_port(mmio, port);
+ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+ writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ handled = 1;
+ }
+ /*
+ * Process completed CRPB response(s) before other events.
+ */
pp = ap->private_data;
-
- shift = port << 1; /* (port * 2) */
- if (port >= MV_PORTS_PER_HC)
- shift++; /* skip bit 8 in the HC Main IRQ reg */
-
- have_err_bits = ((PORT0_ERR << shift) & relevant);
-
- if (unlikely(have_err_bits)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
- continue;
-
- mv_err_intr(ap, qc);
- continue;
+ if (hc_irq_cause & (DMA_IRQ << hardport)) {
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN)
+ mv_process_crpb_entries(ap, pp);
}
-
- hard_port = mv_hardport_from_port(port); /* range 0..3 */
-
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
- mv_intr_edma(ap);
- } else {
- if ((DEV_IRQ << hard_port) & hc_irq_cause)
- mv_intr_pio(ap);
+ /*
+ * Handle chip-reported errors, or continue on to handle PIO.
+ */
+ if (unlikely(port_cause & ERR_IRQ)) {
+ mv_err_intr(ap, mv_get_active_qc(ap));
+ } else if (hc_irq_cause & (DEV_IRQ << hardport)) {
+ if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
+ struct ata_queued_cmd *qc = mv_get_active_qc(ap);
+ if (qc) {
+ ata_sff_host_intr(ap, qc);
+ continue;
+ }
+ }
+ mv_unexpected_intr(ap);
}
}
- VPRINTK("EXIT\n");
+ return handled;
}
-static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
+static int mv_pci_error(struct ata_host *host, void __iomem *mmio)
{
struct mv_host_priv *hpriv = host->private_data;
struct ata_port *ap;
@@ -1771,6 +1789,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
ata_port_freeze(ap);
}
}
+ return 1; /* handled */
}
/**
@@ -1791,41 +1810,23 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct mv_host_priv *hpriv = host->private_data;
- unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = hpriv->base;
- u32 irq_stat, irq_mask;
+ unsigned int handled = 0;
+ u32 main_cause, main_mask;
- /* Note to self: &host->lock == &ap->host->lock == ap->lock */
spin_lock(&host->lock);
-
- irq_stat = readl(hpriv->main_cause_reg_addr);
- irq_mask = readl(hpriv->main_mask_reg_addr);
-
- /* check the cases where we either have nothing pending or have read
- * a bogus register value which can indicate HW removal or PCI fault
+ main_cause = readl(hpriv->main_cause_reg_addr);
+ main_mask = readl(hpriv->main_mask_reg_addr);
+ /*
+ * Deal with cases where we either have nothing pending, or have read
+ * a bogus register value which can indicate HW removal or PCI fault.
*/
- if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat))
- goto out_unlock;
-
- n_hcs = mv_get_hc_count(host->ports[0]->flags);
-
- if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) {
- mv_pci_error(host, mmio);
- handled = 1;
- goto out_unlock; /* skip all other HC irq handling */
- }
-
- for (hc = 0; hc < n_hcs; hc++) {
- u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
- if (relevant) {
- mv_host_intr(host, relevant, hc);
- handled = 1;
- }
+ if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) {
+ if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host)))
+ handled = mv_pci_error(host, hpriv->base);
+ else
+ handled = mv_host_intr(host, main_cause);
}
-
-out_unlock:
spin_unlock(&host->lock);
-
return IRQ_RETVAL(handled);
}
@@ -2109,13 +2110,6 @@ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
rc = 1;
}
- /*
- * Temporary: wait 3 seconds before port-probing can happen,
- * so that we don't miss finding sleepy SilXXXX port-multipliers.
- * This can go away once hotplug is fully/correctly implemented.
- */
- if (rc == 0)
- msleep(3000);
done:
return rc;
}
@@ -2409,55 +2403,44 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
static void mv_eh_freeze(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int hc = (ap->port_no > 3) ? 1 : 0;
- u32 tmp, mask;
- unsigned int shift;
+ unsigned int shift, hardport, port = ap->port_no;
+ u32 main_mask;
/* FIXME: handle coalescing completion events properly */
- shift = ap->port_no * 2;
- if (hc > 0)
- shift++;
-
- mask = 0x3 << shift;
+ mv_stop_edma(ap);
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
/* disable assertion of portN err, done events */
- tmp = readl(hpriv->main_mask_reg_addr);
- writelfl(tmp & ~mask, hpriv->main_mask_reg_addr);
+ main_mask = readl(hpriv->main_mask_reg_addr);
+ main_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
+ writelfl(main_mask, hpriv->main_mask_reg_addr);
}
static void mv_eh_thaw(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = hpriv->base;
- unsigned int hc = (ap->port_no > 3) ? 1 : 0;
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+ unsigned int shift, hardport, port = ap->port_no;
+ void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port);
void __iomem *port_mmio = mv_ap_base(ap);
- u32 tmp, mask, hc_irq_cause;
- unsigned int shift, hc_port_no = ap->port_no;
+ u32 main_mask, hc_irq_cause;
/* FIXME: handle coalescing completion events properly */
- shift = ap->port_no * 2;
- if (hc > 0) {
- shift++;
- hc_port_no -= 4;
- }
-
- mask = 0x3 << shift;
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
/* clear EDMA errors on this port */
writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
/* clear pending irq events */
hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- hc_irq_cause &= ~(1 << hc_port_no); /* clear CRPB-done */
- hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
- writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ hc_irq_cause &= ~((DEV_IRQ | DMA_IRQ) << hardport);
+ writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
/* enable assertion of portN err, done events */
- tmp = readl(hpriv->main_mask_reg_addr);
- writelfl(tmp | mask, hpriv->main_mask_reg_addr);
+ main_mask = readl(hpriv->main_mask_reg_addr);
+ main_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
+ writelfl(main_mask, hpriv->main_mask_reg_addr);
}
/**
@@ -2668,19 +2651,17 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
rc = mv_chip_id(host, board_idx);
if (rc)
- goto done;
+ goto done;
if (HAS_PCI(host)) {
- hpriv->main_cause_reg_addr = hpriv->base +
- HC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_cause_reg_addr = mmio + HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_mask_reg_addr = mmio + HC_MAIN_IRQ_MASK_OFS;
} else {
- hpriv->main_cause_reg_addr = hpriv->base +
- HC_SOC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = hpriv->base +
- HC_SOC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_cause_reg_addr = mmio + HC_SOC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_mask_reg_addr = mmio + HC_SOC_MAIN_IRQ_MASK_OFS;
}
- /* global interrupt mask */
+
+ /* global interrupt mask: 0 == mask everything */
writel(0, hpriv->main_mask_reg_addr);
n_hc = mv_get_hc_count(host->ports[0]->flags);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 109b07495721..858f70610eda 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1591,13 +1591,16 @@ static void nv_mcp55_thaw(struct ata_port *ap)
static int nv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- unsigned int dummy;
+ int rc;
/* SATA hardreset fails to retrieve proper device signature on
- * some controllers. Don't classify on hardreset. For more
- * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352
+ * some controllers. Request follow up SRST. For more info,
+ * see http://bugzilla.kernel.org/show_bug.cgi?id=3352
*/
- return sata_sff_hardreset(link, &dummy, deadline);
+ rc = sata_sff_hardreset(link, class, deadline);
+ if (rc)
+ return rc;
+ return -EAGAIN;
}
static void nv_adma_error_handler(struct ata_port *ap)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 6b8e45ba32e8..1010b3069bd5 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -142,7 +142,7 @@ static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
u8 pmr;
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return 0xffffffff;
+ return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -158,14 +158,14 @@ static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0;
}
-static void sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
u8 pmr;
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return;
+ return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -174,6 +174,8 @@ static void sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
pci_write_config_dword(pdev, cfg_addr+0x10, val);
+
+ return 0;
}
static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
@@ -211,14 +213,14 @@ static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
pci_read_config_byte(pdev, SIS_PMR, &pmr);
if (ap->flags & SIS_FLAG_CFGSCR)
- sis_scr_cfg_write(ap, sc_reg, val);
+ return sis_scr_cfg_write(ap, sc_reg, val);
else {
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+ return 0;
}
- return 0;
}
static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 38c769f8d2b7..3da804b1627d 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -415,7 +415,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
card->pcidev = pcidev;
membase = pci_resource_start(pcidev, 1);
card->membase = ioremap(membase, NS_IOREMAP_SIZE);
- if (card->membase == 0)
+ if (!card->membase)
{
printk("nicstar%d: can't ioremap() membase.\n",i);
error = 3;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 7bd76639544c..e8e38faeafd8 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -319,7 +319,7 @@ out:
#ifdef CONFIG_BLK_DEV_XIP
static int brd_direct_access (struct block_device *bdev, sector_t sector,
- unsigned long *data)
+ void **kaddr, unsigned long *pfn)
{
struct brd_device *brd = bdev->bd_disk->private_data;
struct page *page;
@@ -333,7 +333,8 @@ static int brd_direct_access (struct block_device *bdev, sector_t sector,
page = brd_insert_page(brd, sector);
if (!page)
return -ENOMEM;
- *data = (unsigned long)page_address(page);
+ *kaddr = page_address(page);
+ *pfn = page_to_pfn(page);
return 0;
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 9c6f3f99208d..d771da816d95 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -47,6 +47,7 @@
#include <xen/interface/grant_table.h>
#include <xen/interface/io/blkif.h>
+#include <xen/interface/io/protocols.h>
#include <asm/xen/hypervisor.h>
@@ -74,7 +75,6 @@ static struct block_device_operations xlvbd_block_fops;
struct blkfront_info
{
struct xenbus_device *xbdev;
- dev_t dev;
struct gendisk *gd;
int vdevice;
blkif_vdev_t handle;
@@ -88,6 +88,7 @@ struct blkfront_info
struct blk_shadow shadow[BLK_RING_SIZE];
unsigned long shadow_free;
int feature_barrier;
+ int is_ready;
/**
* The number of people holding this device open. We won't allow a
@@ -614,6 +615,12 @@ again:
message = "writing event-channel";
goto abort_transaction;
}
+ err = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
+ XEN_IO_PROTO_ABI_NATIVE);
+ if (err) {
+ message = "writing protocol";
+ goto abort_transaction;
+ }
err = xenbus_transaction_end(xbt, 0);
if (err) {
@@ -833,6 +840,8 @@ static void blkfront_connect(struct blkfront_info *info)
spin_unlock_irq(&blkif_io_lock);
add_disk(info->gd);
+
+ info->is_ready = 1;
}
/**
@@ -896,7 +905,7 @@ static void backend_changed(struct xenbus_device *dev,
break;
case XenbusStateClosing:
- bd = bdget(info->dev);
+ bd = bdget_disk(info->gd, 0);
if (bd == NULL)
xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
@@ -925,6 +934,13 @@ static int blkfront_remove(struct xenbus_device *dev)
return 0;
}
+static int blkfront_is_ready(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+
+ return info->is_ready;
+}
+
static int blkif_open(struct inode *inode, struct file *filep)
{
struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
@@ -971,6 +987,7 @@ static struct xenbus_driver blkfront = {
.remove = blkfront_remove,
.resume = blkfront_resume,
.otherend_changed = backend_changed,
+ .is_ready = blkfront_is_ready,
};
static int __init xlblk_init(void)
@@ -998,3 +1015,5 @@ module_exit(xlblk_exit);
MODULE_DESCRIPTION("Xen virtual block device frontend");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
+MODULE_ALIAS("xen:vbd");
+MODULE_ALIAS("xenblk");
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 2906ee7bd298..929d4fa73fd9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -732,9 +732,16 @@ config NVRAM
To compile this driver as a module, choose M here: the
module will be called nvram.
+#
+# These legacy RTC drivers just cause too many conflicts with the generic
+# RTC framework ... let's not even try to coexist any more.
+#
+if RTC_LIB=n
+
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32
+ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
+ && !ARM && !SUPERH && !S390 && !AVR32
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -840,6 +847,8 @@ config DS1302
will get access to the real time clock (or hardware clock) built
into your computer.
+endif # RTC_LIB
+
config COBALT_LCD
bool "Support for Cobalt LCD"
depends on MIPS_COBALT
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index d28669992147..96bdb9296b07 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -436,8 +436,9 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
system controller may experience noise due to strong drive strengths
*/
if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_7006) {
- u8 cap_ptr=0;
struct pci_dev *gfxcard=NULL;
+
+ cap_ptr = 0;
while (!cap_ptr) {
gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard);
if (!gfxcard) {
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 55d7a82bd071..857b26227d87 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -967,7 +967,7 @@ int agpioc_chipset_flush_wrap(struct agp_file_private *priv)
return 0;
}
-static int agp_ioctl(struct inode *inode, struct file *file,
+static long agp_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct agp_file_private *curr_priv = file->private_data;
@@ -1058,7 +1058,7 @@ static const struct file_operations agp_fops =
.llseek = no_llseek,
.read = agp_read,
.write = agp_write,
- .ioctl = agp_ioctl,
+ .unlocked_ioctl = agp_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_agp_ioctl,
#endif
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index c2d23cae9515..c0a4a0bb509e 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -215,7 +215,7 @@ static int __init cs5535_gpio_init(void)
else
mask = 0x0b003c66;
- if (request_region(gpio_base, CS5535_GPIO_SIZE, NAME) == 0) {
+ if (!request_region(gpio_base, CS5535_GPIO_SIZE, NAME)) {
printk(KERN_ERR NAME ": can't allocate I/O for GPIO\n");
return -ENODEV;
}
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index 141f4dfa0a11..b710426bab3e 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -167,13 +167,6 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
page_base += ATI_PCIGART_PAGE_SIZE;
}
}
-
- if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
- dma_sync_single_for_device(&dev->pdev->dev,
- bus_address,
- max_pages * sizeof(u32),
- PCI_DMA_TODEVICE);
-
ret = 1;
#if defined(__i386__) || defined(__x86_64__)
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 3a05c6d5ebe1..6874f31ca8ca 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -471,6 +471,7 @@ struct drm_irq_busid {
enum drm_vblank_seq_type {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
+ _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
_DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
@@ -503,6 +504,21 @@ union drm_wait_vblank {
struct drm_wait_vblank_reply reply;
};
+enum drm_modeset_ctl_cmd {
+ _DRM_PRE_MODESET = 1,
+ _DRM_POST_MODESET = 2,
+};
+
+/**
+ * DRM_IOCTL_MODESET_CTL ioctl argument type
+ *
+ * \sa drmModesetCtl().
+ */
+struct drm_modeset_ctl {
+ unsigned long arg;
+ enum drm_modeset_ctl_cmd cmd;
+};
+
/**
* DRM_IOCTL_AGP_ENABLE ioctl argument type.
*
@@ -587,6 +603,7 @@ struct drm_set_version {
#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client)
#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats)
#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version)
+#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl)
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique)
#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 6540948d5176..ecee3547a13f 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -100,10 +100,8 @@ struct drm_device;
#define DRIVER_HAVE_DMA 0x20
#define DRIVER_HAVE_IRQ 0x40
#define DRIVER_IRQ_SHARED 0x80
-#define DRIVER_IRQ_VBL 0x100
#define DRIVER_DMA_QUEUE 0x200
#define DRIVER_FB_DMA 0x400
-#define DRIVER_IRQ_VBL2 0x800
/***********************************************************************/
/** \name Begin the DRM... */
@@ -379,13 +377,12 @@ struct drm_buf_entry {
struct drm_file {
int authenticated;
int master;
- int minor;
pid_t pid;
uid_t uid;
drm_magic_t magic;
unsigned long ioctl_count;
struct list_head lhead;
- struct drm_head *head;
+ struct drm_minor *minor;
int remove_auth_on_close;
unsigned long lock_count;
struct file *filp;
@@ -580,10 +577,52 @@ struct drm_driver {
int (*context_dtor) (struct drm_device *dev, int context);
int (*kernel_context_switch) (struct drm_device *dev, int old,
int new);
- void (*kernel_context_switch_unlock) (struct drm_device *dev);
- int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence);
- int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence);
- int (*dri_library_name) (struct drm_device *dev, char *buf);
+ void (*kernel_context_switch_unlock) (struct drm_device * dev);
+ /**
+ * get_vblank_counter - get raw hardware vblank counter
+ * @dev: DRM device
+ * @crtc: counter to fetch
+ *
+ * Driver callback for fetching a raw hardware vblank counter
+ * for @crtc. If a device doesn't have a hardware counter, the
+ * driver can simply return the value of drm_vblank_count and
+ * make the enable_vblank() and disable_vblank() hooks into no-ops,
+ * leaving interrupts enabled at all times.
+ *
+ * Wraparound handling and loss of events due to modesetting is dealt
+ * with in the DRM core code.
+ *
+ * RETURNS
+ * Raw vblank counter value.
+ */
+ u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
+
+ /**
+ * enable_vblank - enable vblank interrupt events
+ * @dev: DRM device
+ * @crtc: which irq to enable
+ *
+ * Enable vblank interrupts for @crtc. If the device doesn't have
+ * a hardware vblank counter, this routine should be a no-op, since
+ * interrupts will have to stay on to keep the count accurate.
+ *
+ * RETURNS
+ * Zero on success, appropriate errno if the given @crtc's vblank
+ * interrupt cannot be enabled.
+ */
+ int (*enable_vblank) (struct drm_device *dev, int crtc);
+
+ /**
+ * disable_vblank - disable vblank interrupt events
+ * @dev: DRM device
+ * @crtc: which irq to enable
+ *
+ * Disable vblank interrupts for @crtc. If the device doesn't have
+ * a hardware vblank counter, this routine should be a no-op, since
+ * interrupts will have to stay on to keep the count accurate.
+ */
+ void (*disable_vblank) (struct drm_device *dev, int crtc);
+ int (*dri_library_name) (struct drm_device *dev, char * buf);
/**
* Called by \c drm_device_is_agp. Typically used to determine if a
@@ -602,7 +641,7 @@ struct drm_driver {
irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
void (*irq_preinstall) (struct drm_device *dev);
- void (*irq_postinstall) (struct drm_device *dev);
+ int (*irq_postinstall) (struct drm_device *dev);
void (*irq_uninstall) (struct drm_device *dev);
void (*reclaim_buffers) (struct drm_device *dev,
struct drm_file * file_priv);
@@ -630,16 +669,19 @@ struct drm_driver {
struct pci_driver pci_driver;
};
+#define DRM_MINOR_UNASSIGNED 0
+#define DRM_MINOR_LEGACY 1
+
/**
- * DRM head structure. This structure represent a video head on a card
- * that may contain multiple heads. Embed one per head of these in the
- * private drm_device structure.
+ * DRM minor structure. This structure represents a drm minor number.
*/
-struct drm_head {
- int minor; /**< Minor device number */
+struct drm_minor {
+ int index; /**< Minor device number */
+ int type; /**< Control or render */
+ dev_t device; /**< Device number for mknod */
+ struct device kdev; /**< Linux device */
struct drm_device *dev;
struct proc_dir_entry *dev_root; /**< proc directory entry */
- dev_t device; /**< Device number for mknod */
};
/**
@@ -647,7 +689,6 @@ struct drm_head {
* may contain multiple heads.
*/
struct drm_device {
- struct device dev; /**< Linux device */
char *unique; /**< Unique identifier: e.g., busid */
int unique_len; /**< Length of unique field */
char *devname; /**< For /proc/interrupts */
@@ -729,13 +770,21 @@ struct drm_device {
/** \name VBLANK IRQ support */
/*@{ */
- wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
- atomic_t vbl_received;
- atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
+ wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */
+ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
spinlock_t vbl_lock;
- struct list_head vbl_sigs; /**< signal list to send on VBLANK */
- struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */
- unsigned int vbl_pending;
+ struct list_head *vbl_sigs; /**< signal list to send on VBLANK */
+ atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/
+ atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */
+ u32 *last_vblank; /* protected by dev->vbl_lock, used */
+ /* for wraparound handling */
+ u32 *vblank_offset; /* used to track how many vblanks */
+ int *vblank_enabled; /* so we don't call enable more than
+ once per disable */
+ u32 *vblank_premodeset; /* were lost during modeset */
+ struct timer_list vblank_disable_timer;
+
+ unsigned long max_vblank_count; /**< size of vblank counter register */
spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
void (*locked_tasklet_func)(struct drm_device *dev);
@@ -755,6 +804,7 @@ struct drm_device {
#ifdef __alpha__
struct pci_controller *hose;
#endif
+ int num_crtcs; /**< Number of CRTCs on this device */
struct drm_sg_mem *sg; /**< Scatter gather memory */
void *dev_private; /**< device private data */
struct drm_sigdata sigdata; /**< For block_all_signals */
@@ -763,7 +813,7 @@ struct drm_device {
struct drm_driver *driver;
drm_local_map_t *agp_buffer_map;
unsigned int agp_buffer_token;
- struct drm_head primary; /**< primary screen head */
+ struct drm_minor *primary; /**< render type primary screen head */
/** \name Drawable information */
/*@{ */
@@ -989,11 +1039,19 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev);
extern void drm_driver_irq_postinstall(struct drm_device *dev);
extern void drm_driver_irq_uninstall(struct drm_device *dev);
-extern int drm_wait_vblank(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
-extern void drm_vbl_send_signals(struct drm_device *dev);
+extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
+extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp);
+extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq);
extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
+extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
+extern void drm_update_vblank_count(struct drm_device *dev, int crtc);
+extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+extern int drm_vblank_get(struct drm_device *dev, int crtc);
+extern void drm_vblank_put(struct drm_device *dev, int crtc);
+
+ /* Modesetting support */
+extern int drm_modeset_ctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* AGP/GART support (drm_agpsupport.h) */
extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
@@ -1030,23 +1088,20 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver);
extern int drm_put_dev(struct drm_device *dev);
-extern int drm_put_head(struct drm_head *head);
+extern int drm_put_minor(struct drm_minor **minor);
extern unsigned int drm_debug;
-extern unsigned int drm_cards_limit;
-extern struct drm_head **drm_heads;
+
extern struct class *drm_class;
extern struct proc_dir_entry *drm_proc_root;
+extern struct idr drm_minors_idr;
+
extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
/* Proc support (drm_proc.h) */
-extern int drm_proc_init(struct drm_device *dev,
- int minor,
- struct proc_dir_entry *root,
- struct proc_dir_entry **dev_root);
-extern int drm_proc_cleanup(int minor,
- struct proc_dir_entry *root,
- struct proc_dir_entry *dev_root);
+extern int drm_proc_init(struct drm_minor *minor, int minor_id,
+ struct proc_dir_entry *root);
+extern int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root);
/* Scatter Gather Support (drm_scatter.h) */
extern void drm_sg_cleanup(struct drm_sg_mem * entry);
@@ -1071,8 +1126,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
struct drm_sysfs_class;
extern struct class *drm_sysfs_create(struct module *owner, char *name);
extern void drm_sysfs_destroy(void);
-extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head);
-extern void drm_sysfs_device_remove(struct drm_device *dev);
+extern int drm_sysfs_device_add(struct drm_minor *minor);
+extern void drm_sysfs_device_remove(struct drm_minor *minor);
/*
* Basic memory manager support (drm_mm.c)
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c
index 9468c7889ff1..aefa5ac4c0b1 100644
--- a/drivers/char/drm/drm_agpsupport.c
+++ b/drivers/char/drm/drm_agpsupport.c
@@ -122,7 +122,7 @@ EXPORT_SYMBOL(drm_agp_acquire);
int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- return drm_agp_acquire((struct drm_device *) file_priv->head->dev);
+ return drm_agp_acquire((struct drm_device *) file_priv->minor->dev);
}
/**
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 0e7af53c87de..fc54140551a7 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -313,35 +313,36 @@ static void drm_cleanup(struct drm_device * dev)
drm_ht_remove(&dev->map_hash);
drm_ctxbitmap_cleanup(dev);
- drm_put_head(&dev->primary);
+ drm_put_minor(&dev->primary);
if (drm_put_dev(dev))
DRM_ERROR("Cannot unload module\n");
}
-void drm_exit(struct drm_driver *driver)
+int drm_minors_cleanup(int id, void *ptr, void *data)
{
- int i;
- struct drm_device *dev = NULL;
- struct drm_head *head;
+ struct drm_minor *minor = ptr;
+ struct drm_device *dev;
+ struct drm_driver *driver = data;
+
+ dev = minor->dev;
+ if (minor->dev->driver != driver)
+ return 0;
+
+ if (minor->type != DRM_MINOR_LEGACY)
+ return 0;
+ if (dev)
+ pci_dev_put(dev->pdev);
+ drm_cleanup(dev);
+ return 1;
+}
+
+void drm_exit(struct drm_driver *driver)
+{
DRM_DEBUG("\n");
- for (i = 0; i < drm_cards_limit; i++) {
- head = drm_heads[i];
- if (!head)
- continue;
- if (!head->dev)
- continue;
- if (head->dev->driver != driver)
- continue;
- dev = head->dev;
- if (dev) {
- /* release the pci driver */
- if (dev->pdev)
- pci_dev_put(dev->pdev);
- drm_cleanup(dev);
- }
- }
+ idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver);
+
DRM_INFO("Module unloaded\n");
}
@@ -357,13 +358,7 @@ static int __init drm_core_init(void)
{
int ret = -ENOMEM;
- drm_cards_limit =
- (drm_cards_limit <
- DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1);
- drm_heads =
- drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB);
- if (!drm_heads)
- goto err_p1;
+ idr_init(&drm_minors_idr);
if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
goto err_p1;
@@ -391,7 +386,8 @@ err_p3:
drm_sysfs_destroy();
err_p2:
unregister_chrdev(DRM_MAJOR, "drm");
- drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
+
+ idr_destroy(&drm_minors_idr);
err_p1:
return ret;
}
@@ -403,7 +399,7 @@ static void __exit drm_core_exit(void)
unregister_chrdev(DRM_MAJOR, "drm");
- drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
+ idr_destroy(&drm_minors_idr);
}
module_init(drm_core_init);
@@ -452,7 +448,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct drm_file *file_priv = filp->private_data;
- struct drm_device *dev = file_priv->head->dev;
+ struct drm_device *dev = file_priv->minor->dev;
struct drm_ioctl_desc *ioctl;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
@@ -465,7 +461,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
task_pid_nr(current), cmd, nr,
- (long)old_encode_dev(file_priv->head->device),
+ (long)old_encode_dev(file_priv->minor->device),
file_priv->authenticated);
if ((nr >= DRM_CORE_IOCTL_COUNT) &&
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index f09d4b5002b0..68f0da801ed8 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -129,16 +129,15 @@ static int drm_setup(struct drm_device * dev)
int drm_open(struct inode *inode, struct file *filp)
{
struct drm_device *dev = NULL;
- int minor = iminor(inode);
+ int minor_id = iminor(inode);
+ struct drm_minor *minor;
int retcode = 0;
- if (!((minor >= 0) && (minor < drm_cards_limit)))
+ minor = idr_find(&drm_minors_idr, minor_id);
+ if (!minor)
return -ENODEV;
- if (!drm_heads[minor])
- return -ENODEV;
-
- if (!(dev = drm_heads[minor]->dev))
+ if (!(dev = minor->dev))
return -ENODEV;
retcode = drm_open_helper(inode, filp, dev);
@@ -168,19 +167,18 @@ EXPORT_SYMBOL(drm_open);
int drm_stub_open(struct inode *inode, struct file *filp)
{
struct drm_device *dev = NULL;
- int minor = iminor(inode);
+ struct drm_minor *minor;
+ int minor_id = iminor(inode);
int err = -ENODEV;
const struct file_operations *old_fops;
DRM_DEBUG("\n");
- if (!((minor >= 0) && (minor < drm_cards_limit)))
- return -ENODEV;
-
- if (!drm_heads[minor])
+ minor = idr_find(&drm_minors_idr, minor_id);
+ if (!minor)
return -ENODEV;
- if (!(dev = drm_heads[minor]->dev))
+ if (!(dev = minor->dev))
return -ENODEV;
old_fops = filp->f_op;
@@ -225,7 +223,7 @@ static int drm_cpu_valid(void)
static int drm_open_helper(struct inode *inode, struct file *filp,
struct drm_device * dev)
{
- int minor = iminor(inode);
+ int minor_id = iminor(inode);
struct drm_file *priv;
int ret;
@@ -234,7 +232,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
if (!drm_cpu_valid())
return -EINVAL;
- DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor);
+ DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
if (!priv)
@@ -245,8 +243,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
priv->filp = filp;
priv->uid = current->euid;
priv->pid = task_pid_nr(current);
- priv->minor = minor;
- priv->head = drm_heads[minor];
+ priv->minor = idr_find(&drm_minors_idr, minor_id);
priv->ioctl_count = 0;
/* for compatibility root is always authenticated */
priv->authenticated = capable(CAP_SYS_ADMIN);
@@ -297,11 +294,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
int drm_fasync(int fd, struct file *filp, int on)
{
struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
int retcode;
DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
- (long)old_encode_dev(priv->head->device));
+ (long)old_encode_dev(priv->minor->device));
retcode = fasync_helper(fd, filp, on, &dev->buf_async);
if (retcode < 0)
return retcode;
@@ -324,7 +321,7 @@ EXPORT_SYMBOL(drm_fasync);
int drm_release(struct inode *inode, struct file *filp)
{
struct drm_file *file_priv = filp->private_data;
- struct drm_device *dev = file_priv->head->dev;
+ struct drm_device *dev = file_priv->minor->dev;
int retcode = 0;
unsigned long irqflags;
@@ -341,14 +338,14 @@ int drm_release(struct inode *inode, struct file *filp)
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
task_pid_nr(current),
- (long)old_encode_dev(file_priv->head->device),
+ (long)old_encode_dev(file_priv->minor->device),
dev->open_count);
if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
if (drm_i_have_hw_lock(dev, file_priv)) {
dev->driver->reclaim_buffers_locked(dev, file_priv);
} else {
- unsigned long _end=jiffies + 3*DRM_HZ;
+ unsigned long endtime = jiffies + 3 * DRM_HZ;
int locked = 0;
drm_idlelock_take(&dev->lock);
@@ -366,7 +363,7 @@ int drm_release(struct inode *inode, struct file *filp)
if (locked)
break;
schedule();
- } while (!time_after_eq(jiffies, _end));
+ } while (!time_after_eq(jiffies, endtime));
if (!locked) {
DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 089c015c01d1..286f9d61e7d5 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -71,6 +71,117 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
return 0;
}
+static void vblank_disable_fn(unsigned long arg)
+{
+ struct drm_device *dev = (struct drm_device *)arg;
+ unsigned long irqflags;
+ int i;
+
+ for (i = 0; i < dev->num_crtcs; i++) {
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
+ dev->vblank_enabled[i]) {
+ dev->driver->disable_vblank(dev, i);
+ dev->vblank_enabled[i] = 0;
+ }
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+ }
+}
+
+static void drm_vblank_cleanup(struct drm_device *dev)
+{
+ /* Bail if the driver didn't call drm_vblank_init() */
+ if (dev->num_crtcs == 0)
+ return;
+
+ del_timer(&dev->vblank_disable_timer);
+
+ vblank_disable_fn((unsigned long)dev);
+
+ drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+ drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
+ dev->num_crtcs, DRM_MEM_DRIVER);
+ drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs,
+ DRM_MEM_DRIVER);
+
+ dev->num_crtcs = 0;
+}
+
+int drm_vblank_init(struct drm_device *dev, int num_crtcs)
+{
+ int i, ret = -ENOMEM;
+
+ setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
+ (unsigned long)dev);
+ spin_lock_init(&dev->vbl_lock);
+ atomic_set(&dev->vbl_signal_pending, 0);
+ dev->num_crtcs = num_crtcs;
+
+ dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vbl_queue)
+ goto err;
+
+ dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vbl_sigs)
+ goto err;
+
+ dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->_vblank_count)
+ goto err;
+
+ dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_refcount)
+ goto err;
+
+ dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int),
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_enabled)
+ goto err;
+
+ dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
+ if (!dev->last_vblank)
+ goto err;
+
+ dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32),
+ DRM_MEM_DRIVER);
+ if (!dev->vblank_premodeset)
+ goto err;
+
+ dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
+ if (!dev->vblank_offset)
+ goto err;
+
+ /* Zero per-crtc vblank stuff */
+ for (i = 0; i < num_crtcs; i++) {
+ init_waitqueue_head(&dev->vbl_queue[i]);
+ INIT_LIST_HEAD(&dev->vbl_sigs[i]);
+ atomic_set(&dev->_vblank_count[i], 0);
+ atomic_set(&dev->vblank_refcount[i], 0);
+ }
+
+ return 0;
+
+err:
+ drm_vblank_cleanup(dev);
+ return ret;
+}
+EXPORT_SYMBOL(drm_vblank_init);
+
/**
* Install IRQ handler.
*
@@ -109,17 +220,6 @@ static int drm_irq_install(struct drm_device * dev)
DRM_DEBUG("irq=%d\n", dev->irq);
- if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
- init_waitqueue_head(&dev->vbl_queue);
-
- spin_lock_init(&dev->vbl_lock);
-
- INIT_LIST_HEAD(&dev->vbl_sigs);
- INIT_LIST_HEAD(&dev->vbl_sigs2);
-
- dev->vbl_pending = 0;
- }
-
/* Before installing handler */
dev->driver->irq_preinstall(dev);
@@ -137,9 +237,14 @@ static int drm_irq_install(struct drm_device * dev)
}
/* After installing handler */
- dev->driver->irq_postinstall(dev);
+ ret = dev->driver->irq_postinstall(dev);
+ if (ret < 0) {
+ mutex_lock(&dev->struct_mutex);
+ dev->irq_enabled = 0;
+ mutex_unlock(&dev->struct_mutex);
+ }
- return 0;
+ return ret;
}
/**
@@ -170,6 +275,8 @@ int drm_irq_uninstall(struct drm_device * dev)
free_irq(dev->irq, dev);
+ drm_vblank_cleanup(dev);
+
dev->locked_tasklet_func = NULL;
return 0;
@@ -214,6 +321,148 @@ int drm_control(struct drm_device *dev, void *data,
}
/**
+ * drm_vblank_count - retrieve "cooked" vblank counter value
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ */
+u32 drm_vblank_count(struct drm_device *dev, int crtc)
+{
+ return atomic_read(&dev->_vblank_count[crtc]) +
+ dev->vblank_offset[crtc];
+}
+EXPORT_SYMBOL(drm_vblank_count);
+
+/**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc). Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ */
+void drm_update_vblank_count(struct drm_device *dev, int crtc)
+{
+ unsigned long irqflags;
+ u32 cur_vblank, diff;
+
+ /*
+ * Interrupts were disabled prior to this call, so deal with counter
+ * wrap if needed.
+ * NOTE! It's possible we lost a full dev->max_vblank_count events
+ * here if the register is small or we had vblank interrupts off for
+ * a long time.
+ */
+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ if (cur_vblank < dev->last_vblank[crtc]) {
+ diff = dev->max_vblank_count -
+ dev->last_vblank[crtc];
+ diff += cur_vblank;
+ } else {
+ diff = cur_vblank - dev->last_vblank[crtc];
+ }
+ dev->last_vblank[crtc] = cur_vblank;
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+ atomic_add(diff, &dev->_vblank_count[crtc]);
+}
+EXPORT_SYMBOL(drm_update_vblank_count);
+
+/**
+ * drm_vblank_get - get a reference count on vblank events
+ * @dev: DRM device
+ * @crtc: which CRTC to own
+ *
+ * Acquire a reference count on vblank events to avoid having them disabled
+ * while in use. Note callers will probably want to update the master counter
+ * using drm_update_vblank_count() above before calling this routine so that
+ * wakeups occur on the right vblank event.
+ *
+ * RETURNS
+ * Zero on success, nonzero on failure.
+ */
+int drm_vblank_get(struct drm_device *dev, int crtc)
+{
+ unsigned long irqflags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ /* Going from 0->1 means we have to enable interrupts again */
+ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
+ !dev->vblank_enabled[crtc]) {
+ ret = dev->driver->enable_vblank(dev, crtc);
+ if (ret)
+ atomic_dec(&dev->vblank_refcount[crtc]);
+ else
+ dev->vblank_enabled[crtc] = 1;
+ }
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_vblank_get);
+
+/**
+ * drm_vblank_put - give up ownership of vblank events
+ * @dev: DRM device
+ * @crtc: which counter to give up
+ *
+ * Release ownership of a given vblank counter, turning off interrupts
+ * if possible.
+ */
+void drm_vblank_put(struct drm_device *dev, int crtc)
+{
+ /* Last user schedules interrupt disable */
+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
+ mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
+}
+EXPORT_SYMBOL(drm_vblank_put);
+
+/**
+ * drm_modeset_ctl - handle vblank event counter changes across mode switch
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
+ * ioctls around modesetting so that any lost vblank events are accounted for.
+ */
+int drm_modeset_ctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_modeset_ctl *modeset = data;
+ int crtc, ret = 0;
+ u32 new;
+
+ crtc = modeset->arg;
+ if (crtc >= dev->num_crtcs) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (modeset->cmd) {
+ case _DRM_PRE_MODESET:
+ dev->vblank_premodeset[crtc] =
+ dev->driver->get_vblank_counter(dev, crtc);
+ break;
+ case _DRM_POST_MODESET:
+ new = dev->driver->get_vblank_counter(dev, crtc);
+ dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ return ret;
+}
+
+/**
* Wait for VBLANK.
*
* \param inode device inode.
@@ -232,12 +481,13 @@ int drm_control(struct drm_device *dev, void *data,
*
* If a signal is not requested, then calls vblank_wait().
*/
-int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int drm_wait_vblank(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
union drm_wait_vblank *vblwait = data;
struct timeval now;
int ret = 0;
- unsigned int flags, seq;
+ unsigned int flags, seq, crtc;
if ((!dev->irq) || (!dev->irq_enabled))
return -EINVAL;
@@ -251,13 +501,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
}
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
+ crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
- if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
- DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+ if (crtc >= dev->num_crtcs)
return -EINVAL;
- seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
- : &dev->vbl_received);
+ drm_update_vblank_count(dev, crtc);
+ seq = drm_vblank_count(dev, crtc);
switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
@@ -276,8 +526,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
- struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
- ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+ struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
struct drm_vbl_sig *vbl_sig;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -298,22 +547,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
}
}
- if (dev->vbl_pending >= 100) {
+ if (atomic_read(&dev->vbl_signal_pending) >= 100) {
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
return -EBUSY;
}
- dev->vbl_pending++;
-
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- if (!
- (vbl_sig =
- drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
+ vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
+ DRM_MEM_DRIVER);
+ if (!vbl_sig)
return -ENOMEM;
+
+ ret = drm_vblank_get(dev, crtc);
+ if (ret) {
+ drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
+ DRM_MEM_DRIVER);
+ return ret;
}
- memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
+ atomic_inc(&dev->vbl_signal_pending);
vbl_sig->sequence = vblwait->request.sequence;
vbl_sig->info.si_signo = vblwait->request.signal;
@@ -327,17 +580,20 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
vblwait->reply.sequence = seq;
} else {
- if (flags & _DRM_VBLANK_SECONDARY) {
- if (dev->driver->vblank_wait2)
- ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
- } else if (dev->driver->vblank_wait)
- ret =
- dev->driver->vblank_wait(dev,
- &vblwait->request.sequence);
-
+ unsigned long cur_vblank;
+
+ ret = drm_vblank_get(dev, crtc);
+ if (ret)
+ return ret;
+ DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
+ (((cur_vblank = drm_vblank_count(dev, crtc))
+ - vblwait->request.sequence) <= (1 << 23)));
+ drm_vblank_put(dev, crtc);
do_gettimeofday(&now);
+
vblwait->reply.tval_sec = now.tv_sec;
vblwait->reply.tval_usec = now.tv_usec;
+ vblwait->reply.sequence = cur_vblank;
}
done:
@@ -348,44 +604,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
* Send the VBLANK signals.
*
* \param dev DRM device.
+ * \param crtc CRTC where the vblank event occurred
*
* Sends a signal for each task in drm_device::vbl_sigs and empties the list.
*
* If a signal is not requested, then calls vblank_wait().
*/
-void drm_vbl_send_signals(struct drm_device * dev)
+static void drm_vbl_send_signals(struct drm_device * dev, int crtc)
{
+ struct drm_vbl_sig *vbl_sig, *tmp;
+ struct list_head *vbl_sigs;
+ unsigned int vbl_seq;
unsigned long flags;
- int i;
spin_lock_irqsave(&dev->vbl_lock, flags);
- for (i = 0; i < 2; i++) {
- struct drm_vbl_sig *vbl_sig, *tmp;
- struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
- unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
- &dev->vbl_received);
+ vbl_sigs = &dev->vbl_sigs[crtc];
+ vbl_seq = drm_vblank_count(dev, crtc);
- list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
- if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
- vbl_sig->info.si_code = vbl_seq;
- send_sig_info(vbl_sig->info.si_signo,
- &vbl_sig->info, vbl_sig->task);
+ list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
+ if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+ vbl_sig->info.si_code = vbl_seq;
+ send_sig_info(vbl_sig->info.si_signo,
+ &vbl_sig->info, vbl_sig->task);
- list_del(&vbl_sig->head);
+ list_del(&vbl_sig->head);
- drm_free(vbl_sig, sizeof(*vbl_sig),
- DRM_MEM_DRIVER);
-
- dev->vbl_pending--;
- }
- }
+ drm_free(vbl_sig, sizeof(*vbl_sig),
+ DRM_MEM_DRIVER);
+ atomic_dec(&dev->vbl_signal_pending);
+ drm_vblank_put(dev, crtc);
+ }
}
spin_unlock_irqrestore(&dev->vbl_lock, flags);
}
-EXPORT_SYMBOL(drm_vbl_send_signals);
+/**
+ * drm_handle_vblank - handle a vblank event
+ * @dev: DRM device
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ */
+void drm_handle_vblank(struct drm_device *dev, int crtc)
+{
+ drm_update_vblank_count(dev, crtc);
+ DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ drm_vbl_send_signals(dev, crtc);
+}
+EXPORT_SYMBOL(drm_handle_vblank);
/**
* Tasklet wrapper function.
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index d9b560fe9bbe..93b1e0475c93 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -87,34 +87,35 @@ static struct drm_proc_list {
* "/proc/dri/%minor%/", and each entry in proc_list as
* "/proc/dri/%minor%/%name%".
*/
-int drm_proc_init(struct drm_device * dev, int minor,
- struct proc_dir_entry *root, struct proc_dir_entry **dev_root)
+int drm_proc_init(struct drm_minor *minor, int minor_id,
+ struct proc_dir_entry *root)
{
struct proc_dir_entry *ent;
int i, j;
char name[64];
- sprintf(name, "%d", minor);
- *dev_root = proc_mkdir(name, root);
- if (!*dev_root) {
+ sprintf(name, "%d", minor_id);
+ minor->dev_root = proc_mkdir(name, root);
+ if (!minor->dev_root) {
DRM_ERROR("Cannot create /proc/dri/%s\n", name);
return -1;
}
for (i = 0; i < DRM_PROC_ENTRIES; i++) {
ent = create_proc_entry(drm_proc_list[i].name,
- S_IFREG | S_IRUGO, *dev_root);
+ S_IFREG | S_IRUGO, minor->dev_root);
if (!ent) {
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
name, drm_proc_list[i].name);
for (j = 0; j < i; j++)
remove_proc_entry(drm_proc_list[i].name,
- *dev_root);
+ minor->dev_root);
remove_proc_entry(name, root);
+ minor->dev_root = NULL;
return -1;
}
ent->read_proc = drm_proc_list[i].f;
- ent->data = dev;
+ ent->data = minor;
}
return 0;
@@ -130,18 +131,17 @@ int drm_proc_init(struct drm_device * dev, int minor,
*
* Remove all proc entries created by proc_init().
*/
-int drm_proc_cleanup(int minor, struct proc_dir_entry *root,
- struct proc_dir_entry *dev_root)
+int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
{
int i;
char name[64];
- if (!root || !dev_root)
+ if (!root || !minor->dev_root)
return 0;
for (i = 0; i < DRM_PROC_ENTRIES; i++)
- remove_proc_entry(drm_proc_list[i].name, dev_root);
- sprintf(name, "%d", minor);
+ remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
+ sprintf(name, "%d", minor->index);
remove_proc_entry(name, root);
return 0;
@@ -163,7 +163,8 @@ int drm_proc_cleanup(int minor, struct proc_dir_entry *root,
static int drm_name_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
@@ -205,7 +206,8 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
static int drm__vm_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int len = 0;
struct drm_map *map;
struct drm_map_list *r_list;
@@ -261,7 +263,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
static int drm_vm_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -284,7 +287,8 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request,
static int drm__queues_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int len = 0;
int i;
struct drm_queue *q;
@@ -334,7 +338,8 @@ static int drm__queues_info(char *buf, char **start, off_t offset,
static int drm_queues_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -357,7 +362,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request,
static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int len = 0;
struct drm_device_dma *dma = dev->dma;
int i;
@@ -406,7 +412,8 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -429,7 +436,8 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
static int drm__clients_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int len = 0;
struct drm_file *priv;
@@ -445,7 +453,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,
list_for_each_entry(priv, &dev->filelist, lhead) {
DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n',
- priv->minor,
+ priv->minor->index,
priv->pid,
priv->uid, priv->magic, priv->ioctl_count);
}
@@ -462,7 +470,8 @@ static int drm__clients_info(char *buf, char **start, off_t offset,
static int drm_clients_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -476,7 +485,8 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int len = 0;
struct drm_vma_entry *pt;
struct vm_area_struct *vma;
@@ -535,7 +545,8 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
static int drm_vma_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
- struct drm_device *dev = (struct drm_device *) data;
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index d93a217f856a..c2f584f3b46c 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -36,23 +36,49 @@
#include "drmP.h"
#include "drm_core.h"
-unsigned int drm_cards_limit = 16; /* Enough for one machine */
unsigned int drm_debug = 0; /* 1 to enable debug output */
EXPORT_SYMBOL(drm_debug);
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
-MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
MODULE_PARM_DESC(debug, "Enable debug output");
-module_param_named(cards_limit, drm_cards_limit, int, 0444);
module_param_named(debug, drm_debug, int, 0600);
-struct drm_head **drm_heads;
+struct idr drm_minors_idr;
+
struct class *drm_class;
struct proc_dir_entry *drm_proc_root;
+static int drm_minor_get_id(struct drm_device *dev, int type)
+{
+ int new_id;
+ int ret;
+ int base = 0, limit = 63;
+
+again:
+ if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) {
+ DRM_ERROR("Out of memory expanding drawable idr\n");
+ return -ENOMEM;
+ }
+ mutex_lock(&dev->struct_mutex);
+ ret = idr_get_new_above(&drm_minors_idr, NULL,
+ base, &new_id);
+ mutex_unlock(&dev->struct_mutex);
+ if (ret == -EAGAIN) {
+ goto again;
+ } else if (ret) {
+ return ret;
+ }
+
+ if (new_id >= limit) {
+ idr_remove(&drm_minors_idr, new_id);
+ return -EINVAL;
+ }
+ return new_id;
+}
+
static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver)
@@ -145,48 +171,60 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
* create the proc init entry via proc_init(). This routines assigns
* minor numbers to secondary heads of multi-headed cards
*/
-static int drm_get_head(struct drm_device * dev, struct drm_head * head)
+static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
{
- struct drm_head **heads = drm_heads;
+ struct drm_minor *new_minor;
int ret;
- int minor;
+ int minor_id;
DRM_DEBUG("\n");
- for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
- if (!*heads) {
-
- *head = (struct drm_head) {
- .dev = dev,.device =
- MKDEV(DRM_MAJOR, minor),.minor = minor,};
-
- if ((ret =
- drm_proc_init(dev, minor, drm_proc_root,
- &head->dev_root))) {
- printk(KERN_ERR
- "DRM: Failed to initialize /proc/dri.\n");
- goto err_g1;
- }
-
- ret = drm_sysfs_device_add(dev, head);
- if (ret) {
- printk(KERN_ERR
- "DRM: Error sysfs_device_add.\n");
- goto err_g2;
- }
- *heads = head;
-
- DRM_DEBUG("new minor assigned %d\n", minor);
- return 0;
+ minor_id = drm_minor_get_id(dev, type);
+ if (minor_id < 0)
+ return minor_id;
+
+ new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
+ if (!new_minor) {
+ ret = -ENOMEM;
+ goto err_idr;
+ }
+
+ new_minor->type = type;
+ new_minor->device = MKDEV(DRM_MAJOR, minor_id);
+ new_minor->dev = dev;
+ new_minor->index = minor_id;
+
+ idr_replace(&drm_minors_idr, new_minor, minor_id);
+
+ if (type == DRM_MINOR_LEGACY) {
+ ret = drm_proc_init(new_minor, minor_id, drm_proc_root);
+ if (ret) {
+ DRM_ERROR("DRM: Failed to initialize /proc/dri.\n");
+ goto err_mem;
}
+ } else
+ new_minor->dev_root = NULL;
+
+ ret = drm_sysfs_device_add(new_minor);
+ if (ret) {
+ printk(KERN_ERR
+ "DRM: Error sysfs_device_add.\n");
+ goto err_g2;
}
- DRM_ERROR("out of minors\n");
- return -ENOMEM;
- err_g2:
- drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
- err_g1:
- *head = (struct drm_head) {
- .dev = NULL};
+ *minor = new_minor;
+
+ DRM_DEBUG("new minor assigned %d\n", minor_id);
+ return 0;
+
+
+err_g2:
+ if (new_minor->type == DRM_MINOR_LEGACY)
+ drm_proc_cleanup(new_minor, drm_proc_root);
+err_mem:
+ kfree(new_minor);
+err_idr:
+ idr_remove(&drm_minors_idr, minor_id);
+ *minor = NULL;
return ret;
}
@@ -222,12 +260,12 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g2;
}
- if ((ret = drm_get_head(dev, &dev->primary)))
+ if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
goto err_g2;
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
- driver->date, dev->primary.minor);
+ driver->date, dev->primary->index);
return 0;
@@ -276,18 +314,18 @@ int drm_put_dev(struct drm_device * dev)
* last minor released.
*
*/
-int drm_put_head(struct drm_head * head)
+int drm_put_minor(struct drm_minor **minor_p)
{
- int minor = head->minor;
-
- DRM_DEBUG("release secondary minor %d\n", minor);
-
- drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
- drm_sysfs_device_remove(head->dev);
+ struct drm_minor *minor = *minor_p;
+ DRM_DEBUG("release secondary minor %d\n", minor->index);
- *head = (struct drm_head) {.dev = NULL};
+ if (minor->type == DRM_MINOR_LEGACY)
+ drm_proc_cleanup(minor, drm_proc_root);
+ drm_sysfs_device_remove(minor);
- drm_heads[minor] = NULL;
+ idr_remove(&drm_minors_idr, minor->index);
+ kfree(minor);
+ *minor_p = NULL;
return 0;
}
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 05ed5043254f..7a1d9a782ddb 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -19,7 +19,7 @@
#include "drm_core.h"
#include "drmP.h"
-#define to_drm_device(d) container_of(d, struct drm_device, dev)
+#define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
/**
* drm_sysfs_suspend - DRM class suspend hook
@@ -31,7 +31,8 @@
*/
static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
{
- struct drm_device *drm_dev = to_drm_device(dev);
+ struct drm_minor *drm_minor = to_drm_minor(dev);
+ struct drm_device *drm_dev = drm_minor->dev;
printk(KERN_ERR "%s\n", __FUNCTION__);
@@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
*/
static int drm_sysfs_resume(struct device *dev)
{
- struct drm_device *drm_dev = to_drm_device(dev);
+ struct drm_minor *drm_minor = to_drm_minor(dev);
+ struct drm_device *drm_dev = drm_minor->dev;
if (drm_dev->driver->resume)
return drm_dev->driver->resume(drm_dev);
@@ -120,10 +122,11 @@ void drm_sysfs_destroy(void)
static ssize_t show_dri(struct device *device, struct device_attribute *attr,
char *buf)
{
- struct drm_device *dev = to_drm_device(device);
- if (dev->driver->dri_library_name)
- return dev->driver->dri_library_name(dev, buf);
- return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
+ struct drm_minor *drm_minor = to_drm_minor(device);
+ struct drm_device *drm_dev = drm_minor->dev;
+ if (drm_dev->driver->dri_library_name)
+ return drm_dev->driver->dri_library_name(drm_dev, buf);
+ return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);
}
static struct device_attribute device_attrs[] = {
@@ -152,25 +155,28 @@ static void drm_sysfs_device_release(struct device *dev)
* as the parent for the Linux device, and make sure it has a file containing
* the driver we're using (for userspace compatibility).
*/
-int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head)
+int drm_sysfs_device_add(struct drm_minor *minor)
{
int err;
int i, j;
+ char *minor_str;
- dev->dev.parent = &dev->pdev->dev;
- dev->dev.class = drm_class;
- dev->dev.release = drm_sysfs_device_release;
- dev->dev.devt = head->device;
- snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor);
+ minor->kdev.parent = &minor->dev->pdev->dev;
+ minor->kdev.class = drm_class;
+ minor->kdev.release = drm_sysfs_device_release;
+ minor->kdev.devt = minor->device;
+ minor_str = "card%d";
- err = device_register(&dev->dev);
+ snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index);
+
+ err = device_register(&minor->kdev);
if (err) {
DRM_ERROR("device add failed: %d\n", err);
goto err_out;
}
for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
- err = device_create_file(&dev->dev, &device_attrs[i]);
+ err = device_create_file(&minor->kdev, &device_attrs[i]);
if (err)
goto err_out_files;
}
@@ -180,8 +186,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head)
err_out_files:
if (i > 0)
for (j = 0; j < i; j++)
- device_remove_file(&dev->dev, &device_attrs[i]);
- device_unregister(&dev->dev);
+ device_remove_file(&minor->kdev, &device_attrs[i]);
+ device_unregister(&minor->kdev);
err_out:
return err;
@@ -194,11 +200,11 @@ err_out:
* This call unregisters and cleans up a class device that was created with a
* call to drm_sysfs_device_add()
*/
-void drm_sysfs_device_remove(struct drm_device *dev)
+void drm_sysfs_device_remove(struct drm_minor *minor)
{
int i;
for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
- device_remove_file(&dev->dev, &device_attrs[i]);
- device_unregister(&dev->dev);
+ device_remove_file(&minor->kdev, &device_attrs[i]);
+ device_unregister(&minor->kdev);
}
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 945df72a51a9..c234c6f24a8d 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -90,7 +90,7 @@ static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma)
static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_map *map = NULL;
struct drm_map_list *r_list;
struct drm_hash_item *hash;
@@ -207,7 +207,7 @@ static int drm_do_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
static void drm_vm_shm_close(struct vm_area_struct *vma)
{
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_vma_entry *pt, *temp;
struct drm_map *map;
struct drm_map_list *r_list;
@@ -286,7 +286,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_device_dma *dma = dev->dma;
unsigned long offset;
unsigned long page_nr;
@@ -321,7 +321,7 @@ static int drm_do_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_map *map = (struct drm_map *) vma->vm_private_data;
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_sg_mem *entry = dev->sg;
unsigned long offset;
unsigned long map_offset;
@@ -402,7 +402,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {
static void drm_vm_open_locked(struct vm_area_struct *vma)
{
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_vma_entry *vma_entry;
DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -420,7 +420,7 @@ static void drm_vm_open_locked(struct vm_area_struct *vma)
static void drm_vm_open(struct vm_area_struct *vma)
{
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
mutex_lock(&dev->struct_mutex);
drm_vm_open_locked(vma);
@@ -438,7 +438,7 @@ static void drm_vm_open(struct vm_area_struct *vma)
static void drm_vm_close(struct vm_area_struct *vma)
{
struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_vma_entry *pt, *temp;
DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -473,7 +473,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
struct drm_device_dma *dma;
unsigned long length = vma->vm_end - vma->vm_start;
- dev = priv->head->dev;
+ dev = priv->minor->dev;
dma = dev->dma;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
vma->vm_start, vma->vm_end, vma->vm_pgoff);
@@ -543,7 +543,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{
struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
struct drm_map *map = NULL;
unsigned long offset = 0;
struct drm_hash_item *hash;
@@ -640,12 +640,12 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
/* Don't let this area swap. Change when
DRM_KERNEL advisory is supported. */
vma->vm_flags |= VM_RESERVED;
- vma->vm_page_prot = drm_dma_prot(map->type, vma);
break;
case _DRM_SCATTER_GATHER:
vma->vm_ops = &drm_vm_sg_ops;
vma->vm_private_data = (void *)map;
vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = drm_dma_prot(map->type, vma);
break;
default:
return -EINVAL; /* This should never happen. */
@@ -661,7 +661,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
int drm_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = priv->minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 8d7ea81c4b66..e5de8ea41544 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -94,7 +94,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
drm_i810_buf_priv_t *buf_priv;
lock_kernel();
- dev = priv->head->dev;
+ dev = priv->minor->dev;
dev_priv = dev->dev_private;
buf = dev_priv->mmap_buffer;
buf_priv = buf->dev_private;
@@ -122,7 +122,7 @@ static const struct file_operations i810_buffer_fops = {
static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
{
- struct drm_device *dev = file_priv->head->dev;
+ struct drm_device *dev = file_priv->minor->dev;
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
drm_i810_private_t *dev_priv = dev->dev_private;
const struct file_operations *old_fops;
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 9df08105f4f3..60c9376be486 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -96,7 +96,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
drm_i830_buf_priv_t *buf_priv;
lock_kernel();
- dev = priv->head->dev;
+ dev = priv->minor->dev;
dev_priv = dev->dev_private;
buf = dev_priv->mmap_buffer;
buf_priv = buf->dev_private;
@@ -124,7 +124,7 @@ static const struct file_operations i830_buffer_fops = {
static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
{
- struct drm_device *dev = file_priv->head->dev;
+ struct drm_device *dev = file_priv->minor->dev;
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
drm_i830_private_t *dev_priv = dev->dev_private;
const struct file_operations *old_fops;
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index a043bb12301a..ef7bf143a80c 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -415,10 +415,13 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+ if (++dev_priv->counter > BREADCRUMB_MASK) {
+ dev_priv->counter = 1;
+ DRM_DEBUG("Breadcrumb counter wrapped around\n");
+ }
- if (dev_priv->counter > 0x7FFFFFFFUL)
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
BEGIN_LP_RING(4);
OUT_RING(CMD_STORE_DWORD_IDX);
@@ -428,6 +431,26 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
ADVANCE_LP_RING();
}
+int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t flush_cmd = CMD_MI_FLUSH;
+ RING_LOCALS;
+
+ flush_cmd |= flush;
+
+ i915_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(4);
+ OUT_RING(flush_cmd);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+
+ return 0;
+}
+
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
drm_i915_cmdbuffer_t * cmd)
{
@@ -511,52 +534,74 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
return 0;
}
-static int i915_dispatch_flip(struct drm_device * dev)
+static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 num_pages, current_page, next_page, dspbase;
+ int shift = 2 * plane, x, y;
RING_LOCALS;
- DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
- dev_priv->current_page,
- dev_priv->sarea_priv->pf_current_page);
+ /* Calculate display base offset */
+ num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
+ current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3;
+ next_page = (current_page + 1) % num_pages;
- i915_kernel_lost_context(dev);
-
- BEGIN_LP_RING(2);
- OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ switch (next_page) {
+ default:
+ case 0:
+ dspbase = dev_priv->sarea_priv->front_offset;
+ break;
+ case 1:
+ dspbase = dev_priv->sarea_priv->back_offset;
+ break;
+ case 2:
+ dspbase = dev_priv->sarea_priv->third_offset;
+ break;
+ }
- BEGIN_LP_RING(6);
- OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
- OUT_RING(0);
- if (dev_priv->current_page == 0) {
- OUT_RING(dev_priv->back_offset);
- dev_priv->current_page = 1;
+ if (plane == 0) {
+ x = dev_priv->sarea_priv->planeA_x;
+ y = dev_priv->sarea_priv->planeA_y;
} else {
- OUT_RING(dev_priv->front_offset);
- dev_priv->current_page = 0;
+ x = dev_priv->sarea_priv->planeB_x;
+ y = dev_priv->sarea_priv->planeB_y;
}
- OUT_RING(0);
- ADVANCE_LP_RING();
- BEGIN_LP_RING(2);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp;
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+ DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page,
+ dspbase);
BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
- OUT_RING(dev_priv->counter);
- OUT_RING(0);
+ OUT_RING(sync ? 0 :
+ (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP :
+ MI_WAIT_FOR_PLANE_A_FLIP)));
+ OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |
+ (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
+ OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
+ OUT_RING(dspbase);
ADVANCE_LP_RING();
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
- return 0;
+ dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
+ dev_priv->sarea_priv->pf_current_page |= next_page << shift;
+}
+
+void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
+
+ DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
+ planes, dev_priv->sarea_priv->pf_current_page);
+
+ i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
+
+ for (i = 0; i < 2; i++)
+ if (planes & (1 << i))
+ i915_do_dispatch_flip(dev, i, sync);
+
+ i915_emit_breadcrumb(dev);
+
}
static int i915_quiescent(struct drm_device * dev)
@@ -579,7 +624,6 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_batchbuffer_t *batch = data;
@@ -602,7 +646,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
ret = i915_dispatch_batchbuffer(dev, batch);
- sarea_priv->last_dispatch = (int)hw_status[5];
+ sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return ret;
}
@@ -610,7 +654,6 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_cmdbuffer_t *cmdbuf = data;
@@ -635,18 +678,51 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
return ret;
}
- sarea_priv->last_dispatch = (int)hw_status[5];
+ sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ return 0;
+}
+
+static int i915_do_cleanup_pageflip(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
+
+ DRM_DEBUG("\n");
+
+ for (i = 0, planes = 0; i < 2; i++)
+ if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
+ dev_priv->sarea_priv->pf_current_page =
+ (dev_priv->sarea_priv->pf_current_page &
+ ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
+
+ planes |= 1 << i;
+ }
+
+ if (planes)
+ i915_dispatch_flip(dev, planes, 0);
+
return 0;
}
static int i915_flip_bufs(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- DRM_DEBUG("%s\n", __FUNCTION__);
+ drm_i915_flip_t *param = data;
+
+ DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, file_priv);
- return i915_dispatch_flip(dev);
+ /* This is really planes */
+ if (param->pipes & ~0x3) {
+ DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n",
+ param->pipes);
+ return -EINVAL;
+ }
+
+ i915_dispatch_flip(dev, param->pipes, 0);
+
+ return 0;
}
static int i915_getparam(struct drm_device *dev, void *data,
@@ -807,6 +883,8 @@ void i915_driver_lastclose(struct drm_device * dev)
if (!dev_priv)
return;
+ if (drm_getsarea(dev) && dev_priv->sarea_priv)
+ i915_do_cleanup_pageflip(dev);
if (dev_priv->agp_heap)
i915_mem_takedown(&(dev_priv->agp_heap));
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 05c66cf03a9e..0431c00e2289 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -105,14 +105,29 @@ typedef struct _drm_i915_sarea {
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
- int pipeA_x;
- int pipeA_y;
- int pipeA_w;
- int pipeA_h;
- int pipeB_x;
- int pipeB_y;
- int pipeB_w;
- int pipeB_h;
+ int planeA_x;
+ int planeA_y;
+ int planeA_w;
+ int planeA_h;
+ int planeB_x;
+ int planeB_y;
+ int planeB_w;
+ int planeB_h;
+
+ /* Triple buffering */
+ drm_handle_t third_handle;
+ int third_offset;
+ int third_size;
+ unsigned int third_tiled;
+
+ /* buffer object handles for the static buffers. May change
+ * over the lifetime of the client, though it doesn't in our current
+ * implementation.
+ */
+ unsigned int front_bo_handle;
+ unsigned int back_bo_handle;
+ unsigned int third_bo_handle;
+ unsigned int depth_bo_handle;
} drm_i915_sarea_t;
/* Flags for perf_boxes
@@ -146,7 +161,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
-#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP)
+#define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t)
#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t)
#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t)
#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t)
@@ -161,6 +176,18 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+/* Asynchronous page flipping:
+ */
+typedef struct drm_i915_flip {
+ /*
+ * This is really talking about planes, and we could rename it
+ * except for the fact that some of the duplicated i915_drm.h files
+ * out there check for HAVE_I915_FLIP and so might pick up this
+ * version.
+ */
+ int pipes;
+} drm_i915_flip_t;
+
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
*/
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index b2b451dc4460..bb8f1b2fb383 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -533,8 +533,7 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
- DRIVER_IRQ_VBL2,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
.load = i915_driver_load,
.unload = i915_driver_unload,
.lastclose = i915_driver_lastclose,
@@ -542,8 +541,9 @@ static struct drm_driver driver = {
.suspend = i915_suspend,
.resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp,
- .vblank_wait = i915_driver_vblank_wait,
- .vblank_wait2 = i915_driver_vblank_wait2,
+ .get_vblank_counter = i915_get_vblank_counter,
+ .enable_vblank = i915_enable_vblank,
+ .disable_vblank = i915_disable_vblank,
.irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 675d88bda066..c614d78b3dfd 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -76,8 +76,9 @@ struct mem_block {
typedef struct _drm_i915_vbl_swap {
struct list_head head;
drm_drawable_t drw_id;
- unsigned int pipe;
+ unsigned int plane;
unsigned int sequence;
+ int flip;
} drm_i915_vbl_swap_t;
typedef struct drm_i915_private {
@@ -90,7 +91,7 @@ typedef struct drm_i915_private {
drm_dma_handle_t *status_page_dmah;
void *hw_status_page;
dma_addr_t dma_status_page;
- unsigned long counter;
+ uint32_t counter;
unsigned int status_gfx_addr;
drm_local_map_t hws_map;
@@ -103,13 +104,18 @@ typedef struct drm_i915_private {
wait_queue_head_t irq_queue;
atomic_t irq_received;
- atomic_t irq_emitted;
+ atomic_t irq_emited;
int tex_lru_log_granularity;
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
+ spinlock_t user_irq_lock;
+ int user_irq_refcount;
+ int fence_irq_on;
+ uint32_t irq_enable_reg;
+ int irq_enabled;
spinlock_t swaps_lock;
drm_i915_vbl_swap_t vbl_swaps;
@@ -216,7 +222,7 @@ extern void i915_driver_preclose(struct drm_device *dev,
extern int i915_driver_device_is_agp(struct drm_device * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
-
+extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);
/* i915_irq.c */
extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -227,7 +233,7 @@ extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequenc
extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev);
-extern void i915_driver_irq_postinstall(struct drm_device * dev);
+extern int i915_driver_irq_postinstall(struct drm_device * dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev);
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -235,6 +241,9 @@ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern int i915_enable_vblank(struct drm_device *dev, int crtc);
+extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -379,21 +388,91 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
/* Interrupt bits:
*/
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-#define HWB_OOM_FLAG (1<<13) /* binner out of memory */
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
+#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */
+#define I915_SYNC_STATUS_INTERRUPT (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4)
+#define I915_DEBUG_INTERRUPT (1<<2)
+#define I915_USER_INTERRUPT (1<<1)
+
#define I915REG_HWSTAM 0x02098
#define I915REG_INT_IDENTITY_R 0x020a4
#define I915REG_INT_MASK_R 0x020a8
#define I915REG_INT_ENABLE_R 0x020a0
+#define I915REG_INSTPM 0x020c0
+
+#define PIPEADSL 0x70000
+#define PIPEBDSL 0x71000
#define I915REG_PIPEASTAT 0x70024
#define I915REG_PIPEBSTAT 0x71024
+/*
+ * The two pipe frame counter registers are not synchronized, so
+ * reading a stable value is somewhat tricky. The following code
+ * should work:
+ *
+ * do {
+ * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ * PIPE_FRAME_HIGH_SHIFT;
+ * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >>
+ * PIPE_FRAME_LOW_SHIFT);
+ * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ * PIPE_FRAME_HIGH_SHIFT);
+ * } while (high1 != high2);
+ * frame = (high1 << 8) | low1;
+ */
+#define PIPEAFRAMEHIGH 0x70040
+#define PIPEBFRAMEHIGH 0x71040
+#define PIPE_FRAME_HIGH_MASK 0x0000ffff
+#define PIPE_FRAME_HIGH_SHIFT 0
+#define PIPEAFRAMEPIXEL 0x70044
+#define PIPEBFRAMEPIXEL 0x71044
-#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
-#define I915_VBLANK_CLEAR (1UL<<1)
+#define PIPE_FRAME_LOW_MASK 0xff000000
+#define PIPE_FRAME_LOW_SHIFT 24
+/*
+ * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register
+ * and is 24 bits wide.
+ */
+#define PIPE_PIXEL_MASK 0x00ffffff
+#define PIPE_PIXEL_SHIFT 0
+
+#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
+#define I915_CRC_ERROR_ENABLE (1UL<<29)
+#define I915_CRC_DONE_ENABLE (1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
+#define I915_DPST_EVENT_ENABLE (1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
+#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
+#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
+#define I915_DPST_EVENT_STATUS (1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
+#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
+#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
@@ -566,6 +645,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+#define XY_SRC_COPY_BLT_SRC_TILED (1<<15)
+#define XY_SRC_COPY_BLT_DST_TILED (1<<11)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index 92653b38e64c..023ce66ef3ab 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -38,6 +38,109 @@
#define MAX_NOPID ((u32)~0)
/**
+ * i915_get_pipe - return the the pipe associated with a given plane
+ * @dev: DRM device
+ * @plane: plane to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a pipe number, since they may not always be equal. This routine
+ * maps the given @plane back to a pipe number.
+ */
+static int
+i915_get_pipe(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 dspcntr;
+
+ dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
+
+ return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0;
+}
+
+/**
+ * i915_get_plane - return the the plane associated with a given pipe
+ * @dev: DRM device
+ * @pipe: pipe to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a plane number, since they may not always be equal. This routine
+ * maps the given @pipe back to a plane number.
+ */
+static int
+i915_get_plane(struct drm_device *dev, int pipe)
+{
+ if (i915_get_pipe(dev, 0) == pipe)
+ return 0;
+ return 1;
+}
+
+/**
+ * i915_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+static int
+i915_pipe_enabled(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
+
+ if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Emit a synchronous flip.
+ *
+ * This function must be called with the drawable spinlock held.
+ */
+static void
+i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
+ int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ u16 x1, y1, x2, y2;
+ int pf_planes = 1 << plane;
+
+ /* If the window is visible on the other plane, we have to flip on that
+ * plane as well.
+ */
+ if (plane == 1) {
+ x1 = sarea_priv->planeA_x;
+ y1 = sarea_priv->planeA_y;
+ x2 = x1 + sarea_priv->planeA_w;
+ y2 = y1 + sarea_priv->planeA_h;
+ } else {
+ x1 = sarea_priv->planeB_x;
+ y1 = sarea_priv->planeB_y;
+ x2 = x1 + sarea_priv->planeB_w;
+ y2 = y1 + sarea_priv->planeB_h;
+ }
+
+ if (x2 > 0 && y2 > 0) {
+ int i, num_rects = drw->num_rects;
+ struct drm_clip_rect *rect = drw->rects;
+
+ for (i = 0; i < num_rects; i++)
+ if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 ||
+ rect[i].x2 <= x1 || rect[i].y2 <= y1)) {
+ pf_planes = 0x3;
+
+ break;
+ }
+ }
+
+ i915_dispatch_flip(dev, pf_planes, 1);
+}
+
+/**
* Emit blits for scheduled buffer swaps.
*
* This function will be called with the HW lock held.
@@ -45,40 +148,59 @@
static void i915_vblank_tasklet(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long irqflags;
struct list_head *list, *tmp, hits, *hit;
- int nhits, nrects, slice[2], upper[2], lower[2], i;
- unsigned counter[2] = { atomic_read(&dev->vbl_received),
- atomic_read(&dev->vbl_received2) };
+ int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
+ unsigned counter[2];
struct drm_drawable_info *drw;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 cpp = dev_priv->cpp;
+ u32 cpp = dev_priv->cpp, offsets[3];
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB)
: XY_SRC_COPY_BLT_CMD;
- u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
- (cpp << 23) | (1 << 24);
+ u32 src_pitch = sarea_priv->pitch * cpp;
+ u32 dst_pitch = sarea_priv->pitch * cpp;
+ /* COPY rop (0xcc), map cpp to magic color depth constants */
+ u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
RING_LOCALS;
+ if (sarea_priv->front_tiled) {
+ cmd |= XY_SRC_COPY_BLT_DST_TILED;
+ dst_pitch >>= 2;
+ }
+ if (sarea_priv->back_tiled) {
+ cmd |= XY_SRC_COPY_BLT_SRC_TILED;
+ src_pitch >>= 2;
+ }
+
+ counter[0] = drm_vblank_count(dev, 0);
+ counter[1] = drm_vblank_count(dev, 1);
+
DRM_DEBUG("\n");
INIT_LIST_HEAD(&hits);
nhits = nrects = 0;
- spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+ /* No irqsave/restore necessary. This tasklet may be run in an
+ * interrupt context or normal context, but we don't have to worry
+ * about getting interrupted by something acquiring the lock, because
+ * we are the interrupt context thing that acquires the lock.
+ */
+ spin_lock(&dev_priv->swaps_lock);
/* Find buffer swaps scheduled for this vertical blank */
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
drm_i915_vbl_swap_t *vbl_swap =
list_entry(list, drm_i915_vbl_swap_t, head);
+ int pipe = i915_get_pipe(dev, vbl_swap->plane);
- if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
+ if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
continue;
list_del(list);
dev_priv->swaps_pending--;
+ drm_vblank_put(dev, pipe);
spin_unlock(&dev_priv->swaps_lock);
spin_lock(&dev->drw_lock);
@@ -116,33 +238,23 @@ static void i915_vblank_tasklet(struct drm_device *dev)
spin_lock(&dev_priv->swaps_lock);
}
- if (nhits == 0) {
- spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
- return;
- }
-
spin_unlock(&dev_priv->swaps_lock);
- i915_kernel_lost_context(dev);
-
- BEGIN_LP_RING(6);
-
- OUT_RING(GFX_OP_DRAWRECT_INFO);
- OUT_RING(0);
- OUT_RING(0);
- OUT_RING(sarea_priv->width | sarea_priv->height << 16);
- OUT_RING(sarea_priv->width | sarea_priv->height << 16);
- OUT_RING(0);
-
- ADVANCE_LP_RING();
+ if (nhits == 0)
+ return;
- sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+ i915_kernel_lost_context(dev);
upper[0] = upper[1] = 0;
- slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
- slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
- lower[0] = sarea_priv->pipeA_y + slice[0];
- lower[1] = sarea_priv->pipeB_y + slice[0];
+ slice[0] = max(sarea_priv->planeA_h / nhits, 1);
+ slice[1] = max(sarea_priv->planeB_h / nhits, 1);
+ lower[0] = sarea_priv->planeA_y + slice[0];
+ lower[1] = sarea_priv->planeB_y + slice[0];
+
+ offsets[0] = sarea_priv->front_offset;
+ offsets[1] = sarea_priv->back_offset;
+ offsets[2] = sarea_priv->third_offset;
+ num_pages = sarea_priv->third_handle ? 3 : 2;
spin_lock(&dev->drw_lock);
@@ -154,6 +266,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
for (i = 0; i++ < nhits;
upper[0] = lower[0], lower[0] += slice[0],
upper[1] = lower[1], lower[1] += slice[1]) {
+ int init_drawrect = 1;
+
if (i == nhits)
lower[0] = lower[1] = sarea_priv->height;
@@ -161,7 +275,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
drm_i915_vbl_swap_t *swap_hit =
list_entry(hit, drm_i915_vbl_swap_t, head);
struct drm_clip_rect *rect;
- int num_rects, pipe;
+ int num_rects, plane, front, back;
unsigned short top, bottom;
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
@@ -169,10 +283,50 @@ static void i915_vblank_tasklet(struct drm_device *dev)
if (!drw)
continue;
+ plane = swap_hit->plane;
+
+ if (swap_hit->flip) {
+ i915_dispatch_vsync_flip(dev, drw, plane);
+ continue;
+ }
+
+ if (init_drawrect) {
+ int width = sarea_priv->width;
+ int height = sarea_priv->height;
+ if (IS_I965G(dev)) {
+ BEGIN_LP_RING(4);
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+ OUT_RING(0);
+ OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
+ OUT_RING(0);
+
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(6);
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
+ OUT_RING(0);
+ OUT_RING(0);
+
+ ADVANCE_LP_RING();
+ }
+
+ sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+ init_drawrect = 0;
+ }
+
rect = drw->rects;
- pipe = swap_hit->pipe;
- top = upper[pipe];
- bottom = lower[pipe];
+ top = upper[plane];
+ bottom = lower[plane];
+
+ front = (dev_priv->sarea_priv->pf_current_page >>
+ (2 * plane)) & 0x3;
+ back = (front + 1) % num_pages;
for (num_rects = drw->num_rects; num_rects--; rect++) {
int y1 = max(rect->y1, top);
@@ -184,20 +338,20 @@ static void i915_vblank_tasklet(struct drm_device *dev)
BEGIN_LP_RING(8);
OUT_RING(cmd);
- OUT_RING(pitchropcpp);
+ OUT_RING(ropcpp | dst_pitch);
OUT_RING((y1 << 16) | rect->x1);
OUT_RING((y2 << 16) | rect->x2);
- OUT_RING(sarea_priv->front_offset);
+ OUT_RING(offsets[front]);
OUT_RING((y1 << 16) | rect->x1);
- OUT_RING(pitchropcpp & 0xffff);
- OUT_RING(sarea_priv->back_offset);
+ OUT_RING(src_pitch);
+ OUT_RING(offsets[back]);
ADVANCE_LP_RING();
}
}
}
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ spin_unlock(&dev->drw_lock);
list_for_each_safe(hit, tmp, &hits) {
drm_i915_vbl_swap_t *swap_hit =
@@ -209,67 +363,112 @@ static void i915_vblank_tasklet(struct drm_device *dev)
}
}
+u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long high_frame;
+ unsigned long low_frame;
+ u32 high1, high2, low, count;
+ int pipe;
+
+ pipe = i915_get_pipe(dev, plane);
+ high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+ low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+ if (!i915_pipe_enabled(dev, pipe)) {
+ printk(KERN_ERR "trying to get vblank count for disabled "
+ "pipe %d\n", pipe);
+ return 0;
+ }
+
+ /*
+ * High & low register fields aren't synchronized, so make sure
+ * we get a low value that's stable across two reads of the high
+ * register.
+ */
+ do {
+ high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+ PIPE_FRAME_LOW_SHIFT);
+ high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+ PIPE_FRAME_HIGH_SHIFT);
+ } while (high1 != high2);
+
+ count = (high1 << 8) | low;
+
+ /* count may be reset by other driver(e.g. 2D driver),
+ we have no way to know if it is wrapped or resetted
+ when count is zero. do a rough guess.
+ */
+ if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2)
+ dev->last_vblank[pipe] = 0;
+
+ return count;
+}
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
+ u32 iir;
u32 pipea_stats, pipeb_stats;
-
- pipea_stats = I915_READ(I915REG_PIPEASTAT);
- pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
-
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
-
- temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
-
- DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
-
- if (temp == 0)
+ int vblank = 0;
+
+ iir = I915_READ(I915REG_INT_IDENTITY_R);
+ if (iir == 0) {
+ DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n",
+ iir,
+ I915_READ(I915REG_INT_MASK_R),
+ I915_READ(I915REG_INT_ENABLE_R),
+ I915_READ(I915REG_PIPEASTAT),
+ I915_READ(I915REG_PIPEBSTAT));
return IRQ_NONE;
+ }
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
- (void) I915_READ16(I915REG_INT_IDENTITY_R);
- DRM_READMEMORYBARRIER();
-
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ /*
+ * Clear the PIPE(A|B)STAT regs before the IIR otherwise
+ * we may get extra interrupts.
+ */
+ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+ pipea_stats = I915_READ(I915REG_PIPEASTAT);
+ if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
+ I915_VBLANK_INTERRUPT_STATUS))
+ {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 0));
+ }
+ I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
+ }
+ if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+ pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
+ if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
+ I915_VBLANK_INTERRUPT_STATUS))
+ {
+ vblank++;
+ drm_handle_vblank(dev, i915_get_plane(dev, 1));
+ }
+ I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats);
+ }
- if (temp & USER_INT_FLAG)
- DRM_WAKEUP(&dev_priv->irq_queue);
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
- int vblank_pipe = dev_priv->vblank_pipe;
-
- if ((vblank_pipe &
- (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
- == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
- if (temp & VSYNC_PIPEA_FLAG)
- atomic_inc(&dev->vbl_received);
- if (temp & VSYNC_PIPEB_FLAG)
- atomic_inc(&dev->vbl_received2);
- } else if (((temp & VSYNC_PIPEA_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
- ((temp & VSYNC_PIPEB_FLAG) &&
- (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
- atomic_inc(&dev->vbl_received);
-
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ I915_WRITE(I915REG_INT_IDENTITY_R, iir);
+ (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */
+ if (iir & I915_USER_INTERRUPT) {
+ DRM_WAKEUP(&dev_priv->irq_queue);
+ }
+ if (vblank) {
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
- I915_WRITE(I915REG_PIPEASTAT,
- pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
- I915_WRITE(I915REG_PIPEBSTAT,
- pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
- I915_VBLANK_CLEAR);
}
return IRQ_HANDLED;
}
-static int i915_emit_irq(struct drm_device * dev)
+static int i915_emit_irq(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -316,42 +515,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- return ret;
-}
-
-static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
- atomic_t *counter)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1<<23)));
-
- *sequence = cur_vblank;
-
+ if (dev_priv->sarea_priv)
+ dev_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
return ret;
}
-
-int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
-}
-
-int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
- return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
-}
-
/* Needs the lock as it touches the ring.
*/
int i915_irq_emit(struct drm_device *dev, void *data,
@@ -394,18 +563,96 @@ int i915_irq_wait(struct drm_device *dev, void *data,
return i915_wait_irq(dev, irqwait->irq_seq);
}
+int i915_enable_vblank(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe = i915_get_pipe(dev, plane);
+ u32 pipestat_reg = 0;
+ u32 pipestat;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = I915REG_PIPEASTAT;
+ dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = I915REG_PIPEBSTAT;
+ dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
+ pipe);
+ break;
+ }
+
+ if (pipestat_reg)
+ {
+ pipestat = I915_READ (pipestat_reg);
+ /*
+ * Older chips didn't have the start vblank interrupt,
+ * but
+ */
+ if (IS_I965G (dev))
+ pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE;
+ else
+ pipestat |= I915_VBLANK_INTERRUPT_ENABLE;
+ /*
+ * Clear any pending status
+ */
+ pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
+ I915_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ }
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+
+ return 0;
+}
+
+void i915_disable_vblank(struct drm_device *dev, int plane)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe = i915_get_pipe(dev, plane);
+ u32 pipestat_reg = 0;
+ u32 pipestat;
+
+ switch (pipe) {
+ case 0:
+ pipestat_reg = I915REG_PIPEASTAT;
+ dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+ break;
+ case 1:
+ pipestat_reg = I915REG_PIPEBSTAT;
+ dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+ break;
+ default:
+ DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
+ pipe);
+ break;
+ }
+
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ if (pipestat_reg)
+ {
+ pipestat = I915_READ (pipestat_reg);
+ pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE |
+ I915_VBLANK_INTERRUPT_ENABLE);
+ /*
+ * Clear any pending status
+ */
+ pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
+ I915_VBLANK_INTERRUPT_STATUS);
+ I915_WRITE(pipestat_reg, pipestat);
+ }
+}
+
static void i915_enable_interrupt (struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 flag;
- flag = 0;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
- flag |= VSYNC_PIPEA_FLAG;
- if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
- flag |= VSYNC_PIPEB_FLAG;
+ dev_priv->irq_enable_reg |= I915_USER_INTERRUPT;
- I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ dev_priv->irq_enabled = 1;
}
/* Set the vblank monitor pipe
@@ -428,8 +675,6 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
dev_priv->vblank_pipe = pipe->pipe;
- i915_enable_interrupt (dev);
-
return 0;
}
@@ -447,9 +692,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
flag = I915_READ(I915REG_INT_ENABLE_R);
pipe->pipe = 0;
- if (flag & VSYNC_PIPEA_FLAG)
+ if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)
pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
- if (flag & VSYNC_PIPEB_FLAG)
+ if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
return 0;
@@ -464,27 +709,30 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_swap_t *swap = data;
drm_i915_vbl_swap_t *vbl_swap;
- unsigned int pipe, seqtype, curseq;
+ unsigned int pipe, seqtype, curseq, plane;
unsigned long irqflags;
struct list_head *list;
+ int ret;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
- if (dev_priv->sarea_priv->rotation) {
+ if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) {
DRM_DEBUG("Rotation not supported\n");
return -EINVAL;
}
if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
- _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS |
+ _DRM_VBLANK_FLIP)) {
DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
return -EINVAL;
}
- pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+ plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+ pipe = i915_get_pipe(dev, plane);
seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
@@ -495,6 +743,11 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
spin_lock_irqsave(&dev->drw_lock, irqflags);
+ /* It makes no sense to schedule a swap for a drawable that doesn't have
+ * valid information at this point. E.g. this could mean that the X
+ * server is too old to push drawable information to the DRM, in which
+ * case all such swaps would become ineffective.
+ */
if (!drm_get_drawable_info(dev, swap->drawable)) {
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
@@ -503,7 +756,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+ drm_update_vblank_count(dev, pipe);
+ curseq = drm_vblank_count(dev, pipe);
if (seqtype == _DRM_VBLANK_RELATIVE)
swap->sequence += curseq;
@@ -517,14 +771,43 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
}
}
+ if (swap->seqtype & _DRM_VBLANK_FLIP) {
+ swap->sequence--;
+
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ struct drm_drawable_info *drw;
+
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+ spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+ drw = drm_get_drawable_info(dev, swap->drawable);
+
+ if (!drw) {
+ spin_unlock_irqrestore(&dev->drw_lock,
+ irqflags);
+ DRM_DEBUG("Invalid drawable ID %d\n",
+ swap->drawable);
+ return -EINVAL;
+ }
+
+ i915_dispatch_vsync_flip(dev, drw, plane);
+
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+ return 0;
+ }
+ }
+
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
list_for_each(list, &dev_priv->vbl_swaps.head) {
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
if (vbl_swap->drw_id == swap->drawable &&
- vbl_swap->pipe == pipe &&
+ vbl_swap->plane == plane &&
vbl_swap->sequence == swap->sequence) {
+ vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_DEBUG("Already scheduled\n");
return 0;
@@ -547,9 +830,19 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
DRM_DEBUG("\n");
+ ret = drm_vblank_get(dev, pipe);
+ if (ret) {
+ drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+ return ret;
+ }
+
vbl_swap->drw_id = swap->drawable;
- vbl_swap->pipe = pipe;
+ vbl_swap->plane = plane;
vbl_swap->sequence = swap->sequence;
+ vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+
+ if (vbl_swap->flip)
+ swap->sequence++;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -567,37 +860,57 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_HWSTAM, 0xfffe);
+ I915_WRITE16(I915REG_HWSTAM, 0xeffe);
I915_WRITE16(I915REG_INT_MASK_R, 0x0);
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}
-void i915_driver_irq_postinstall(struct drm_device * dev)
+int i915_driver_irq_postinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int ret, num_pipes = 2;
spin_lock_init(&dev_priv->swaps_lock);
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
- if (!dev_priv->vblank_pipe)
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
+ dev_priv->user_irq_refcount = 0;
+ dev_priv->irq_enable_reg = 0;
+
+ ret = drm_vblank_init(dev, num_pipes);
+ if (ret)
+ return ret;
+
+ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+
i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+
+ /*
+ * Initialize the hardware status page IRQ location.
+ */
+
+ I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
+ return 0;
}
void i915_driver_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u16 temp;
+ u32 temp;
if (!dev_priv)
return;
- I915_WRITE16(I915REG_HWSTAM, 0xffff);
- I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
-
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ dev_priv->irq_enabled = 0;
+ I915_WRITE(I915REG_HWSTAM, 0xffffffff);
+ I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
+ I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
+
+ temp = I915_READ(I915REG_PIPEASTAT);
+ I915_WRITE(I915REG_PIPEASTAT, temp);
+ temp = I915_READ(I915REG_PIPEBSTAT);
+ I915_WRITE(I915REG_PIPEBSTAT, temp);
+ temp = I915_READ(I915REG_INT_IDENTITY_R);
+ I915_WRITE(I915REG_INT_IDENTITY_R, temp);
}
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 5572939fc7d1..6b3790939e76 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
- DRIVER_IRQ_VBL,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load,
.unload = mga_driver_unload,
.lastclose = mga_driver_lastclose,
.dma_quiescent = mga_driver_dma_quiescent,
.device_is_agp = mga_driver_device_is_agp,
- .vblank_wait = mga_driver_vblank_wait,
+ .get_vblank_counter = mga_get_vblank_counter,
+ .enable_vblank = mga_enable_vblank,
+ .disable_vblank = mga_disable_vblank,
.irq_preinstall = mga_driver_irq_preinstall,
.irq_postinstall = mga_driver_irq_postinstall,
.irq_uninstall = mga_driver_irq_uninstall,
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index f6ebd24bd587..8f7291f36363 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -120,6 +120,7 @@ typedef struct drm_mga_private {
u32 clear_cmd;
u32 maccess;
+ atomic_t vbl_received; /**< Number of vblanks received. */
wait_queue_head_t fence_queue;
atomic_t last_fence_retired;
u32 next_fence_to_post;
@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv);
/* mga_irq.c */
+extern int mga_enable_vblank(struct drm_device *dev, int crtc);
+extern void mga_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(struct drm_device * dev);
-extern void mga_driver_irq_postinstall(struct drm_device * dev);
+extern int mga_driver_irq_postinstall(struct drm_device * dev);
extern void mga_driver_irq_uninstall(struct drm_device * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c
index 9302cb8f0f83..06852fb4b278 100644
--- a/drivers/char/drm/mga_irq.c
+++ b/drivers/char/drm/mga_irq.c
@@ -35,6 +35,20 @@
#include "mga_drm.h"
#include "mga_drv.h"
+u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ const drm_mga_private_t *const dev_priv =
+ (drm_mga_private_t *) dev->dev_private;
+
+ if (crtc != 0) {
+ return 0;
+ }
+
+
+ return atomic_read(&dev_priv->vbl_received);
+}
+
+
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -47,9 +61,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */
if (status & MGA_VLINEPEN) {
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
- atomic_inc(&dev->vbl_received);
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ atomic_inc(&dev_priv->vbl_received);
+ drm_handle_vblank(dev, 0);
handled = 1;
}
@@ -78,22 +91,34 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
}
-int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int mga_enable_vblank(struct drm_device *dev, int crtc)
{
- unsigned int cur_vblank;
- int ret = 0;
+ drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
- - *sequence) <= (1 << 23)));
+ if (crtc != 0) {
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ return 0;
+ }
- *sequence = cur_vblank;
+ MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+ return 0;
+}
- return ret;
+
+void mga_disable_vblank(struct drm_device *dev, int crtc)
+{
+ if (crtc != 0) {
+ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+ crtc);
+ }
+
+ /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
+ * a nice hardware counter that tracks the number of refreshes when
+ * the interrupt is disabled, and the kernel doesn't know the refresh
+ * rate to calculate an estimate.
+ */
+ /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
}
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
@@ -125,14 +150,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
MGA_WRITE(MGA_ICLEAR, ~0);
}
-void mga_driver_irq_postinstall(struct drm_device * dev)
+int mga_driver_irq_postinstall(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+ int ret;
+
+ ret = drm_vblank_init(dev, 1);
+ if (ret)
+ return ret;
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
- /* Turn on vertical blank interrupt and soft trap interrupt. */
- MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+ /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
+ * in mga_enable_vblank.
+ */
+ MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
+ return 0;
}
void mga_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index f36adbd3aaf5..c31afbde62e7 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -817,7 +817,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev)
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->file_priv == 0)
+ if (!buf->file_priv)
return buf;
}
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index 6108e7587e12..2888aa01ebc7 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
- DRIVER_IRQ_VBL,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
.preclose = r128_driver_preclose,
.lastclose = r128_driver_lastclose,
- .vblank_wait = r128_driver_vblank_wait,
+ .get_vblank_counter = r128_get_vblank_counter,
+ .enable_vblank = r128_enable_vblank,
+ .disable_vblank = r128_disable_vblank,
.irq_preinstall = r128_driver_irq_preinstall,
.irq_postinstall = r128_driver_irq_postinstall,
.irq_uninstall = r128_driver_irq_uninstall,
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 011105e51ac6..80af9e09e75d 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -97,6 +97,8 @@ typedef struct drm_r128_private {
u32 crtc_offset;
u32 crtc_offset_cntl;
+ atomic_t vbl_received;
+
u32 color_fmt;
unsigned int front_offset;
unsigned int front_pitch;
@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
extern int r128_do_cleanup_cce(struct drm_device * dev);
-extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
-
+extern int r128_enable_vblank(struct drm_device *dev, int crtc);
+extern void r128_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
extern void r128_driver_irq_preinstall(struct drm_device * dev);
-extern void r128_driver_irq_postinstall(struct drm_device * dev);
+extern int r128_driver_irq_postinstall(struct drm_device * dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev);
extern void r128_driver_preclose(struct drm_device * dev,
diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c
index c76fdca7662d..5b95bd898f95 100644
--- a/drivers/char/drm/r128_irq.c
+++ b/drivers/char/drm/r128_irq.c
@@ -35,6 +35,16 @@
#include "r128_drm.h"
#include "r128_drv.h"
+u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ const drm_r128_private_t *dev_priv = dev->dev_private;
+
+ if (crtc != 0)
+ return 0;
+
+ return atomic_read(&dev_priv->vbl_received);
+}
+
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */
if (status & R128_CRTC_VBLANK_INT) {
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
- atomic_inc(&dev->vbl_received);
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ atomic_inc(&dev_priv->vbl_received);
+ drm_handle_vblank(dev, 0);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
-int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int r128_enable_vblank(struct drm_device *dev, int crtc)
{
- unsigned int cur_vblank;
- int ret = 0;
+ drm_r128_private_t *dev_priv = dev->dev_private;
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
- - *sequence) <= (1 << 23)));
+ if (crtc != 0) {
+ DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
+ return -EINVAL;
+ }
- *sequence = cur_vblank;
+ R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+ return 0;
+}
+
+void r128_disable_vblank(struct drm_device *dev, int crtc)
+{
+ if (crtc != 0)
+ DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
- return ret;
+ /*
+ * FIXME: implement proper interrupt disable by using the vblank
+ * counter register (if available)
+ *
+ * R128_WRITE(R128_GEN_INT_CNTL,
+ * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
+ */
}
void r128_driver_irq_preinstall(struct drm_device * dev)
@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
}
-void r128_driver_irq_postinstall(struct drm_device * dev)
+int r128_driver_irq_postinstall(struct drm_device * dev)
{
- drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
-
- /* Turn on VBL interrupt */
- R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+ return drm_vblank_init(dev, 1);
}
void r128_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index 349ac3d3b848..a2610319624d 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -59,8 +59,7 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
- DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
+ DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
.load = radeon_driver_load,
.firstopen = radeon_driver_firstopen,
@@ -69,8 +68,9 @@ static struct drm_driver driver = {
.postclose = radeon_driver_postclose,
.lastclose = radeon_driver_lastclose,
.unload = radeon_driver_unload,
- .vblank_wait = radeon_driver_vblank_wait,
- .vblank_wait2 = radeon_driver_vblank_wait2,
+ .get_vblank_counter = radeon_get_vblank_counter,
+ .enable_vblank = radeon_enable_vblank,
+ .disable_vblank = radeon_disable_vblank,
.dri_library_name = dri_library_name,
.irq_preinstall = radeon_driver_irq_preinstall,
.irq_postinstall = radeon_driver_irq_postinstall,
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 173ae620223a..b791420bd3d9 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -304,6 +304,9 @@ typedef struct drm_radeon_private {
u32 scratch_ages[5];
+ unsigned int crtc_last_cnt;
+ unsigned int crtc2_last_cnt;
+
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
unsigned long fb_aper_offset;
@@ -374,13 +377,13 @@ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_do_release(struct drm_device * dev);
-extern int radeon_driver_vblank_wait(struct drm_device * dev,
- unsigned int *sequence);
-extern int radeon_driver_vblank_wait2(struct drm_device * dev,
- unsigned int *sequence);
+extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
+extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
+extern void radeon_do_release(struct drm_device * dev);
extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
extern void radeon_driver_irq_preinstall(struct drm_device * dev);
-extern void radeon_driver_irq_postinstall(struct drm_device * dev);
+extern int radeon_driver_irq_postinstall(struct drm_device * dev);
extern void radeon_driver_irq_uninstall(struct drm_device * dev);
extern int radeon_vblank_crtc_get(struct drm_device *dev);
extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
@@ -558,6 +561,12 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \
: RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
+#define RADEON_CRTC_CRNT_FRAME 0x0214
+#define RADEON_CRTC2_CRNT_FRAME 0x0314
+
+#define RADEON_CRTC_STATUS 0x005c
+#define RADEON_CRTC2_STATUS 0x03fc
+
#define RADEON_GEN_INT_CNTL 0x0040
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
# define RADEON_CRTC2_VBLANK_MASK (1 << 9)
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index 009af3814b6f..507d6b747a13 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -35,12 +35,61 @@
#include "radeon_drm.h"
#include "radeon_drv.h"
-static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
- u32 mask)
+static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
{
- u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if (state)
+ dev_priv->irq_enable_reg |= mask;
+ else
+ dev_priv->irq_enable_reg &= ~mask;
+
+ RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+}
+
+int radeon_enable_vblank(struct drm_device *dev, int crtc)
+{
+ switch (crtc) {
+ case 0:
+ radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
+ break;
+ case 1:
+ radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+void radeon_disable_vblank(struct drm_device *dev, int crtc)
+{
+ switch (crtc) {
+ case 0:
+ radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
+ break;
+ case 1:
+ radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
+ break;
+ default:
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+ crtc);
+ break;
+ }
+}
+
+static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)
+{
+ u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
+ (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT);
+
if (irqs)
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
+
return irqs;
}
@@ -72,39 +121,21 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
/* Only consider the bits we're interested in - others could be used
* outside the DRM
*/
- stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT |
- RADEON_CRTC2_VBLANK_STAT));
+ stat = radeon_acknowledge_irqs(dev_priv);
if (!stat)
return IRQ_NONE;
stat &= dev_priv->irq_enable_reg;
/* SW interrupt */
- if (stat & RADEON_SW_INT_TEST) {
+ if (stat & RADEON_SW_INT_TEST)
DRM_WAKEUP(&dev_priv->swi_queue);
- }
/* VBLANK interrupt */
- if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
- int vblank_crtc = dev_priv->vblank_crtc;
-
- if ((vblank_crtc &
- (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
- (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
- if (stat & RADEON_CRTC_VBLANK_STAT)
- atomic_inc(&dev->vbl_received);
- if (stat & RADEON_CRTC2_VBLANK_STAT)
- atomic_inc(&dev->vbl_received2);
- } else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
- (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
- ((stat & RADEON_CRTC2_VBLANK_STAT) &&
- (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
- atomic_inc(&dev->vbl_received);
-
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
- }
+ if (stat & RADEON_CRTC_VBLANK_STAT)
+ drm_handle_vblank(dev, 0);
+ if (stat & RADEON_CRTC2_VBLANK_STAT)
+ drm_handle_vblank(dev, 1);
return IRQ_HANDLED;
}
@@ -144,54 +175,27 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
return ret;
}
-static int radeon_driver_vblank_do_wait(struct drm_device * dev,
- unsigned int *sequence, int crtc)
+u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
{
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *) dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
- int ack = 0;
- atomic_t *counter;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ u32 crtc_cnt_reg, crtc_status_reg;
+
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- if (crtc == DRM_RADEON_VBLANK_CRTC1) {
- counter = &dev->vbl_received;
- ack |= RADEON_CRTC_VBLANK_STAT;
- } else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
- counter = &dev->vbl_received2;
- ack |= RADEON_CRTC2_VBLANK_STAT;
- } else
+ if (crtc == 0) {
+ crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
+ crtc_status_reg = RADEON_CRTC_STATUS;
+ } else if (crtc == 1) {
+ crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
+ crtc_status_reg = RADEON_CRTC2_STATUS;
+ } else {
return -EINVAL;
+ }
- radeon_acknowledge_irqs(dev_priv, ack);
-
- dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(counter))
- - *sequence) <= (1 << 23)));
-
- *sequence = cur_vblank;
-
- return ret;
-}
-
-int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
-{
- return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
-}
-
-int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
-{
- return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
+ return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
}
/* Needs the lock as it touches the ring.
@@ -234,21 +238,6 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
return radeon_wait_irq(dev, irqwait->irq_seq);
}
-static void radeon_enable_interrupt(struct drm_device *dev)
-{
- drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
-
- dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
- if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
- dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
-
- if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
- dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
-
- RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
- dev_priv->irq_enabled = 1;
-}
-
/* drm_dma.h hooks
*/
void radeon_driver_irq_preinstall(struct drm_device * dev)
@@ -260,20 +249,27 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
/* Clear bits if they're already high */
- radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT |
- RADEON_CRTC2_VBLANK_STAT));
+ radeon_acknowledge_irqs(dev_priv);
}
-void radeon_driver_irq_postinstall(struct drm_device * dev)
+int radeon_driver_irq_postinstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
+ int ret;
atomic_set(&dev_priv->swi_emitted, 0);
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
- radeon_enable_interrupt(dev);
+ ret = drm_vblank_init(dev, 2);
+ if (ret)
+ return ret;
+
+ dev->max_vblank_count = 0x001fffff;
+
+ radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
+
+ return 0;
}
void radeon_driver_irq_uninstall(struct drm_device * dev)
@@ -315,6 +311,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
return -EINVAL;
}
dev_priv->vblank_crtc = (unsigned int)value;
- radeon_enable_interrupt(dev);
return 0;
}
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index 80c01cdfa37d..37870a4a3dc7 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
- DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+ DRIVER_IRQ_SHARED,
.load = via_driver_load,
.unload = via_driver_unload,
.context_dtor = via_final_context,
- .vblank_wait = via_driver_vblank_wait,
+ .get_vblank_counter = via_get_vblank_counter,
+ .enable_vblank = via_enable_vblank,
+ .disable_vblank = via_disable_vblank,
.irq_preinstall = via_driver_irq_preinstall,
.irq_postinstall = via_driver_irq_postinstall,
.irq_uninstall = via_driver_irq_uninstall,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 2daae81874cd..fe67030e39ac 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -75,6 +75,7 @@ typedef struct drm_via_private {
struct timeval last_vblank;
int last_vblank_valid;
unsigned usec_per_vblank;
+ atomic_t vbl_received;
drm_via_state_t hc_state;
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
@@ -130,11 +131,13 @@ extern int via_init_context(struct drm_device * dev, int context);
extern int via_final_context(struct drm_device * dev, int context);
extern int via_do_cleanup_map(struct drm_device * dev);
-extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
+extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int via_enable_vblank(struct drm_device *dev, int crtc);
+extern void via_disable_vblank(struct drm_device *dev, int crtc);
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
extern void via_driver_irq_preinstall(struct drm_device * dev);
-extern void via_driver_irq_postinstall(struct drm_device * dev);
+extern int via_driver_irq_postinstall(struct drm_device * dev);
extern void via_driver_irq_uninstall(struct drm_device * dev);
extern int via_dma_cleanup(struct drm_device * dev);
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index c6bb978a1106..f1ab6fc7c07e 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -92,8 +92,17 @@ static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
static unsigned time_diff(struct timeval *now, struct timeval *then)
{
return (now->tv_usec >= then->tv_usec) ?
- now->tv_usec - then->tv_usec :
- 1000000 - (then->tv_usec - now->tv_usec);
+ now->tv_usec - then->tv_usec :
+ 1000000 - (then->tv_usec - now->tv_usec);
+}
+
+u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
+ if (crtc != 0)
+ return 0;
+
+ return atomic_read(&dev_priv->vbl_received);
}
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
@@ -108,8 +117,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
status = VIA_READ(VIA_REG_INTERRUPT);
if (status & VIA_IRQ_VBLANK_PENDING) {
- atomic_inc(&dev->vbl_received);
- if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+ atomic_inc(&dev_priv->vbl_received);
+ if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
do_gettimeofday(&cur_vblank);
if (dev_priv->last_vblank_valid) {
dev_priv->usec_per_vblank =
@@ -119,12 +128,11 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
dev_priv->last_vblank = cur_vblank;
dev_priv->last_vblank_valid = 1;
}
- if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+ if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
DRM_DEBUG("US per vblank is: %u\n",
dev_priv->usec_per_vblank);
}
- DRM_WAKEUP(&dev->vbl_queue);
- drm_vbl_send_signals(dev);
+ drm_handle_vblank(dev, 0);
handled = 1;
}
@@ -163,31 +171,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
}
}
-int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
+int via_enable_vblank(struct drm_device *dev, int crtc)
{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- unsigned int cur_vblank;
- int ret = 0;
+ drm_via_private_t *dev_priv = dev->dev_private;
+ u32 status;
- DRM_DEBUG("\n");
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
+ if (crtc != 0) {
+ DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
return -EINVAL;
}
- viadrv_acknowledge_irqs(dev_priv);
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using vertical blanks...
- */
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
- DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received)) -
- *sequence) <= (1 << 23)));
+ return 0;
+}
- *sequence = cur_vblank;
- return ret;
+void via_disable_vblank(struct drm_device *dev, int crtc)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
+
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
+
+ if (crtc != 0)
+ DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
}
static int
@@ -292,23 +303,25 @@ void via_driver_irq_preinstall(struct drm_device * dev)
}
}
-void via_driver_irq_postinstall(struct drm_device * dev)
+int via_driver_irq_postinstall(struct drm_device * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
- DRM_DEBUG("\n");
- if (dev_priv) {
- status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
- | dev_priv->irq_enable_mask);
+ DRM_DEBUG("via_driver_irq_postinstall\n");
+ if (!dev_priv)
+ return -EINVAL;
- /* Some magic, oh for some data sheets ! */
+ drm_vblank_init(dev, 1);
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
+ | dev_priv->irq_enable_mask);
- VIA_WRITE8(0x83d4, 0x11);
- VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+ /* Some magic, oh for some data sheets ! */
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
- }
+ return 0;
}
void via_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 9769bf8279a6..60b934adea65 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -42,6 +42,7 @@
#include <linux/input.h>
#include <linux/reboot.h>
#include <linux/notifier.h>
+#include <linux/jiffies.h>
extern void ctrl_alt_del(void);
@@ -928,7 +929,8 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
if (up_flag) {
if (brl_timeout) {
if (!committing ||
- jiffies - releasestart > (brl_timeout * HZ) / 1000) {
+ time_after(jiffies,
+ releasestart + msecs_to_jiffies(brl_timeout))) {
committing = pressed;
releasestart = jiffies;
}
@@ -1238,6 +1240,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
}
param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+ param.ledstate = kbd->ledflagstate;
key_map = key_maps[shift_final];
if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, &param) == NOTIFY_STOP || !key_map) {
@@ -1286,6 +1289,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
(*k_handler[type])(vc, keysym & 0xff, !down);
+ param.ledstate = kbd->ledflagstate;
atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
if (type != KT_SLOCK)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 20070b7c573d..e83623ead441 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -41,36 +41,7 @@
*/
static inline int uncached_access(struct file *file, unsigned long addr)
{
-#if defined(__i386__) && !defined(__arch_um__)
- /*
- * On the PPro and successors, the MTRRs are used to set
- * memory types for physical addresses outside main memory,
- * so blindly setting PCD or PWT on those pages is wrong.
- * For Pentiums and earlier, the surround logic should disable
- * caching for the high addresses through the KEN pin, but
- * we maintain the tradition of paranoia in this code.
- */
- if (file->f_flags & O_SYNC)
- return 1;
- return !( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) ||
- test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) ||
- test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ||
- test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) )
- && addr >= __pa(high_memory);
-#elif defined(__x86_64__) && !defined(__arch_um__)
- /*
- * This is broken because it can generate memory type aliases,
- * which can cause cache corruptions
- * But it is only available for root and we have to be bug-to-bug
- * compatible with i386.
- */
- if (file->f_flags & O_SYNC)
- return 1;
- /* same behaviour as i386. PAT always set to cached and MTRRs control the
- caching behaviour.
- Hopefully a full PAT implementation will fix that soon. */
- return 0;
-#elif defined(CONFIG_IA64)
+#if defined(CONFIG_IA64)
/*
* On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
*/
@@ -108,6 +79,36 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
}
#endif
+#ifdef CONFIG_NONPROMISC_DEVMEM
+static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+{
+ u64 from = ((u64)pfn) << PAGE_SHIFT;
+ u64 to = from + size;
+ u64 cursor = from;
+
+ while (cursor < to) {
+ if (!devmem_is_allowed(pfn)) {
+ printk(KERN_INFO
+ "Program %s tried to access /dev/mem between %Lx->%Lx.\n",
+ current->comm, from, to);
+ return 0;
+ }
+ cursor += PAGE_SIZE;
+ pfn++;
+ }
+ return 1;
+}
+#else
+static inline int range_is_allowed(unsigned long pfn, unsigned long size)
+{
+ return 1;
+}
+#endif
+
+void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+{
+}
+
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
@@ -150,15 +151,25 @@ static ssize_t read_mem(struct file * file, char __user * buf,
sz = min_t(unsigned long, sz, count);
+ if (!range_is_allowed(p >> PAGE_SHIFT, count))
+ return -EPERM;
+
/*
* On ia64 if a page has been mapped somewhere as
* uncached, then it must also be accessed uncached
* by the kernel or data corruption may occur
*/
ptr = xlate_dev_mem_ptr(p);
+ if (!ptr)
+ return -EFAULT;
- if (copy_to_user(buf, ptr, sz))
+ if (copy_to_user(buf, ptr, sz)) {
+ unxlate_dev_mem_ptr(p, ptr);
return -EFAULT;
+ }
+
+ unxlate_dev_mem_ptr(p, ptr);
+
buf += sz;
p += sz;
count -= sz;
@@ -207,20 +218,32 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
sz = min_t(unsigned long, sz, count);
+ if (!range_is_allowed(p >> PAGE_SHIFT, sz))
+ return -EPERM;
+
/*
* On ia64 if a page has been mapped somewhere as
* uncached, then it must also be accessed uncached
* by the kernel or data corruption may occur
*/
ptr = xlate_dev_mem_ptr(p);
+ if (!ptr) {
+ if (written)
+ break;
+ return -EFAULT;
+ }
copied = copy_from_user(ptr, buf, sz);
if (copied) {
written += sz - copied;
+ unxlate_dev_mem_ptr(p, ptr);
if (written)
break;
return -EFAULT;
}
+
+ unxlate_dev_mem_ptr(p, ptr);
+
buf += sz;
p += sz;
count -= sz;
@@ -231,6 +254,12 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
return written;
}
+int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file,
+ unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
+{
+ return 1;
+}
+
#ifndef __HAVE_PHYS_MEM_ACCESS_PROT
static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot)
@@ -271,6 +300,35 @@ static inline int private_mapping_ok(struct vm_area_struct *vma)
}
#endif
+void __attribute__((weak))
+map_devmem(unsigned long pfn, unsigned long len, pgprot_t prot)
+{
+ /* nothing. architectures can override. */
+}
+
+void __attribute__((weak))
+unmap_devmem(unsigned long pfn, unsigned long len, pgprot_t prot)
+{
+ /* nothing. architectures can override. */
+}
+
+static void mmap_mem_open(struct vm_area_struct *vma)
+{
+ map_devmem(vma->vm_pgoff, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static void mmap_mem_close(struct vm_area_struct *vma)
+{
+ unmap_devmem(vma->vm_pgoff, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static struct vm_operations_struct mmap_mem_ops = {
+ .open = mmap_mem_open,
+ .close = mmap_mem_close
+};
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
size_t size = vma->vm_end - vma->vm_start;
@@ -281,17 +339,28 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
if (!private_mapping_ok(vma))
return -ENOSYS;
+ if (!range_is_allowed(vma->vm_pgoff, size))
+ return -EPERM;
+
+ if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size,
+ &vma->vm_page_prot))
+ return -EINVAL;
+
vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
size,
vma->vm_page_prot);
+ vma->vm_ops = &mmap_mem_ops;
+
/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
if (remap_pfn_range(vma,
vma->vm_start,
vma->vm_pgoff,
size,
- vma->vm_page_prot))
+ vma->vm_page_prot)) {
+ unmap_devmem(vma->vm_pgoff, size, vma->vm_page_prot);
return -EAGAIN;
+ }
return 0;
}
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 82bcfb9c839a..06803ed5568c 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -501,7 +501,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
__FILE__,__LINE__, count);
/* This can happen if stuff comes in on the backup tty */
- if (n_hdlc == 0 || tty != n_hdlc->tty)
+ if (!n_hdlc || tty != n_hdlc->tty)
return;
/* verify line is using HDLC discipline */
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 4e84d233e5a2..583356426dfb 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -189,20 +189,20 @@ typedef struct _mgslpc_info {
u32 pending_bh;
- int bh_running;
- int bh_requested;
+ bool bh_running;
+ bool bh_requested;
int dcd_chkcount; /* check counts to prevent */
int cts_chkcount; /* too many IRQs if a signal */
int dsr_chkcount; /* is floating */
int ri_chkcount;
- int rx_enabled;
- int rx_overflow;
+ bool rx_enabled;
+ bool rx_overflow;
- int tx_enabled;
- int tx_active;
- int tx_aborting;
+ bool tx_enabled;
+ bool tx_active;
+ bool tx_aborting;
u32 idle_mode;
int if_mode; /* serial interface selection (RS-232, v.35 etc) */
@@ -216,12 +216,12 @@ typedef struct _mgslpc_info {
unsigned char serial_signals; /* current serial signal states */
- char irq_occurred; /* for diagnostics use */
+ bool irq_occurred; /* for diagnostics use */
char testing_irq;
unsigned int init_error; /* startup error (DIAGS) */
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
- BOOLEAN drop_rts_on_tx_done;
+ bool drop_rts_on_tx_done;
struct _input_signal_events input_signal_events;
@@ -402,8 +402,8 @@ static void hdlcdev_exit(MGSLPC_INFO *info);
static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit);
-static BOOLEAN register_test(MGSLPC_INFO *info);
-static BOOLEAN irq_test(MGSLPC_INFO *info);
+static bool register_test(MGSLPC_INFO *info);
+static bool irq_test(MGSLPC_INFO *info);
static int adapter_test(MGSLPC_INFO *info);
static int claim_resources(MGSLPC_INFO *info);
@@ -411,7 +411,7 @@ static void release_resources(MGSLPC_INFO *info);
static void mgslpc_add_device(MGSLPC_INFO *info);
static void mgslpc_remove_device(MGSLPC_INFO *info);
-static int rx_get_frame(MGSLPC_INFO *info);
+static bool rx_get_frame(MGSLPC_INFO *info);
static void rx_reset_buffers(MGSLPC_INFO *info);
static int rx_alloc_buffers(MGSLPC_INFO *info);
static void rx_free_buffers(MGSLPC_INFO *info);
@@ -719,7 +719,7 @@ static int mgslpc_resume(struct pcmcia_device *link)
}
-static inline int mgslpc_paranoia_check(MGSLPC_INFO *info,
+static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info,
char *name, const char *routine)
{
#ifdef MGSLPC_PARANOIA_CHECK
@@ -730,17 +730,17 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info,
if (!info) {
printk(badinfo, name, routine);
- return 1;
+ return true;
}
if (info->magic != MGSLPC_MAGIC) {
printk(badmagic, name, routine);
- return 1;
+ return true;
}
#else
if (!info)
- return 1;
+ return true;
#endif
- return 0;
+ return false;
}
@@ -752,16 +752,16 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info,
#define CMD_TXEOM BIT1 // transmit end message
#define CMD_TXRESET BIT0 // transmit reset
-static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
+static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
{
int i = 0;
/* wait for command completion */
while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) {
udelay(1);
if (i++ == 1000)
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd)
@@ -825,8 +825,8 @@ static int bh_action(MGSLPC_INFO *info)
if (!rc) {
/* Mark BH routine as complete */
- info->bh_running = 0;
- info->bh_requested = 0;
+ info->bh_running = false;
+ info->bh_requested = false;
}
spin_unlock_irqrestore(&info->lock,flags);
@@ -846,7 +846,7 @@ static void bh_handler(struct work_struct *work)
printk( "%s(%d):bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name);
- info->bh_running = 1;
+ info->bh_running = true;
while((action = bh_action(info)) != 0) {
@@ -913,7 +913,7 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
/* no more free buffers */
issue_command(info, CHA, CMD_RXRESET);
info->pending_bh |= BH_RECEIVE;
- info->rx_overflow = 1;
+ info->rx_overflow = true;
info->icount.buf_overrun++;
return;
}
@@ -1032,8 +1032,8 @@ static void tx_done(MGSLPC_INFO *info)
if (!info->tx_active)
return;
- info->tx_active = 0;
- info->tx_aborting = 0;
+ info->tx_active = false;
+ info->tx_aborting = false;
if (info->params.mode == MGSL_MODE_ASYNC)
return;
@@ -1047,7 +1047,7 @@ static void tx_done(MGSLPC_INFO *info)
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
}
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
}
#if SYNCLINK_GENERIC_HDLC
@@ -1081,7 +1081,7 @@ static void tx_ready(MGSLPC_INFO *info)
return;
}
if (!info->tx_count)
- info->tx_active = 0;
+ info->tx_active = false;
}
if (!info->tx_count)
@@ -1261,7 +1261,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
{
isr = read_reg16(info, CHA + ISR);
if (isr & IRQ_TIMER) {
- info->irq_occurred = 1;
+ info->irq_occurred = true;
irq_disable(info, CHA, IRQ_TIMER);
}
@@ -1318,7 +1318,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
printk("%s(%d):%s queueing bh task.\n",
__FILE__,__LINE__,info->device_name);
schedule_work(&info->task);
- info->bh_requested = 1;
+ info->bh_requested = true;
}
spin_unlock(&info->lock);
@@ -1990,7 +1990,7 @@ static int tx_abort(MGSLPC_INFO * info)
* This results in underrun and abort transmission.
*/
info->tx_count = info->tx_put = info->tx_get = 0;
- info->tx_aborting = TRUE;
+ info->tx_aborting = true;
}
spin_unlock_irqrestore(&info->lock,flags);
return 0;
@@ -2589,7 +2589,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
{
DECLARE_WAITQUEUE(wait, current);
int retval;
- int do_clocal = 0, extra_count = 0;
+ bool do_clocal = false;
+ bool extra_count = false;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -2604,7 +2605,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
+ do_clocal = true;
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
@@ -2622,7 +2623,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
spin_lock_irqsave(&info->lock, flags);
if (!tty_hung_up_p(filp)) {
- extra_count = 1;
+ extra_count = true;
info->count--;
}
spin_unlock_irqrestore(&info->lock, flags);
@@ -3493,8 +3494,8 @@ static void rx_stop(MGSLPC_INFO *info)
/* MODE:03 RAC Receiver Active, 0=inactive */
clear_reg_bits(info, CHA + MODE, BIT3);
- info->rx_enabled = 0;
- info->rx_overflow = 0;
+ info->rx_enabled = false;
+ info->rx_overflow = false;
}
static void rx_start(MGSLPC_INFO *info)
@@ -3504,13 +3505,13 @@ static void rx_start(MGSLPC_INFO *info)
__FILE__,__LINE__, info->device_name );
rx_reset_buffers(info);
- info->rx_enabled = 0;
- info->rx_overflow = 0;
+ info->rx_enabled = false;
+ info->rx_overflow = false;
/* MODE:03 RAC Receiver Active, 1=active */
set_reg_bits(info, CHA + MODE, BIT3);
- info->rx_enabled = 1;
+ info->rx_enabled = true;
}
static void tx_start(MGSLPC_INFO *info)
@@ -3523,24 +3524,24 @@ static void tx_start(MGSLPC_INFO *info)
/* If auto RTS enabled and RTS is inactive, then assert */
/* RTS and set a flag indicating that the driver should */
/* negate RTS when the transmission completes. */
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
get_signals(info);
if (!(info->serial_signals & SerialSignal_RTS)) {
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
- info->drop_rts_on_tx_done = 1;
+ info->drop_rts_on_tx_done = true;
}
}
if (info->params.mode == MGSL_MODE_ASYNC) {
if (!info->tx_active) {
- info->tx_active = 1;
+ info->tx_active = true;
tx_ready(info);
}
} else {
- info->tx_active = 1;
+ info->tx_active = true;
tx_ready(info);
mod_timer(&info->tx_timer, jiffies +
msecs_to_jiffies(5000));
@@ -3548,7 +3549,7 @@ static void tx_start(MGSLPC_INFO *info)
}
if (!info->tx_enabled)
- info->tx_enabled = 1;
+ info->tx_enabled = true;
}
static void tx_stop(MGSLPC_INFO *info)
@@ -3559,8 +3560,8 @@ static void tx_stop(MGSLPC_INFO *info)
del_timer(&info->tx_timer);
- info->tx_enabled = 0;
- info->tx_active = 0;
+ info->tx_enabled = false;
+ info->tx_active = false;
}
/* Reset the adapter to a known state and prepare it for further use.
@@ -3860,19 +3861,19 @@ static void rx_reset_buffers(MGSLPC_INFO *info)
/* Attempt to return a received HDLC frame
* Only frames received without errors are returned.
*
- * Returns 1 if frame returned, otherwise 0
+ * Returns true if frame returned, otherwise false
*/
-static int rx_get_frame(MGSLPC_INFO *info)
+static bool rx_get_frame(MGSLPC_INFO *info)
{
unsigned short status;
RXBUF *buf;
unsigned int framesize = 0;
unsigned long flags;
struct tty_struct *tty = info->tty;
- int return_frame = 0;
+ bool return_frame = false;
if (info->rx_frame_count == 0)
- return 0;
+ return false;
buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size));
@@ -3891,7 +3892,7 @@ static int rx_get_frame(MGSLPC_INFO *info)
else if (!(status & BIT5)) {
info->icount.rxcrc++;
if (info->params.crc_type & HDLC_CRC_RETURN_EX)
- return_frame = 1;
+ return_frame = true;
}
framesize = 0;
#if SYNCLINK_GENERIC_HDLC
@@ -3902,7 +3903,7 @@ static int rx_get_frame(MGSLPC_INFO *info)
}
#endif
} else
- return_frame = 1;
+ return_frame = true;
if (return_frame)
framesize = buf->count;
@@ -3945,16 +3946,16 @@ static int rx_get_frame(MGSLPC_INFO *info)
info->rx_get = 0;
spin_unlock_irqrestore(&info->lock,flags);
- return 1;
+ return true;
}
-static BOOLEAN register_test(MGSLPC_INFO *info)
+static bool register_test(MGSLPC_INFO *info)
{
static unsigned char patterns[] =
{ 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
static unsigned int count = ARRAY_SIZE(patterns);
unsigned int i;
- BOOLEAN rc = TRUE;
+ bool rc = true;
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
@@ -3965,7 +3966,7 @@ static BOOLEAN register_test(MGSLPC_INFO *info)
write_reg(info, XAD2, patterns[(i + 1) % count]);
if ((read_reg(info, XAD1) != patterns[i]) ||
(read_reg(info, XAD2) != patterns[(i + 1) % count])) {
- rc = FALSE;
+ rc = false;
break;
}
}
@@ -3974,7 +3975,7 @@ static BOOLEAN register_test(MGSLPC_INFO *info)
return rc;
}
-static BOOLEAN irq_test(MGSLPC_INFO *info)
+static bool irq_test(MGSLPC_INFO *info)
{
unsigned long end_time;
unsigned long flags;
@@ -3982,10 +3983,10 @@ static BOOLEAN irq_test(MGSLPC_INFO *info)
spin_lock_irqsave(&info->lock,flags);
reset_device(info);
- info->testing_irq = TRUE;
+ info->testing_irq = true;
hdlc_mode(info);
- info->irq_occurred = FALSE;
+ info->irq_occurred = false;
/* init hdlc mode */
@@ -4000,13 +4001,13 @@ static BOOLEAN irq_test(MGSLPC_INFO *info)
msleep_interruptible(10);
}
- info->testing_irq = FALSE;
+ info->testing_irq = false;
spin_lock_irqsave(&info->lock,flags);
reset_device(info);
spin_unlock_irqrestore(&info->lock,flags);
- return info->irq_occurred ? TRUE : FALSE;
+ return info->irq_occurred;
}
static int adapter_test(MGSLPC_INFO *info)
@@ -4079,7 +4080,7 @@ static void tx_timeout(unsigned long context)
info->icount.txtimeout++;
}
spin_lock_irqsave(&info->lock,flags);
- info->tx_active = 0;
+ info->tx_active = false;
info->tx_count = info->tx_put = info->tx_get = 0;
spin_unlock_irqrestore(&info->lock,flags);
diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c
index 85091ff74d96..7a9df7dcf9a8 100644
--- a/drivers/char/rio/rioroute.c
+++ b/drivers/char/rio/rioroute.c
@@ -526,7 +526,7 @@ void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit)
** If RTA is not powered on, the tx packets will be
** unset, so go no further.
*/
- if (PortP->TxStart == 0) {
+ if (!PortP->TxStart) {
rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
break;
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 5c3142b6f1fc..e2ec2ee4cf79 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -88,6 +88,7 @@
#ifdef CONFIG_SPARC32
#include <linux/pci.h>
+#include <linux/jiffies.h>
#include <asm/ebus.h>
static unsigned long rtc_port;
@@ -1316,7 +1317,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
* Once the read clears, read the RTC time (again via ioctl). Easy.
*/
- while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100)
+ while (rtc_is_updating() != 0 &&
+ time_before(jiffies, uip_watchdog + 2*HZ/100))
cpu_relax();
/*
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index a3237d48a584..fadab1d9510f 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -218,9 +218,9 @@ struct mgsl_struct {
u32 pending_bh;
- int bh_running; /* Protection from multiple */
+ bool bh_running; /* Protection from multiple */
int isr_overflow;
- int bh_requested;
+ bool bh_requested;
int dcd_chkcount; /* check counts to prevent */
int cts_chkcount; /* too many IRQs if a signal */
@@ -250,12 +250,12 @@ struct mgsl_struct {
int tx_holding_count; /* number of tx holding buffers waiting */
struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS];
- int rx_enabled;
- int rx_overflow;
- int rx_rcc_underrun;
+ bool rx_enabled;
+ bool rx_overflow;
+ bool rx_rcc_underrun;
- int tx_enabled;
- int tx_active;
+ bool tx_enabled;
+ bool tx_active;
u32 idle_mode;
u16 cmr_value;
@@ -269,14 +269,14 @@ struct mgsl_struct {
unsigned int io_base; /* base I/O address of adapter */
unsigned int io_addr_size; /* size of the I/O address range */
- int io_addr_requested; /* nonzero if I/O address requested */
+ bool io_addr_requested; /* true if I/O address requested */
unsigned int irq_level; /* interrupt level */
unsigned long irq_flags;
- int irq_requested; /* nonzero if IRQ requested */
+ bool irq_requested; /* true if IRQ requested */
unsigned int dma_level; /* DMA channel */
- int dma_requested; /* nonzero if dma channel requested */
+ bool dma_requested; /* true if dma channel requested */
u16 mbre_bit;
u16 loopback_bits;
@@ -286,27 +286,27 @@ struct mgsl_struct {
unsigned char serial_signals; /* current serial signal states */
- int irq_occurred; /* for diagnostics use */
+ bool irq_occurred; /* for diagnostics use */
unsigned int init_error; /* Initialization startup error (DIAGS) */
int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */
u32 last_mem_alloc;
unsigned char* memory_base; /* shared memory address (PCI only) */
u32 phys_memory_base;
- int shared_mem_requested;
+ bool shared_mem_requested;
unsigned char* lcr_base; /* local config registers (PCI only) */
u32 phys_lcr_base;
u32 lcr_offset;
- int lcr_mem_requested;
+ bool lcr_mem_requested;
u32 misc_ctrl_value;
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
char char_buf[MAX_ASYNC_BUFFER_SIZE];
- BOOLEAN drop_rts_on_tx_done;
+ bool drop_rts_on_tx_done;
- BOOLEAN loopmode_insert_requested;
- BOOLEAN loopmode_send_done_requested;
+ bool loopmode_insert_requested;
+ bool loopmode_send_done_requested;
struct _input_signal_events input_signal_events;
@@ -752,10 +752,10 @@ static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int coun
/*
* Adapter diagnostic routines
*/
-static BOOLEAN mgsl_register_test( struct mgsl_struct *info );
-static BOOLEAN mgsl_irq_test( struct mgsl_struct *info );
-static BOOLEAN mgsl_dma_test( struct mgsl_struct *info );
-static BOOLEAN mgsl_memory_test( struct mgsl_struct *info );
+static bool mgsl_register_test( struct mgsl_struct *info );
+static bool mgsl_irq_test( struct mgsl_struct *info );
+static bool mgsl_dma_test( struct mgsl_struct *info );
+static bool mgsl_memory_test( struct mgsl_struct *info );
static int mgsl_adapter_test( struct mgsl_struct *info );
/*
@@ -770,8 +770,8 @@ static struct mgsl_struct* mgsl_allocate_device(void);
* DMA buffer manupulation functions.
*/
static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex );
-static int mgsl_get_rx_frame( struct mgsl_struct *info );
-static int mgsl_get_raw_rx_frame( struct mgsl_struct *info );
+static bool mgsl_get_rx_frame( struct mgsl_struct *info );
+static bool mgsl_get_raw_rx_frame( struct mgsl_struct *info );
static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info );
static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info );
static int num_free_tx_dma_buffers(struct mgsl_struct *info);
@@ -791,7 +791,7 @@ static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info);
static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info);
static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info);
static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info);
-static int load_next_tx_holding_buffer(struct mgsl_struct *info);
+static bool load_next_tx_holding_buffer(struct mgsl_struct *info);
static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize);
/*
@@ -847,7 +847,7 @@ static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask);
static int mgsl_loopmode_send_done( struct mgsl_struct * info );
/* set non-zero on successful registration with PCI subsystem */
-static int pci_registered;
+static bool pci_registered;
/*
* Global linked list of SyncLink devices
@@ -1054,8 +1054,8 @@ static int mgsl_bh_action(struct mgsl_struct *info)
if (!rc) {
/* Mark BH routine as complete */
- info->bh_running = 0;
- info->bh_requested = 0;
+ info->bh_running = false;
+ info->bh_requested = false;
}
spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -1079,7 +1079,7 @@ static void mgsl_bh_handler(struct work_struct *work)
printk( "%s(%d):mgsl_bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name);
- info->bh_running = 1;
+ info->bh_running = true;
while((action = mgsl_bh_action(info)) != 0) {
@@ -1113,7 +1113,7 @@ static void mgsl_bh_handler(struct work_struct *work)
static void mgsl_bh_receive(struct mgsl_struct *info)
{
- int (*get_rx_frame)(struct mgsl_struct *info) =
+ bool (*get_rx_frame)(struct mgsl_struct *info) =
(info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame);
if ( debug_level >= DEBUG_LEVEL_BH )
@@ -1187,7 +1187,7 @@ static void mgsl_isr_receive_status( struct mgsl_struct *info )
usc_loopmode_active(info) )
{
++info->icount.rxabort;
- info->loopmode_insert_requested = FALSE;
+ info->loopmode_insert_requested = false;
/* clear CMR:13 to start echoing RxD to TxD */
info->cmr_value &= ~BIT13;
@@ -1257,7 +1257,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info )
else
info->icount.txunder++;
- info->tx_active = 0;
+ info->tx_active = false;
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
del_timer(&info->tx_timer);
@@ -1267,7 +1267,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info )
info->serial_signals &= ~SerialSignal_RTS;
usc_set_serial_signals( info );
}
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
}
#if SYNCLINK_GENERIC_HDLC
@@ -1403,7 +1403,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
usc_OutReg( info, SICR,
(unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) );
usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED );
- info->irq_occurred = 1;
+ info->irq_occurred = true;
}
} /* end of mgsl_isr_io_pin() */
@@ -1431,7 +1431,7 @@ static void mgsl_isr_transmit_data( struct mgsl_struct *info )
if ( info->xmit_cnt )
usc_load_txfifo( info );
else
- info->tx_active = 0;
+ info->tx_active = false;
if (info->xmit_cnt < WAKEUP_CHARS)
info->pending_bh |= BH_TRANSMIT;
@@ -1568,7 +1568,7 @@ static void mgsl_isr_misc( struct mgsl_struct *info )
/* schedule BH handler to restart receiver */
info->pending_bh |= BH_RECEIVE;
- info->rx_rcc_underrun = 1;
+ info->rx_rcc_underrun = true;
}
usc_ClearIrqPendingBits( info, MISC );
@@ -1626,7 +1626,7 @@ static void mgsl_isr_receive_dma( struct mgsl_struct *info )
info->pending_bh |= BH_RECEIVE;
if ( status & BIT3 ) {
- info->rx_overflow = 1;
+ info->rx_overflow = true;
info->icount.buf_overrun++;
}
@@ -1745,7 +1745,7 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id)
printk("%s(%d):%s queueing bh task.\n",
__FILE__,__LINE__,info->device_name);
schedule_work(&info->task);
- info->bh_requested = 1;
+ info->bh_requested = true;
}
spin_unlock(&info->irq_spinlock);
@@ -3303,7 +3303,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
{
DECLARE_WAITQUEUE(wait, current);
int retval;
- int do_clocal = 0, extra_count = 0;
+ bool do_clocal = false;
+ bool extra_count = false;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3317,7 +3318,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
+ do_clocal = true;
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
@@ -3335,7 +3336,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
spin_lock_irqsave(&info->irq_spinlock, flags);
if (!tty_hung_up_p(filp)) {
- extra_count = 1;
+ extra_count = true;
info->count--;
}
spin_unlock_irqrestore(&info->irq_spinlock, flags);
@@ -4043,13 +4044,13 @@ static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info)
*
* info pointer to device instance data
*
- * Return Value: 1 if next buffered tx request loaded
+ * Return Value: true if next buffered tx request loaded
* into adapter's tx dma buffer,
- * 0 otherwise
+ * false otherwise
*/
-static int load_next_tx_holding_buffer(struct mgsl_struct *info)
+static bool load_next_tx_holding_buffer(struct mgsl_struct *info)
{
- int ret = 0;
+ bool ret = false;
if ( info->tx_holding_count ) {
/* determine if we have enough tx dma buffers
@@ -4073,7 +4074,7 @@ static int load_next_tx_holding_buffer(struct mgsl_struct *info)
/* restart transmit timer */
mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000));
- ret = 1;
+ ret = true;
}
}
@@ -4119,7 +4120,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
__FILE__,__LINE__,info->device_name, info->io_base);
return -ENODEV;
}
- info->io_addr_requested = 1;
+ info->io_addr_requested = true;
if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags,
info->device_name, info ) < 0 ) {
@@ -4127,7 +4128,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
__FILE__,__LINE__,info->device_name, info->irq_level );
goto errout;
}
- info->irq_requested = 1;
+ info->irq_requested = true;
if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) {
@@ -4135,13 +4136,13 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
__FILE__,__LINE__,info->device_name, info->phys_memory_base);
goto errout;
}
- info->shared_mem_requested = 1;
+ info->shared_mem_requested = true;
if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) {
printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset);
goto errout;
}
- info->lcr_mem_requested = 1;
+ info->lcr_mem_requested = true;
info->memory_base = ioremap(info->phys_memory_base,0x40000);
if (!info->memory_base) {
@@ -4172,7 +4173,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info)
mgsl_release_resources( info );
return -ENODEV;
}
- info->dma_requested = 1;
+ info->dma_requested = true;
/* ISA adapter uses bus master DMA */
set_dma_mode(info->dma_level,DMA_MODE_CASCADE);
@@ -4200,12 +4201,12 @@ static void mgsl_release_resources(struct mgsl_struct *info)
if ( info->irq_requested ) {
free_irq(info->irq_level, info);
- info->irq_requested = 0;
+ info->irq_requested = false;
}
if ( info->dma_requested ) {
disable_dma(info->dma_level);
free_dma(info->dma_level);
- info->dma_requested = 0;
+ info->dma_requested = false;
}
mgsl_free_dma_buffers(info);
mgsl_free_intermediate_rxbuffer_memory(info);
@@ -4213,15 +4214,15 @@ static void mgsl_release_resources(struct mgsl_struct *info)
if ( info->io_addr_requested ) {
release_region(info->io_base,info->io_addr_size);
- info->io_addr_requested = 0;
+ info->io_addr_requested = false;
}
if ( info->shared_mem_requested ) {
release_mem_region(info->phys_memory_base,0x40000);
- info->shared_mem_requested = 0;
+ info->shared_mem_requested = false;
}
if ( info->lcr_mem_requested ) {
release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
- info->lcr_mem_requested = 0;
+ info->lcr_mem_requested = false;
}
if (info->memory_base){
iounmap(info->memory_base);
@@ -4486,7 +4487,7 @@ static int __init synclink_init(void)
if ((rc = pci_register_driver(&synclink_pci_driver)) < 0)
printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc);
else
- pci_registered = 1;
+ pci_registered = true;
if ((rc = mgsl_init_tty()) < 0)
goto error;
@@ -4679,7 +4680,7 @@ static u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr )
static void usc_set_sdlc_mode( struct mgsl_struct *info )
{
u16 RegValue;
- int PreSL1660;
+ bool PreSL1660;
/*
* determine if the IUSC on the adapter is pre-SL1660. If
@@ -4692,11 +4693,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
*/
usc_OutReg(info,TMCR,0x1f);
RegValue=usc_InReg(info,TMDR);
- if ( RegValue == IUSC_PRE_SL1660 )
- PreSL1660 = 1;
- else
- PreSL1660 = 0;
-
+ PreSL1660 = (RegValue == IUSC_PRE_SL1660);
if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
{
@@ -5382,9 +5379,9 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info )
int start_index;
int end_index;
int frame_start_index;
- int start_of_frame_found = FALSE;
- int end_of_frame_found = FALSE;
- int reprogram_dma = FALSE;
+ bool start_of_frame_found = false;
+ bool end_of_frame_found = false;
+ bool reprogram_dma = false;
DMABUFFERENTRY *buffer_list = info->rx_buffer_list;
u32 phys_addr;
@@ -5410,9 +5407,9 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info )
if ( !start_of_frame_found )
{
- start_of_frame_found = TRUE;
+ start_of_frame_found = true;
frame_start_index = end_index;
- end_of_frame_found = FALSE;
+ end_of_frame_found = false;
}
if ( buffer_list[end_index].status )
@@ -5423,8 +5420,8 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info )
/* We want to leave the buffers for this frame intact. */
/* Move on to next possible frame. */
- start_of_frame_found = FALSE;
- end_of_frame_found = TRUE;
+ start_of_frame_found = false;
+ end_of_frame_found = true;
}
/* advance to next buffer entry in linked list */
@@ -5439,8 +5436,8 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info )
/* completely screwed, reset all receive buffers! */
mgsl_reset_rx_dma_buffers( info );
frame_start_index = 0;
- start_of_frame_found = FALSE;
- reprogram_dma = TRUE;
+ start_of_frame_found = false;
+ reprogram_dma = true;
break;
}
}
@@ -5466,7 +5463,7 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info )
} while( start_index != end_index );
- reprogram_dma = TRUE;
+ reprogram_dma = true;
}
if ( reprogram_dma )
@@ -5536,9 +5533,9 @@ static void usc_stop_receiver( struct mgsl_struct *info )
usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) );
usc_RTCmd( info, RTCmd_PurgeRxFifo );
- info->rx_enabled = 0;
- info->rx_overflow = 0;
- info->rx_rcc_underrun = 0;
+ info->rx_enabled = false;
+ info->rx_overflow = false;
+ info->rx_rcc_underrun = false;
} /* end of stop_receiver() */
@@ -5601,7 +5598,7 @@ static void usc_start_receiver( struct mgsl_struct *info )
usc_OutReg( info, CCSR, 0x1020 );
- info->rx_enabled = 1;
+ info->rx_enabled = true;
} /* end of usc_start_receiver() */
@@ -5628,14 +5625,14 @@ static void usc_start_transmitter( struct mgsl_struct *info )
/* RTS and set a flag indicating that the driver should */
/* negate RTS when the transmission completes. */
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) {
usc_get_serial_signals( info );
if ( !(info->serial_signals & SerialSignal_RTS) ) {
info->serial_signals |= SerialSignal_RTS;
usc_set_serial_signals( info );
- info->drop_rts_on_tx_done = 1;
+ info->drop_rts_on_tx_done = true;
}
}
@@ -5699,11 +5696,11 @@ static void usc_start_transmitter( struct mgsl_struct *info )
mod_timer(&info->tx_timer, jiffies +
msecs_to_jiffies(5000));
}
- info->tx_active = 1;
+ info->tx_active = true;
}
if ( !info->tx_enabled ) {
- info->tx_enabled = 1;
+ info->tx_enabled = true;
if ( info->params.flags & HDLC_FLAG_AUTO_CTS )
usc_EnableTransmitter(info,ENABLE_AUTO_CTS);
else
@@ -5735,8 +5732,8 @@ static void usc_stop_transmitter( struct mgsl_struct *info )
usc_DmaCmd( info, DmaCmd_ResetTxChannel );
usc_RTCmd( info, RTCmd_PurgeTxFifo );
- info->tx_enabled = 0;
- info->tx_active = 0;
+ info->tx_enabled = false;
+ info->tx_active = false;
} /* end of usc_stop_transmitter() */
@@ -6520,7 +6517,7 @@ static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info )
*/
static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex )
{
- int Done = 0;
+ bool Done = false;
DMABUFFERENTRY *pBufEntry;
unsigned int Index;
@@ -6534,7 +6531,7 @@ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int S
if ( Index == EndIndex ) {
/* This is the last buffer of the frame! */
- Done = 1;
+ Done = true;
}
/* reset current buffer for reuse */
@@ -6559,18 +6556,18 @@ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int S
* receive DMA buffers. Only frames received without errors are returned.
*
* Arguments: info pointer to device extension
- * Return Value: 1 if frame returned, otherwise 0
+ * Return Value: true if frame returned, otherwise false
*/
-static int mgsl_get_rx_frame(struct mgsl_struct *info)
+static bool mgsl_get_rx_frame(struct mgsl_struct *info)
{
unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */
unsigned short status;
DMABUFFERENTRY *pBufEntry;
unsigned int framesize = 0;
- int ReturnCode = 0;
+ bool ReturnCode = false;
unsigned long flags;
struct tty_struct *tty = info->tty;
- int return_frame = 0;
+ bool return_frame = false;
/*
* current_rx_buffer points to the 1st buffer of the next available
@@ -6629,7 +6626,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info)
else {
info->icount.rxcrc++;
if ( info->params.crc_type & HDLC_CRC_RETURN_EX )
- return_frame = 1;
+ return_frame = true;
}
framesize = 0;
#if SYNCLINK_GENERIC_HDLC
@@ -6640,7 +6637,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info)
}
#endif
} else
- return_frame = 1;
+ return_frame = true;
if ( return_frame ) {
/* receive frame has no errors, get frame size.
@@ -6719,7 +6716,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info)
/* Free the buffers used by this frame. */
mgsl_free_rx_frame_buffers( info, StartIndex, EndIndex );
- ReturnCode = 1;
+ ReturnCode = true;
Cleanup:
@@ -6758,15 +6755,15 @@ Cleanup:
* last Rx DMA buffer and return that last portion of the frame.
*
* Arguments: info pointer to device extension
- * Return Value: 1 if frame returned, otherwise 0
+ * Return Value: true if frame returned, otherwise false
*/
-static int mgsl_get_raw_rx_frame(struct mgsl_struct *info)
+static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info)
{
unsigned int CurrentIndex, NextIndex;
unsigned short status;
DMABUFFERENTRY *pBufEntry;
unsigned int framesize = 0;
- int ReturnCode = 0;
+ bool ReturnCode = false;
unsigned long flags;
struct tty_struct *tty = info->tty;
@@ -6891,7 +6888,7 @@ static int mgsl_get_raw_rx_frame(struct mgsl_struct *info)
/* Free the buffers used by this frame. */
mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex );
- ReturnCode = 1;
+ ReturnCode = true;
}
@@ -7000,15 +6997,15 @@ static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info,
* Performs a register test of the 16C32.
*
* Arguments: info pointer to device instance data
- * Return Value: TRUE if test passed, otherwise FALSE
+ * Return Value: true if test passed, otherwise false
*/
-static BOOLEAN mgsl_register_test( struct mgsl_struct *info )
+static bool mgsl_register_test( struct mgsl_struct *info )
{
static unsigned short BitPatterns[] =
{ 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f };
static unsigned int Patterncount = ARRAY_SIZE(BitPatterns);
unsigned int i;
- BOOLEAN rc = TRUE;
+ bool rc = true;
unsigned long flags;
spin_lock_irqsave(&info->irq_spinlock,flags);
@@ -7019,10 +7016,10 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info )
if ( (usc_InReg( info, SICR ) != 0) ||
(usc_InReg( info, IVR ) != 0) ||
(usc_InDmaReg( info, DIVR ) != 0) ){
- rc = FALSE;
+ rc = false;
}
- if ( rc == TRUE ){
+ if ( rc ){
/* Write bit patterns to various registers but do it out of */
/* sync, then read back and verify values. */
@@ -7040,7 +7037,7 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info )
(usc_InReg( info, RCLR ) != BitPatterns[(i+3)%Patterncount]) ||
(usc_InReg( info, RSR ) != BitPatterns[(i+4)%Patterncount]) ||
(usc_InDmaReg( info, TBCR ) != BitPatterns[(i+5)%Patterncount]) ){
- rc = FALSE;
+ rc = false;
break;
}
}
@@ -7056,9 +7053,9 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info )
/* mgsl_irq_test() Perform interrupt test of the 16C32.
*
* Arguments: info pointer to device instance data
- * Return Value: TRUE if test passed, otherwise FALSE
+ * Return Value: true if test passed, otherwise false
*/
-static BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
+static bool mgsl_irq_test( struct mgsl_struct *info )
{
unsigned long EndTime;
unsigned long flags;
@@ -7068,10 +7065,10 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
/*
* Setup 16C32 to interrupt on TxC pin (14MHz clock) transition.
- * The ISR sets irq_occurred to 1.
+ * The ISR sets irq_occurred to true.
*/
- info->irq_occurred = FALSE;
+ info->irq_occurred = false;
/* Enable INTEN gate for ISA adapter (Port 6, Bit12) */
/* Enable INTEN (Port 6, Bit12) */
@@ -7097,10 +7094,7 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
usc_reset(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- if ( !info->irq_occurred )
- return FALSE;
- else
- return TRUE;
+ return info->irq_occurred;
} /* end of mgsl_irq_test() */
@@ -7111,16 +7105,16 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
* using single buffer DMA mode.
*
* Arguments: info pointer to device instance data
- * Return Value: TRUE if test passed, otherwise FALSE
+ * Return Value: true if test passed, otherwise false
*/
-static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
+static bool mgsl_dma_test( struct mgsl_struct *info )
{
unsigned short FifoLevel;
unsigned long phys_addr;
unsigned int FrameSize;
unsigned int i;
char *TmpPtr;
- BOOLEAN rc = TRUE;
+ bool rc = true;
unsigned short status=0;
unsigned long EndTime;
unsigned long flags;
@@ -7233,7 +7227,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
for(;;) {
if (time_after(jiffies, EndTime)) {
- rc = FALSE;
+ rc = false;
break;
}
@@ -7289,7 +7283,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
for(;;) {
if (time_after(jiffies, EndTime)) {
- rc = FALSE;
+ rc = false;
break;
}
@@ -7309,7 +7303,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
}
- if ( rc == TRUE )
+ if ( rc )
{
/* Enable 16C32 transmitter. */
@@ -7337,7 +7331,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) {
if (time_after(jiffies, EndTime)) {
- rc = FALSE;
+ rc = false;
break;
}
@@ -7348,13 +7342,13 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
}
- if ( rc == TRUE ){
+ if ( rc ){
/* CHECK FOR TRANSMIT ERRORS */
if ( status & (BIT5 + BIT1) )
- rc = FALSE;
+ rc = false;
}
- if ( rc == TRUE ) {
+ if ( rc ) {
/* WAIT FOR RECEIVE COMPLETE */
/* Wait 100ms */
@@ -7364,7 +7358,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
status=info->rx_buffer_list[0].status;
while ( status == 0 ) {
if (time_after(jiffies, EndTime)) {
- rc = FALSE;
+ rc = false;
break;
}
status=info->rx_buffer_list[0].status;
@@ -7372,17 +7366,17 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
}
- if ( rc == TRUE ) {
+ if ( rc ) {
/* CHECK FOR RECEIVE ERRORS */
status = info->rx_buffer_list[0].status;
if ( status & (BIT8 + BIT3 + BIT1) ) {
/* receive error has occurred */
- rc = FALSE;
+ rc = false;
} else {
if ( memcmp( info->tx_buffer_list[0].virt_addr ,
info->rx_buffer_list[0].virt_addr, FrameSize ) ){
- rc = FALSE;
+ rc = false;
}
}
}
@@ -7445,9 +7439,9 @@ static int mgsl_adapter_test( struct mgsl_struct *info )
* Test the shared memory on a PCI adapter.
*
* Arguments: info pointer to device instance data
- * Return Value: TRUE if test passed, otherwise FALSE
+ * Return Value: true if test passed, otherwise false
*/
-static BOOLEAN mgsl_memory_test( struct mgsl_struct *info )
+static bool mgsl_memory_test( struct mgsl_struct *info )
{
static unsigned long BitPatterns[] =
{ 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
@@ -7457,7 +7451,7 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info )
unsigned long * TestAddr;
if ( info->bus_type != MGSL_BUS_TYPE_PCI )
- return TRUE;
+ return true;
TestAddr = (unsigned long *)info->memory_base;
@@ -7466,7 +7460,7 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info )
for ( i = 0 ; i < Patterncount ; i++ ) {
*TestAddr = BitPatterns[i];
if ( *TestAddr != BitPatterns[i] )
- return FALSE;
+ return false;
}
/* Test address lines with incrementing pattern over */
@@ -7481,13 +7475,13 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info )
for ( i = 0 ; i < TestLimit ; i++ ) {
if ( *TestAddr != i * 4 )
- return FALSE;
+ return false;
TestAddr++;
}
memset( info->memory_base, 0, SHARED_MEM_ADDRESS_SIZE );
- return TRUE;
+ return true;
} /* End Of mgsl_memory_test() */
@@ -7604,7 +7598,7 @@ static void mgsl_tx_timeout(unsigned long context)
info->icount.txtimeout++;
}
spin_lock_irqsave(&info->irq_spinlock,flags);
- info->tx_active = 0;
+ info->tx_active = false;
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
@@ -7632,7 +7626,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info )
spin_lock_irqsave(&info->irq_spinlock,flags);
if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
if (info->tx_active)
- info->loopmode_send_done_requested = TRUE;
+ info->loopmode_send_done_requested = true;
else
usc_loopmode_send_done(info);
}
@@ -7646,7 +7640,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info )
*/
static void usc_loopmode_send_done( struct mgsl_struct * info )
{
- info->loopmode_send_done_requested = FALSE;
+ info->loopmode_send_done_requested = false;
/* clear CMR:13 to 0 to start echoing RxData to TxData */
info->cmr_value &= ~BIT13;
usc_OutReg(info, CMR, info->cmr_value);
@@ -7668,7 +7662,7 @@ static void usc_loopmode_cancel_transmit( struct mgsl_struct * info )
*/
static void usc_loopmode_insert_request( struct mgsl_struct * info )
{
- info->loopmode_insert_requested = TRUE;
+ info->loopmode_insert_requested = true;
/* enable RxAbort irq. On next RxAbort, clear CMR:13 to
* begin repeating TxData on RxData (complete insertion)
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 3c89266c8255..f3d8d72e5ea4 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -117,7 +117,7 @@ static struct pci_driver pci_driver = {
.remove = __devexit_p(remove_one),
};
-static int pci_registered;
+static bool pci_registered;
/*
* module configuration and status
@@ -289,12 +289,12 @@ struct slgt_info {
struct work_struct task;
u32 pending_bh;
- int bh_requested;
- int bh_running;
+ bool bh_requested;
+ bool bh_running;
int isr_overflow;
- int irq_requested; /* nonzero if IRQ requested */
- int irq_occurred; /* for diagnostics use */
+ bool irq_requested; /* true if IRQ requested */
+ bool irq_occurred; /* for diagnostics use */
/* device configuration */
@@ -304,7 +304,7 @@ struct slgt_info {
unsigned char __iomem * reg_addr; /* memory mapped registers address */
u32 phys_reg_addr;
- int reg_addr_requested;
+ bool reg_addr_requested;
MGSL_PARAMS params; /* communications parameters */
u32 idle_mode;
@@ -315,11 +315,11 @@ struct slgt_info {
/* device status */
- int rx_enabled;
- int rx_restart;
+ bool rx_enabled;
+ bool rx_restart;
- int tx_enabled;
- int tx_active;
+ bool tx_enabled;
+ bool tx_active;
unsigned char signals; /* serial signal states */
int init_error; /* initialization error */
@@ -329,7 +329,7 @@ struct slgt_info {
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
char char_buf[MAX_ASYNC_BUFFER_SIZE];
- BOOLEAN drop_rts_on_tx_done;
+ bool drop_rts_on_tx_done;
struct _input_signal_events input_signal_events;
int dcd_chkcount; /* check counts to prevent */
@@ -467,8 +467,8 @@ static void rx_start(struct slgt_info *info);
static void reset_rbufs(struct slgt_info *info);
static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last);
static void rdma_reset(struct slgt_info *info);
-static int rx_get_frame(struct slgt_info *info);
-static int rx_get_buf(struct slgt_info *info);
+static bool rx_get_frame(struct slgt_info *info);
+static bool rx_get_buf(struct slgt_info *info);
static void tx_start(struct slgt_info *info);
static void tx_stop(struct slgt_info *info);
@@ -1968,8 +1968,8 @@ static int bh_action(struct slgt_info *info)
rc = BH_STATUS;
} else {
/* Mark BH routine as complete */
- info->bh_running = 0;
- info->bh_requested = 0;
+ info->bh_running = false;
+ info->bh_requested = false;
rc = 0;
}
@@ -1988,7 +1988,7 @@ static void bh_handler(struct work_struct *work)
if (!info)
return;
- info->bh_running = 1;
+ info->bh_running = true;
while((action = bh_action(info))) {
switch (action) {
@@ -2158,7 +2158,7 @@ static void isr_serial(struct slgt_info *info)
wr_reg16(info, SSR, status); /* clear pending */
- info->irq_occurred = 1;
+ info->irq_occurred = true;
if (info->params.mode == MGSL_MODE_ASYNC) {
if (status & IRQ_TXIDLE) {
@@ -2225,7 +2225,7 @@ static void isr_rdma(struct slgt_info *info)
if (status & (BIT5 + BIT4)) {
DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name));
- info->rx_restart = 1;
+ info->rx_restart = true;
}
info->pending_bh |= BH_RECEIVE;
}
@@ -2276,14 +2276,14 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
info->icount.txok++;
}
- info->tx_active = 0;
+ info->tx_active = false;
info->tx_count = 0;
del_timer(&info->tx_timer);
if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
info->signals &= ~SerialSignal_RTS;
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
set_signals(info);
}
@@ -2337,7 +2337,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
DBGISR(("%s gsr=%08x\n", info->device_name, gsr));
- info->irq_occurred = 1;
+ info->irq_occurred = true;
for(i=0; i < info->port_count ; i++) {
if (info->port_array[i] == NULL)
continue;
@@ -2374,7 +2374,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
!port->bh_requested) {
DBGISR(("%s bh queued\n", port->device_name));
schedule_work(&port->task);
- port->bh_requested = 1;
+ port->bh_requested = true;
}
}
@@ -3110,7 +3110,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
{
DECLARE_WAITQUEUE(wait, current);
int retval;
- int do_clocal = 0, extra_count = 0;
+ bool do_clocal = false;
+ bool extra_count = false;
unsigned long flags;
DBGINFO(("%s block_til_ready\n", tty->driver->name));
@@ -3122,7 +3123,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
+ do_clocal = true;
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
@@ -3136,7 +3137,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
spin_lock_irqsave(&info->lock, flags);
if (!tty_hung_up_p(filp)) {
- extra_count = 1;
+ extra_count = true;
info->count--;
}
spin_unlock_irqrestore(&info->lock, flags);
@@ -3321,7 +3322,7 @@ static int claim_resources(struct slgt_info *info)
goto errout;
}
else
- info->reg_addr_requested = 1;
+ info->reg_addr_requested = true;
info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE);
if (!info->reg_addr) {
@@ -3341,12 +3342,12 @@ static void release_resources(struct slgt_info *info)
{
if (info->irq_requested) {
free_irq(info->irq_level, info);
- info->irq_requested = 0;
+ info->irq_requested = false;
}
if (info->reg_addr_requested) {
release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE);
- info->reg_addr_requested = 0;
+ info->reg_addr_requested = false;
}
if (info->reg_addr) {
@@ -3511,7 +3512,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
port_array[0]->device_name,
port_array[0]->irq_level));
} else {
- port_array[0]->irq_requested = 1;
+ port_array[0]->irq_requested = true;
adapter_test(port_array[0]);
for (i=1 ; i < port_count ; i++) {
port_array[i]->init_error = port_array[0]->init_error;
@@ -3654,7 +3655,7 @@ static int __init slgt_init(void)
printk("%s pci_register_driver error=%d\n", driver_name, rc);
goto error;
}
- pci_registered = 1;
+ pci_registered = true;
if (!slgt_device_list)
printk("%s no devices found\n",driver_name);
@@ -3812,8 +3813,8 @@ static void rx_stop(struct slgt_info *info)
rdma_reset(info);
- info->rx_enabled = 0;
- info->rx_restart = 0;
+ info->rx_enabled = false;
+ info->rx_restart = false;
}
static void rx_start(struct slgt_info *info)
@@ -3849,8 +3850,8 @@ static void rx_start(struct slgt_info *info)
/* enable receiver */
wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1));
- info->rx_restart = 0;
- info->rx_enabled = 1;
+ info->rx_restart = false;
+ info->rx_enabled = true;
}
static void tx_start(struct slgt_info *info)
@@ -3858,11 +3859,11 @@ static void tx_start(struct slgt_info *info)
if (!info->tx_enabled) {
wr_reg16(info, TCR,
(unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2));
- info->tx_enabled = TRUE;
+ info->tx_enabled = true;
}
if (info->tx_count) {
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
if (info->params.mode != MGSL_MODE_ASYNC) {
if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
@@ -3870,7 +3871,7 @@ static void tx_start(struct slgt_info *info)
if (!(info->signals & SerialSignal_RTS)) {
info->signals |= SerialSignal_RTS;
set_signals(info);
- info->drop_rts_on_tx_done = 1;
+ info->drop_rts_on_tx_done = true;
}
}
@@ -3888,7 +3889,7 @@ static void tx_start(struct slgt_info *info)
wr_reg16(info, SSR, IRQ_TXIDLE);
}
tdma_start(info);
- info->tx_active = 1;
+ info->tx_active = true;
}
}
@@ -3949,8 +3950,8 @@ static void tx_stop(struct slgt_info *info)
reset_tbufs(info);
- info->tx_enabled = 0;
- info->tx_active = 0;
+ info->tx_enabled = false;
+ info->tx_active = false;
}
static void reset_port(struct slgt_info *info)
@@ -4470,14 +4471,13 @@ static void reset_rbufs(struct slgt_info *info)
/*
* pass receive HDLC frame to upper layer
*
- * return 1 if frame available, otherwise 0
+ * return true if frame available, otherwise false
*/
-static int rx_get_frame(struct slgt_info *info)
+static bool rx_get_frame(struct slgt_info *info)
{
unsigned int start, end;
unsigned short status;
unsigned int framesize = 0;
- int rc = 0;
unsigned long flags;
struct tty_struct *tty = info->tty;
unsigned char addr_field = 0xff;
@@ -4601,23 +4601,23 @@ check_again:
}
}
free_rbufs(info, start, end);
- rc = 1;
+ return true;
cleanup:
- return rc;
+ return false;
}
/*
* pass receive buffer (RAW synchronous mode) to tty layer
- * return 1 if buffer available, otherwise 0
+ * return true if buffer available, otherwise false
*/
-static int rx_get_buf(struct slgt_info *info)
+static bool rx_get_buf(struct slgt_info *info)
{
unsigned int i = info->rbuf_current;
unsigned int count;
if (!desc_complete(info->rbufs[i]))
- return 0;
+ return false;
count = desc_count(info->rbufs[i]);
switch(info->params.mode) {
case MGSL_MODE_MONOSYNC:
@@ -4633,7 +4633,7 @@ static int rx_get_buf(struct slgt_info *info)
ldisc_receive_buf(info->tty, info->rbufs[i].buf,
info->flag_buf, count);
free_rbufs(info, i, i);
- return 1;
+ return true;
}
static void reset_tbufs(struct slgt_info *info)
@@ -4758,7 +4758,7 @@ static int irq_test(struct slgt_info *info)
/* assume failure */
info->init_error = DiagStatus_IrqFailure;
- info->irq_occurred = FALSE;
+ info->irq_occurred = false;
spin_unlock_irqrestore(&info->lock, flags);
@@ -4891,7 +4891,7 @@ static void tx_timeout(unsigned long context)
info->icount.txtimeout++;
}
spin_lock_irqsave(&info->lock,flags);
- info->tx_active = 0;
+ info->tx_active = false;
info->tx_count = 0;
spin_unlock_irqrestore(&info->lock,flags);
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index c96062ea72b4..e98c3e6f8216 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -188,9 +188,9 @@ typedef struct _synclinkmp_info {
u32 pending_bh;
- int bh_running; /* Protection from multiple */
+ bool bh_running; /* Protection from multiple */
int isr_overflow;
- int bh_requested;
+ bool bh_requested;
int dcd_chkcount; /* check counts to prevent */
int cts_chkcount; /* too many IRQs if a signal */
@@ -213,11 +213,11 @@ typedef struct _synclinkmp_info {
unsigned char *tmp_rx_buf;
unsigned int tmp_rx_buf_count;
- int rx_enabled;
- int rx_overflow;
+ bool rx_enabled;
+ bool rx_overflow;
- int tx_enabled;
- int tx_active;
+ bool tx_enabled;
+ bool tx_active;
u32 idle_mode;
unsigned char ie0_value;
@@ -238,13 +238,13 @@ typedef struct _synclinkmp_info {
unsigned int irq_level; /* interrupt level */
unsigned long irq_flags;
- int irq_requested; /* nonzero if IRQ requested */
+ bool irq_requested; /* true if IRQ requested */
MGSL_PARAMS params; /* communications parameters */
unsigned char serial_signals; /* current serial signal states */
- int irq_occurred; /* for diagnostics use */
+ bool irq_occurred; /* for diagnostics use */
unsigned int init_error; /* Initialization startup error */
u32 last_mem_alloc;
@@ -255,7 +255,7 @@ typedef struct _synclinkmp_info {
unsigned char* sca_base; /* HD64570 SCA Memory address */
u32 phys_sca_base;
u32 sca_offset;
- int sca_base_requested;
+ bool sca_base_requested;
unsigned char* lcr_base; /* local config registers (PCI only) */
u32 phys_lcr_base;
@@ -265,12 +265,12 @@ typedef struct _synclinkmp_info {
unsigned char* statctrl_base; /* status/control register memory */
u32 phys_statctrl_base;
u32 statctrl_offset;
- int sca_statctrl_requested;
+ bool sca_statctrl_requested;
u32 misc_ctrl_value;
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
char char_buf[MAX_ASYNC_BUFFER_SIZE];
- BOOLEAN drop_rts_on_tx_done;
+ bool drop_rts_on_tx_done;
struct _input_signal_events input_signal_events;
@@ -571,12 +571,12 @@ static void shutdown(SLMP_INFO *info);
static void program_hw(SLMP_INFO *info);
static void change_params(SLMP_INFO *info);
-static int init_adapter(SLMP_INFO *info);
-static int register_test(SLMP_INFO *info);
-static int irq_test(SLMP_INFO *info);
-static int loopback_test(SLMP_INFO *info);
+static bool init_adapter(SLMP_INFO *info);
+static bool register_test(SLMP_INFO *info);
+static bool irq_test(SLMP_INFO *info);
+static bool loopback_test(SLMP_INFO *info);
static int adapter_test(SLMP_INFO *info);
-static int memory_test(SLMP_INFO *info);
+static bool memory_test(SLMP_INFO *info);
static void reset_adapter(SLMP_INFO *info);
static void reset_port(SLMP_INFO *info);
@@ -587,7 +587,7 @@ static void rx_stop(SLMP_INFO *info);
static void rx_start(SLMP_INFO *info);
static void rx_reset_buffers(SLMP_INFO *info);
static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last);
-static int rx_get_frame(SLMP_INFO *info);
+static bool rx_get_frame(SLMP_INFO *info);
static void tx_start(SLMP_INFO *info);
static void tx_stop(SLMP_INFO *info);
@@ -1473,7 +1473,7 @@ static inline int line_info(char *buf, SLMP_INFO *info)
/* Called to print information about devices
*/
-int read_proc(char *page, char **start, off_t off, int count,
+static int read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
int len = 0, l;
@@ -2024,7 +2024,7 @@ static void hdlcdev_exit(SLMP_INFO *info)
/* Return next bottom half action to perform.
* Return Value: BH action code or 0 if nothing to do.
*/
-int bh_action(SLMP_INFO *info)
+static int bh_action(SLMP_INFO *info)
{
unsigned long flags;
int rc = 0;
@@ -2044,8 +2044,8 @@ int bh_action(SLMP_INFO *info)
if (!rc) {
/* Mark BH routine as complete */
- info->bh_running = 0;
- info->bh_requested = 0;
+ info->bh_running = false;
+ info->bh_requested = false;
}
spin_unlock_irqrestore(&info->lock,flags);
@@ -2055,7 +2055,7 @@ int bh_action(SLMP_INFO *info)
/* Perform bottom half processing of work items queued by ISR.
*/
-void bh_handler(struct work_struct *work)
+static void bh_handler(struct work_struct *work)
{
SLMP_INFO *info = container_of(work, SLMP_INFO, task);
int action;
@@ -2067,7 +2067,7 @@ void bh_handler(struct work_struct *work)
printk( "%s(%d):%s bh_handler() entry\n",
__FILE__,__LINE__,info->device_name);
- info->bh_running = 1;
+ info->bh_running = true;
while((action = bh_action(info)) != 0) {
@@ -2100,7 +2100,7 @@ void bh_handler(struct work_struct *work)
__FILE__,__LINE__,info->device_name);
}
-void bh_receive(SLMP_INFO *info)
+static void bh_receive(SLMP_INFO *info)
{
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):%s bh_receive()\n",
@@ -2109,7 +2109,7 @@ void bh_receive(SLMP_INFO *info)
while( rx_get_frame(info) );
}
-void bh_transmit(SLMP_INFO *info)
+static void bh_transmit(SLMP_INFO *info)
{
struct tty_struct *tty = info->tty;
@@ -2121,7 +2121,7 @@ void bh_transmit(SLMP_INFO *info)
tty_wakeup(tty);
}
-void bh_status(SLMP_INFO *info)
+static void bh_status(SLMP_INFO *info)
{
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):%s bh_status() entry\n",
@@ -2133,7 +2133,7 @@ void bh_status(SLMP_INFO *info)
info->cts_chkcount = 0;
}
-void isr_timer(SLMP_INFO * info)
+static void isr_timer(SLMP_INFO * info)
{
unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0;
@@ -2152,14 +2152,14 @@ void isr_timer(SLMP_INFO * info)
*/
write_reg(info, (unsigned char)(timer + TMCS), 0);
- info->irq_occurred = TRUE;
+ info->irq_occurred = true;
if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s isr_timer()\n",
__FILE__,__LINE__,info->device_name);
}
-void isr_rxint(SLMP_INFO * info)
+static void isr_rxint(SLMP_INFO * info)
{
struct tty_struct *tty = info->tty;
struct mgsl_icount *icount = &info->icount;
@@ -2218,7 +2218,7 @@ void isr_rxint(SLMP_INFO * info)
/*
* handle async rx data interrupts
*/
-void isr_rxrdy(SLMP_INFO * info)
+static void isr_rxrdy(SLMP_INFO * info)
{
u16 status;
unsigned char DataByte;
@@ -2232,7 +2232,7 @@ void isr_rxrdy(SLMP_INFO * info)
while((status = read_reg(info,CST0)) & BIT0)
{
int flag = 0;
- int over = 0;
+ bool over = false;
DataByte = read_reg(info,TRB);
icount->rx++;
@@ -2265,7 +2265,7 @@ void isr_rxrdy(SLMP_INFO * info)
* reported immediately, and doesn't
* affect the current character
*/
- over = 1;
+ over = true;
}
}
} /* end of if (error) */
@@ -2318,14 +2318,14 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status)
info->icount.txok++;
}
- info->tx_active = 0;
+ info->tx_active = false;
info->tx_count = info->tx_put = info->tx_get = 0;
del_timer(&info->tx_timer);
if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) {
info->serial_signals &= ~SerialSignal_RTS;
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
set_signals(info);
}
@@ -2348,7 +2348,7 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status)
/*
* handle tx status interrupts
*/
-void isr_txint(SLMP_INFO * info)
+static void isr_txint(SLMP_INFO * info)
{
unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS);
@@ -2376,7 +2376,7 @@ void isr_txint(SLMP_INFO * info)
/*
* handle async tx data interrupts
*/
-void isr_txrdy(SLMP_INFO * info)
+static void isr_txrdy(SLMP_INFO * info)
{
if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s isr_txrdy() tx_count=%d\n",
@@ -2398,7 +2398,7 @@ void isr_txrdy(SLMP_INFO * info)
if ( info->tx_count )
tx_load_fifo( info );
else {
- info->tx_active = 0;
+ info->tx_active = false;
info->ie0_value &= ~TXRDYE;
write_reg(info, IE0, info->ie0_value);
}
@@ -2407,7 +2407,7 @@ void isr_txrdy(SLMP_INFO * info)
info->pending_bh |= BH_TRANSMIT;
}
-void isr_rxdmaok(SLMP_INFO * info)
+static void isr_rxdmaok(SLMP_INFO * info)
{
/* BIT7 = EOT (end of transfer)
* BIT6 = EOM (end of message/frame)
@@ -2424,7 +2424,7 @@ void isr_rxdmaok(SLMP_INFO * info)
info->pending_bh |= BH_RECEIVE;
}
-void isr_rxdmaerror(SLMP_INFO * info)
+static void isr_rxdmaerror(SLMP_INFO * info)
{
/* BIT5 = BOF (buffer overflow)
* BIT4 = COF (counter overflow)
@@ -2438,11 +2438,11 @@ void isr_rxdmaerror(SLMP_INFO * info)
printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n",
__FILE__,__LINE__,info->device_name,status);
- info->rx_overflow = TRUE;
+ info->rx_overflow = true;
info->pending_bh |= BH_RECEIVE;
}
-void isr_txdmaok(SLMP_INFO * info)
+static void isr_txdmaok(SLMP_INFO * info)
{
unsigned char status_reg1 = read_reg(info, SR1);
@@ -2460,7 +2460,7 @@ void isr_txdmaok(SLMP_INFO * info)
write_reg(info, IE0, info->ie0_value);
}
-void isr_txdmaerror(SLMP_INFO * info)
+static void isr_txdmaerror(SLMP_INFO * info)
{
/* BIT5 = BOF (buffer overflow)
* BIT4 = COF (counter overflow)
@@ -2477,7 +2477,7 @@ void isr_txdmaerror(SLMP_INFO * info)
/* handle input serial signal changes
*/
-void isr_io_pin( SLMP_INFO *info, u16 status )
+static void isr_io_pin( SLMP_INFO *info, u16 status )
{
struct mgsl_icount *icount;
@@ -2691,7 +2691,7 @@ static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id)
printk("%s(%d):%s queueing bh task.\n",
__FILE__,__LINE__,port->device_name);
schedule_work(&port->task);
- port->bh_requested = 1;
+ port->bh_requested = true;
}
}
@@ -3320,7 +3320,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
{
DECLARE_WAITQUEUE(wait, current);
int retval;
- int do_clocal = 0, extra_count = 0;
+ bool do_clocal = false;
+ bool extra_count = false;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -3335,7 +3336,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
+ do_clocal = true;
/* Wait for carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
@@ -3353,7 +3354,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
spin_lock_irqsave(&info->lock, flags);
if (!tty_hung_up_p(filp)) {
- extra_count = 1;
+ extra_count = true;
info->count--;
}
spin_unlock_irqrestore(&info->lock, flags);
@@ -3413,7 +3414,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return retval;
}
-int alloc_dma_bufs(SLMP_INFO *info)
+static int alloc_dma_bufs(SLMP_INFO *info)
{
unsigned short BuffersPerFrame;
unsigned short BufferCount;
@@ -3487,7 +3488,7 @@ int alloc_dma_bufs(SLMP_INFO *info)
/* Allocate DMA buffers for the transmit and receive descriptor lists.
*/
-int alloc_buf_list(SLMP_INFO *info)
+static int alloc_buf_list(SLMP_INFO *info)
{
unsigned int i;
@@ -3546,7 +3547,7 @@ int alloc_buf_list(SLMP_INFO *info)
/* Allocate the frame DMA buffers used by the specified buffer list.
*/
-int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count)
+static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count)
{
int i;
unsigned long phys_addr;
@@ -3563,7 +3564,7 @@ int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,
return 0;
}
-void free_dma_bufs(SLMP_INFO *info)
+static void free_dma_bufs(SLMP_INFO *info)
{
info->buffer_list = NULL;
info->rx_buf_list = NULL;
@@ -3573,7 +3574,7 @@ void free_dma_bufs(SLMP_INFO *info)
/* allocate buffer large enough to hold max_frame_size.
* This buffer is used to pass an assembled frame to the line discipline.
*/
-int alloc_tmp_rx_buf(SLMP_INFO *info)
+static int alloc_tmp_rx_buf(SLMP_INFO *info)
{
info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
if (info->tmp_rx_buf == NULL)
@@ -3581,13 +3582,13 @@ int alloc_tmp_rx_buf(SLMP_INFO *info)
return 0;
}
-void free_tmp_rx_buf(SLMP_INFO *info)
+static void free_tmp_rx_buf(SLMP_INFO *info)
{
kfree(info->tmp_rx_buf);
info->tmp_rx_buf = NULL;
}
-int claim_resources(SLMP_INFO *info)
+static int claim_resources(SLMP_INFO *info)
{
if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s mem addr conflict, Addr=%08X\n",
@@ -3596,7 +3597,7 @@ int claim_resources(SLMP_INFO *info)
goto errout;
}
else
- info->shared_mem_requested = 1;
+ info->shared_mem_requested = true;
if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) {
printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n",
@@ -3605,7 +3606,7 @@ int claim_resources(SLMP_INFO *info)
goto errout;
}
else
- info->lcr_mem_requested = 1;
+ info->lcr_mem_requested = true;
if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n",
@@ -3614,7 +3615,7 @@ int claim_resources(SLMP_INFO *info)
goto errout;
}
else
- info->sca_base_requested = 1;
+ info->sca_base_requested = true;
if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n",
@@ -3623,7 +3624,7 @@ int claim_resources(SLMP_INFO *info)
goto errout;
}
else
- info->sca_statctrl_requested = 1;
+ info->sca_statctrl_requested = true;
info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE);
if (!info->memory_base) {
@@ -3674,7 +3675,7 @@ errout:
return -ENODEV;
}
-void release_resources(SLMP_INFO *info)
+static void release_resources(SLMP_INFO *info)
{
if ( debug_level >= DEBUG_LEVEL_INFO )
printk( "%s(%d):%s release_resources() entry\n",
@@ -3682,24 +3683,24 @@ void release_resources(SLMP_INFO *info)
if ( info->irq_requested ) {
free_irq(info->irq_level, info);
- info->irq_requested = 0;
+ info->irq_requested = false;
}
if ( info->shared_mem_requested ) {
release_mem_region(info->phys_memory_base,SCA_MEM_SIZE);
- info->shared_mem_requested = 0;
+ info->shared_mem_requested = false;
}
if ( info->lcr_mem_requested ) {
release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
- info->lcr_mem_requested = 0;
+ info->lcr_mem_requested = false;
}
if ( info->sca_base_requested ) {
release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE);
- info->sca_base_requested = 0;
+ info->sca_base_requested = false;
}
if ( info->sca_statctrl_requested ) {
release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE);
- info->sca_statctrl_requested = 0;
+ info->sca_statctrl_requested = false;
}
if (info->memory_base){
@@ -3730,7 +3731,7 @@ void release_resources(SLMP_INFO *info)
/* Add the specified device instance data structure to the
* global linked list of devices and increment the device count.
*/
-void add_device(SLMP_INFO *info)
+static void add_device(SLMP_INFO *info)
{
info->next_device = NULL;
info->line = synclinkmp_device_count;
@@ -3853,7 +3854,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
return info;
}
-void device_init(int adapter_num, struct pci_dev *pdev)
+static void device_init(int adapter_num, struct pci_dev *pdev)
{
SLMP_INFO *port_array[SCA_MAX_PORTS];
int port;
@@ -3902,7 +3903,7 @@ void device_init(int adapter_num, struct pci_dev *pdev)
port_array[0]->irq_level );
}
else {
- port_array[0]->irq_requested = 1;
+ port_array[0]->irq_requested = true;
adapter_test(port_array[0]);
}
}
@@ -4047,7 +4048,7 @@ module_exit(synclinkmp_exit);
* The TxCLK and RxCLK signals are generated from the BRG and
* the TxD is looped back to the RxD internally.
*/
-void enable_loopback(SLMP_INFO *info, int enable)
+static void enable_loopback(SLMP_INFO *info, int enable)
{
if (enable) {
/* MD2 (Mode Register 2)
@@ -4094,7 +4095,7 @@ void enable_loopback(SLMP_INFO *info, int enable)
* data_rate data rate of clock in bits per second
* A data rate of 0 disables the AUX clock.
*/
-void set_rate( SLMP_INFO *info, u32 data_rate )
+static void set_rate( SLMP_INFO *info, u32 data_rate )
{
u32 TMCValue;
unsigned char BRValue;
@@ -4140,7 +4141,7 @@ void set_rate( SLMP_INFO *info, u32 data_rate )
/* Disable receiver
*/
-void rx_stop(SLMP_INFO *info)
+static void rx_stop(SLMP_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):%s rx_stop()\n",
@@ -4155,13 +4156,13 @@ void rx_stop(SLMP_INFO *info)
write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */
write_reg(info, RXDMA + DIR, 0); /* disable Rx DMA interrupts */
- info->rx_enabled = 0;
- info->rx_overflow = 0;
+ info->rx_enabled = false;
+ info->rx_overflow = false;
}
/* enable the receiver
*/
-void rx_start(SLMP_INFO *info)
+static void rx_start(SLMP_INFO *info)
{
int i;
@@ -4211,14 +4212,14 @@ void rx_start(SLMP_INFO *info)
write_reg(info, CMD, RXENABLE);
- info->rx_overflow = FALSE;
- info->rx_enabled = 1;
+ info->rx_overflow = false;
+ info->rx_enabled = true;
}
/* Enable the transmitter and send a transmit frame if
* one is loaded in the DMA buffers.
*/
-void tx_start(SLMP_INFO *info)
+static void tx_start(SLMP_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):%s tx_start() tx_count=%d\n",
@@ -4227,7 +4228,7 @@ void tx_start(SLMP_INFO *info)
if (!info->tx_enabled ) {
write_reg(info, CMD, TXRESET);
write_reg(info, CMD, TXENABLE);
- info->tx_enabled = TRUE;
+ info->tx_enabled = true;
}
if ( info->tx_count ) {
@@ -4236,7 +4237,7 @@ void tx_start(SLMP_INFO *info)
/* RTS and set a flag indicating that the driver should */
/* negate RTS when the transmission completes. */
- info->drop_rts_on_tx_done = 0;
+ info->drop_rts_on_tx_done = false;
if (info->params.mode != MGSL_MODE_ASYNC) {
@@ -4245,7 +4246,7 @@ void tx_start(SLMP_INFO *info)
if ( !(info->serial_signals & SerialSignal_RTS) ) {
info->serial_signals |= SerialSignal_RTS;
set_signals( info );
- info->drop_rts_on_tx_done = 1;
+ info->drop_rts_on_tx_done = true;
}
}
@@ -4282,13 +4283,13 @@ void tx_start(SLMP_INFO *info)
write_reg(info, IE0, info->ie0_value);
}
- info->tx_active = 1;
+ info->tx_active = true;
}
}
/* stop the transmitter and DMA
*/
-void tx_stop( SLMP_INFO *info )
+static void tx_stop( SLMP_INFO *info )
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):%s tx_stop()\n",
@@ -4308,14 +4309,14 @@ void tx_stop( SLMP_INFO *info )
info->ie0_value &= ~TXRDYE;
write_reg(info, IE0, info->ie0_value); /* disable tx data interrupts */
- info->tx_enabled = 0;
- info->tx_active = 0;
+ info->tx_enabled = false;
+ info->tx_active = false;
}
/* Fill the transmit FIFO until the FIFO is full or
* there is no more data to load.
*/
-void tx_load_fifo(SLMP_INFO *info)
+static void tx_load_fifo(SLMP_INFO *info)
{
u8 TwoBytes[2];
@@ -4364,7 +4365,7 @@ void tx_load_fifo(SLMP_INFO *info)
/* Reset a port to a known state
*/
-void reset_port(SLMP_INFO *info)
+static void reset_port(SLMP_INFO *info)
{
if (info->sca_base) {
@@ -4388,7 +4389,7 @@ void reset_port(SLMP_INFO *info)
/* Reset all the ports to a known state.
*/
-void reset_adapter(SLMP_INFO *info)
+static void reset_adapter(SLMP_INFO *info)
{
int i;
@@ -4400,7 +4401,7 @@ void reset_adapter(SLMP_INFO *info)
/* Program port for asynchronous communications.
*/
-void async_mode(SLMP_INFO *info)
+static void async_mode(SLMP_INFO *info)
{
unsigned char RegValue;
@@ -4539,7 +4540,7 @@ void async_mode(SLMP_INFO *info)
/* Program the SCA for HDLC communications.
*/
-void hdlc_mode(SLMP_INFO *info)
+static void hdlc_mode(SLMP_INFO *info)
{
unsigned char RegValue;
u32 DpllDivisor;
@@ -4741,7 +4742,7 @@ void hdlc_mode(SLMP_INFO *info)
/* Set the transmit HDLC idle mode
*/
-void tx_set_idle(SLMP_INFO *info)
+static void tx_set_idle(SLMP_INFO *info)
{
unsigned char RegValue = 0xff;
@@ -4761,7 +4762,7 @@ void tx_set_idle(SLMP_INFO *info)
/* Query the adapter for the state of the V24 status (input) signals.
*/
-void get_signals(SLMP_INFO *info)
+static void get_signals(SLMP_INFO *info)
{
u16 status = read_reg(info, SR3);
u16 gpstatus = read_status_reg(info);
@@ -4790,7 +4791,7 @@ void get_signals(SLMP_INFO *info)
/* Set the state of DTR and RTS based on contents of
* serial_signals member of device context.
*/
-void set_signals(SLMP_INFO *info)
+static void set_signals(SLMP_INFO *info)
{
unsigned char RegValue;
u16 EnableBit;
@@ -4819,7 +4820,7 @@ void set_signals(SLMP_INFO *info)
* and set the current buffer to the first buffer. This effectively
* makes all buffers free and discards any data in buffers.
*/
-void rx_reset_buffers(SLMP_INFO *info)
+static void rx_reset_buffers(SLMP_INFO *info)
{
rx_free_frame_buffers(info, 0, info->rx_buf_count - 1);
}
@@ -4830,16 +4831,16 @@ void rx_reset_buffers(SLMP_INFO *info)
* first index of 1st receive buffer of frame
* last index of last receive buffer of frame
*/
-void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last)
+static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last)
{
- int done = 0;
+ bool done = false;
while(!done) {
/* reset current buffer for reuse */
info->rx_buf_list[first].status = 0xff;
if (first == last) {
- done = 1;
+ done = true;
/* set new last rx descriptor address */
write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry);
}
@@ -4856,14 +4857,14 @@ void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int las
/* Return a received frame from the receive DMA buffers.
* Only frames received without errors are returned.
*
- * Return Value: 1 if frame returned, otherwise 0
+ * Return Value: true if frame returned, otherwise false
*/
-int rx_get_frame(SLMP_INFO *info)
+static bool rx_get_frame(SLMP_INFO *info)
{
unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */
unsigned short status;
unsigned int framesize = 0;
- int ReturnCode = 0;
+ bool ReturnCode = false;
unsigned long flags;
struct tty_struct *tty = info->tty;
unsigned char addr_field = 0xff;
@@ -5014,7 +5015,7 @@ CheckAgain:
/* Free the buffers used by this frame. */
rx_free_frame_buffers( info, StartIndex, EndIndex );
- ReturnCode = 1;
+ ReturnCode = true;
Cleanup:
if ( info->rx_enabled && info->rx_overflow ) {
@@ -5033,7 +5034,7 @@ Cleanup:
/* load the transmit DMA buffer with data
*/
-void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count)
+static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count)
{
unsigned short copy_count;
unsigned int i = 0;
@@ -5073,12 +5074,12 @@ void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count)
info->last_tx_buf = ++i;
}
-int register_test(SLMP_INFO *info)
+static bool register_test(SLMP_INFO *info)
{
static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96};
static unsigned int count = ARRAY_SIZE(testval);
unsigned int i;
- int rc = TRUE;
+ bool rc = true;
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
@@ -5101,7 +5102,7 @@ int register_test(SLMP_INFO *info)
(read_reg(info, SA0) != testval[(i+2)%count]) ||
(read_reg(info, SA1) != testval[(i+3)%count]) )
{
- rc = FALSE;
+ rc = false;
break;
}
}
@@ -5112,7 +5113,7 @@ int register_test(SLMP_INFO *info)
return rc;
}
-int irq_test(SLMP_INFO *info)
+static bool irq_test(SLMP_INFO *info)
{
unsigned long timeout;
unsigned long flags;
@@ -5124,7 +5125,7 @@ int irq_test(SLMP_INFO *info)
/* assume failure */
info->init_error = DiagStatus_IrqFailure;
- info->irq_occurred = FALSE;
+ info->irq_occurred = false;
/* setup timer0 on SCA0 to interrupt */
@@ -5163,7 +5164,7 @@ int irq_test(SLMP_INFO *info)
/* initialize individual SCA device (2 ports)
*/
-static int sca_init(SLMP_INFO *info)
+static bool sca_init(SLMP_INFO *info)
{
/* set wait controller to single mem partition (low), no wait states */
write_reg(info, PABR0, 0); /* wait controller addr boundary 0 */
@@ -5199,12 +5200,12 @@ static int sca_init(SLMP_INFO *info)
*/
write_reg(info, ITCR, 0);
- return TRUE;
+ return true;
}
/* initialize adapter hardware
*/
-int init_adapter(SLMP_INFO *info)
+static bool init_adapter(SLMP_INFO *info)
{
int i;
@@ -5257,20 +5258,20 @@ int init_adapter(SLMP_INFO *info)
sca_init(info->port_array[0]);
sca_init(info->port_array[2]);
- return TRUE;
+ return true;
}
/* Loopback an HDLC frame to test the hardware
* interrupt and DMA functions.
*/
-int loopback_test(SLMP_INFO *info)
+static bool loopback_test(SLMP_INFO *info)
{
#define TESTFRAMESIZE 20
unsigned long timeout;
u16 count = TESTFRAMESIZE;
unsigned char buf[TESTFRAMESIZE];
- int rc = FALSE;
+ bool rc = false;
unsigned long flags;
struct tty_struct *oldtty = info->tty;
@@ -5304,16 +5305,16 @@ int loopback_test(SLMP_INFO *info)
msleep_interruptible(10);
if (rx_get_frame(info)) {
- rc = TRUE;
+ rc = true;
break;
}
}
/* verify received frame length and contents */
- if (rc == TRUE &&
- ( info->tmp_rx_buf_count != count ||
- memcmp(buf, info->tmp_rx_buf,count))) {
- rc = FALSE;
+ if (rc &&
+ ( info->tmp_rx_buf_count != count ||
+ memcmp(buf, info->tmp_rx_buf,count))) {
+ rc = false;
}
spin_lock_irqsave(&info->lock,flags);
@@ -5328,7 +5329,7 @@ int loopback_test(SLMP_INFO *info)
/* Perform diagnostics on hardware
*/
-int adapter_test( SLMP_INFO *info )
+static int adapter_test( SLMP_INFO *info )
{
unsigned long flags;
if ( debug_level >= DEBUG_LEVEL_INFO )
@@ -5390,7 +5391,7 @@ int adapter_test( SLMP_INFO *info )
/* Test the shared memory on a PCI adapter.
*/
-int memory_test(SLMP_INFO *info)
+static bool memory_test(SLMP_INFO *info)
{
static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa,
0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
@@ -5404,7 +5405,7 @@ int memory_test(SLMP_INFO *info)
for ( i = 0 ; i < count ; i++ ) {
*addr = testval[i];
if ( *addr != testval[i] )
- return FALSE;
+ return false;
}
/* Test address lines with incrementing pattern over */
@@ -5419,12 +5420,12 @@ int memory_test(SLMP_INFO *info)
for ( i = 0 ; i < limit ; i++ ) {
if ( *addr != i * 4 )
- return FALSE;
+ return false;
addr++;
}
memset( info->memory_base, 0, SCA_MEM_SIZE );
- return TRUE;
+ return true;
}
/* Load data into PCI adapter shared memory.
@@ -5442,7 +5443,7 @@ int memory_test(SLMP_INFO *info)
* the write transation. This allows any pending DMA request to gain control
* of the local bus in a timely fasion.
*/
-void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count)
+static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count)
{
/* A load interval of 16 allows for 4 32-bit writes at */
/* 136ns each for a maximum latency of 542ns on the local bus.*/
@@ -5461,7 +5462,7 @@ void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned shor
memcpy(dest, src, count % sca_pci_load_interval);
}
-void trace_block(SLMP_INFO *info,const char* data, int count, int xmit)
+static void trace_block(SLMP_INFO *info,const char* data, int count, int xmit)
{
int i;
int linecount;
@@ -5496,7 +5497,7 @@ void trace_block(SLMP_INFO *info,const char* data, int count, int xmit)
/* called when HDLC frame times out
* update stats and do tx completion processing
*/
-void tx_timeout(unsigned long context)
+static void tx_timeout(unsigned long context)
{
SLMP_INFO *info = (SLMP_INFO*)context;
unsigned long flags;
@@ -5508,7 +5509,7 @@ void tx_timeout(unsigned long context)
info->icount.txtimeout++;
}
spin_lock_irqsave(&info->lock,flags);
- info->tx_active = 0;
+ info->tx_active = false;
info->tx_count = info->tx_put = info->tx_get = 0;
spin_unlock_irqrestore(&info->lock,flags);
@@ -5523,7 +5524,7 @@ void tx_timeout(unsigned long context)
/* called to periodically check the DSR/RI modem signal input status
*/
-void status_timeout(unsigned long context)
+static void status_timeout(unsigned long context)
{
u16 status = 0;
SLMP_INFO *info = (SLMP_INFO*)context;
@@ -5574,36 +5575,36 @@ void status_timeout(unsigned long context)
}
-unsigned char read_reg(SLMP_INFO * info, unsigned char Addr)
+static unsigned char read_reg(SLMP_INFO * info, unsigned char Addr)
{
CALC_REGADDR();
return *RegAddr;
}
-void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value)
+static void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value)
{
CALC_REGADDR();
*RegAddr = Value;
}
-u16 read_reg16(SLMP_INFO * info, unsigned char Addr)
+static u16 read_reg16(SLMP_INFO * info, unsigned char Addr)
{
CALC_REGADDR();
return *((u16 *)RegAddr);
}
-void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value)
+static void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value)
{
CALC_REGADDR();
*((u16 *)RegAddr) = Value;
}
-unsigned char read_status_reg(SLMP_INFO * info)
+static unsigned char read_status_reg(SLMP_INFO * info)
{
unsigned char *RegAddr = (unsigned char *)info->statctrl_base;
return *RegAddr;
}
-void write_control_reg(SLMP_INFO * info)
+static void write_control_reg(SLMP_INFO * info)
{
unsigned char *RegAddr = (unsigned char *)info->statctrl_base;
*RegAddr = info->port_array[0]->ctrlreg_value;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index de60e1ea4fb3..1ade193c9128 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -271,8 +271,7 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(struct work_struct *ignored)
{
- out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL],
- GFP_KERNEL, 0);
+ out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0);
}
static DECLARE_WORK(moom_work, moom_callback);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 4d3c7018f0c3..98b65a230994 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1180,7 +1180,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (*str == ',')
str++;
if (*str == '\0')
- str = 0;
+ str = NULL;
if (tty_line >= 0 && tty_line <= p->num && p->poll_init &&
!p->poll_init(p, tty_line, str)) {
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 9b58b894f823..df4c3ead9e2b 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2054,6 +2054,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
unsigned long draw_from = 0, draw_to = 0;
struct vc_data *vc;
unsigned char vc_attr;
+ struct vt_notifier_param param;
uint8_t rescan;
uint8_t inverse;
uint8_t width;
@@ -2113,6 +2114,8 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
if (IS_FG(vc))
hide_cursor(vc);
+ param.vc = vc;
+
while (!tty->stopped && count) {
int orig = *buf;
c = orig;
@@ -2201,6 +2204,11 @@ rescan_last_byte:
tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
+ param.c = tc;
+ if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
+ &param) == NOTIFY_STOP)
+ continue;
+
/* If the original code was a control character we
* only allow a glyph to be displayed if the code is
* not normally used (such as for cursor movement) or
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 016f90567a52..dfe6907ae15b 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -803,7 +803,7 @@ static int __devexit hwicap_of_remove(struct of_device *op)
}
/* Match table for of_platform binding */
-static const struct of_device_id __devinit hwicap_of_match[] = {
+static const struct of_device_id __devinitconst hwicap_of_match[] = {
{ .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
{ .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},
{},
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 35a26a3e5f68..d3575f5ec6d2 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -118,9 +118,11 @@ static void handle_update(struct work_struct *work);
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
static struct srcu_notifier_head cpufreq_transition_notifier_list;
+static bool init_cpufreq_transition_notifier_list_called;
static int __init init_cpufreq_transition_notifier_list(void)
{
srcu_init_notifier_head(&cpufreq_transition_notifier_list);
+ init_cpufreq_transition_notifier_list_called = true;
return 0;
}
pure_initcall(init_cpufreq_transition_notifier_list);
@@ -216,7 +218,7 @@ static void cpufreq_debug_disable_ratelimit(void)
}
void cpufreq_debug_printk(unsigned int type, const char *prefix,
- const char *fmt, ...)
+ const char *fmt, ...)
{
char s[256];
va_list args;
@@ -378,7 +380,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor)
/**
* cpufreq_parse_governor - parse a governor string
*/
-static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
+static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor)
{
int err = -EINVAL;
@@ -446,7 +448,7 @@ extern struct sysdev_class cpu_sysdev_class;
#define show_one(file_name, object) \
static ssize_t show_##file_name \
-(struct cpufreq_policy * policy, char *buf) \
+(struct cpufreq_policy *policy, char *buf) \
{ \
return sprintf (buf, "%u\n", policy->object); \
}
@@ -465,7 +467,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
*/
#define store_one(file_name, object) \
static ssize_t store_##file_name \
-(struct cpufreq_policy * policy, const char *buf, size_t count) \
+(struct cpufreq_policy *policy, const char *buf, size_t count) \
{ \
unsigned int ret = -EINVAL; \
struct cpufreq_policy new_policy; \
@@ -490,8 +492,8 @@ store_one(scaling_max_freq,max);
/**
* show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
*/
-static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy,
- char *buf)
+static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
+ char *buf)
{
unsigned int cur_freq = __cpufreq_get(policy->cpu);
if (!cur_freq)
@@ -503,8 +505,7 @@ static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy,
/**
* show_scaling_governor - show the current policy for the specified CPU
*/
-static ssize_t show_scaling_governor (struct cpufreq_policy * policy,
- char *buf)
+static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
{
if(policy->policy == CPUFREQ_POLICY_POWERSAVE)
return sprintf(buf, "powersave\n");
@@ -519,8 +520,8 @@ static ssize_t show_scaling_governor (struct cpufreq_policy * policy,
/**
* store_scaling_governor - store policy for the specified CPU
*/
-static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
- const char *buf, size_t count)
+static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
{
unsigned int ret = -EINVAL;
char str_governor[16];
@@ -554,7 +555,7 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
/**
* show_scaling_driver - show the cpufreq driver currently loaded
*/
-static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
+static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
{
return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
}
@@ -562,8 +563,8 @@ static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf)
/**
* show_scaling_available_governors - show the available CPUfreq governors
*/
-static ssize_t show_scaling_available_governors (struct cpufreq_policy *policy,
- char *buf)
+static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
+ char *buf)
{
ssize_t i = 0;
struct cpufreq_governor *t;
@@ -585,7 +586,7 @@ out:
/**
* show_affected_cpus - show the CPUs affected by each transition
*/
-static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf)
+static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
{
ssize_t i = 0;
unsigned int cpu;
@@ -602,7 +603,7 @@ static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf)
}
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
unsigned int freq = 0;
unsigned int ret;
@@ -651,7 +652,7 @@ define_one_rw(scaling_max_freq);
define_one_rw(scaling_governor);
define_one_rw(scaling_setspeed);
-static struct attribute * default_attrs[] = {
+static struct attribute *default_attrs[] = {
&cpuinfo_min_freq.attr,
&cpuinfo_max_freq.attr,
&scaling_min_freq.attr,
@@ -667,10 +668,10 @@ static struct attribute * default_attrs[] = {
#define to_policy(k) container_of(k,struct cpufreq_policy,kobj)
#define to_attr(a) container_of(a,struct freq_attr,attr)
-static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
+static ssize_t show(struct kobject *kobj, struct attribute *attr ,char *buf)
{
- struct cpufreq_policy * policy = to_policy(kobj);
- struct freq_attr * fattr = to_attr(attr);
+ struct cpufreq_policy *policy = to_policy(kobj);
+ struct freq_attr *fattr = to_attr(attr);
ssize_t ret = -EINVAL;
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
@@ -691,11 +692,11 @@ no_policy:
return ret;
}
-static ssize_t store(struct kobject * kobj, struct attribute * attr,
- const char * buf, size_t count)
+static ssize_t store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
{
- struct cpufreq_policy * policy = to_policy(kobj);
- struct freq_attr * fattr = to_attr(attr);
+ struct cpufreq_policy *policy = to_policy(kobj);
+ struct freq_attr *fattr = to_attr(attr);
ssize_t ret = -EINVAL;
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
@@ -716,9 +717,9 @@ no_policy:
return ret;
}
-static void cpufreq_sysfs_release(struct kobject * kobj)
+static void cpufreq_sysfs_release(struct kobject *kobj)
{
- struct cpufreq_policy * policy = to_policy(kobj);
+ struct cpufreq_policy *policy = to_policy(kobj);
dprintk("last reference is dropped\n");
complete(&policy->kobj_unregister);
}
@@ -740,7 +741,7 @@ static struct kobj_type ktype_cpufreq = {
*
* Adds the cpufreq interface for a CPU device.
*/
-static int cpufreq_add_dev (struct sys_device * sys_dev)
+static int cpufreq_add_dev(struct sys_device *sys_dev)
{
unsigned int cpu = sys_dev->id;
int ret = 0;
@@ -800,7 +801,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
ret = cpufreq_driver->init(policy);
if (ret) {
dprintk("initialization failed\n");
- unlock_policy_rwsem_write(cpu);
goto err_out;
}
policy->user_policy.min = policy->cpuinfo.min_freq;
@@ -823,7 +823,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* check for existing affected CPUs. They may not be aware
* of it due to CPU Hotplug.
*/
- managed_policy = cpufreq_cpu_get(j);
+ managed_policy = cpufreq_cpu_get(j); // FIXME: Where is this released? What about error paths?
if (unlikely(managed_policy)) {
/* Set proper policy_cpu */
@@ -842,14 +842,11 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
ret = sysfs_create_link(&sys_dev->kobj,
&managed_policy->kobj,
"cpufreq");
- if (ret) {
- unlock_policy_rwsem_write(cpu);
+ if (ret)
goto err_out_driver_exit;
- }
cpufreq_debug_enable_ratelimit();
ret = 0;
- unlock_policy_rwsem_write(cpu);
goto err_out_driver_exit; /* call driver->exit() */
}
}
@@ -859,33 +856,26 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* prepare interface data */
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
"cpufreq");
- if (ret) {
- unlock_policy_rwsem_write(cpu);
+ if (ret)
goto err_out_driver_exit;
- }
+
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
while ((drv_attr) && (*drv_attr)) {
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
- if (ret) {
- unlock_policy_rwsem_write(cpu);
+ if (ret)
goto err_out_driver_exit;
- }
drv_attr++;
}
- if (cpufreq_driver->get){
+ if (cpufreq_driver->get) {
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
- if (ret) {
- unlock_policy_rwsem_write(cpu);
+ if (ret)
goto err_out_driver_exit;
- }
}
- if (cpufreq_driver->target){
+ if (cpufreq_driver->target) {
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
- if (ret) {
- unlock_policy_rwsem_write(cpu);
+ if (ret)
goto err_out_driver_exit;
- }
}
spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -907,10 +897,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
cpu_sys_dev = get_cpu_sysdev(j);
ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
"cpufreq");
- if (ret) {
- unlock_policy_rwsem_write(cpu);
+ if (ret)
goto err_out_unregister;
- }
}
policy->governor = NULL; /* to assure that the starting sequence is
@@ -950,6 +938,7 @@ err_out_driver_exit:
cpufreq_driver->exit(policy);
err_out:
+ unlock_policy_rwsem_write(cpu);
kfree(policy);
nomem_out:
@@ -967,7 +956,7 @@ module_out:
* Caller should already have policy_rwsem in write mode for this CPU.
* This routine frees the rwsem before returning.
*/
-static int __cpufreq_remove_dev (struct sys_device * sys_dev)
+static int __cpufreq_remove_dev(struct sys_device *sys_dev)
{
unsigned int cpu = sys_dev->id;
unsigned long flags;
@@ -1071,7 +1060,7 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
}
-static int cpufreq_remove_dev (struct sys_device * sys_dev)
+static int cpufreq_remove_dev(struct sys_device *sys_dev)
{
unsigned int cpu = sys_dev->id;
int retval;
@@ -1138,7 +1127,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
cpufreq_cpu_put(policy);
}
- return (ret_freq);
+ return ret_freq;
}
EXPORT_SYMBOL(cpufreq_quick_get);
@@ -1149,7 +1138,7 @@ static unsigned int __cpufreq_get(unsigned int cpu)
unsigned int ret_freq = 0;
if (!cpufreq_driver->get)
- return (ret_freq);
+ return ret_freq;
ret_freq = cpufreq_driver->get(cpu);
@@ -1163,7 +1152,7 @@ static unsigned int __cpufreq_get(unsigned int cpu)
}
}
- return (ret_freq);
+ return ret_freq;
}
/**
@@ -1190,7 +1179,7 @@ unsigned int cpufreq_get(unsigned int cpu)
out_policy:
cpufreq_cpu_put(policy);
out:
- return (ret_freq);
+ return ret_freq;
}
EXPORT_SYMBOL(cpufreq_get);
@@ -1199,7 +1188,7 @@ EXPORT_SYMBOL(cpufreq_get);
* cpufreq_suspend - let the low level driver prepare for suspend
*/
-static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
+static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
{
int cpu = sysdev->id;
int ret = 0;
@@ -1221,22 +1210,18 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
return -EINVAL;
/* only handle each CPU group once */
- if (unlikely(cpu_policy->cpu != cpu)) {
- cpufreq_cpu_put(cpu_policy);
- return 0;
- }
+ if (unlikely(cpu_policy->cpu != cpu))
+ goto out;
if (cpufreq_driver->suspend) {
ret = cpufreq_driver->suspend(cpu_policy, pmsg);
if (ret) {
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
"step on CPU %u\n", cpu_policy->cpu);
- cpufreq_cpu_put(cpu_policy);
- return ret;
+ goto out;
}
}
-
if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
goto out;
@@ -1270,7 +1255,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
out:
cpufreq_cpu_put(cpu_policy);
- return 0;
+ return ret;
}
/**
@@ -1281,7 +1266,7 @@ out:
* 3.) schedule call cpufreq_update_policy() ASAP as interrupts are
* restored.
*/
-static int cpufreq_resume(struct sys_device * sysdev)
+static int cpufreq_resume(struct sys_device *sysdev)
{
int cpu = sysdev->id;
int ret = 0;
@@ -1302,18 +1287,15 @@ static int cpufreq_resume(struct sys_device * sysdev)
return -EINVAL;
/* only handle each CPU group once */
- if (unlikely(cpu_policy->cpu != cpu)) {
- cpufreq_cpu_put(cpu_policy);
- return 0;
- }
+ if (unlikely(cpu_policy->cpu != cpu))
+ goto fail;
if (cpufreq_driver->resume) {
ret = cpufreq_driver->resume(cpu_policy);
if (ret) {
printk(KERN_ERR "cpufreq: resume failed in ->resume "
"step on CPU %u\n", cpu_policy->cpu);
- cpufreq_cpu_put(cpu_policy);
- return ret;
+ goto fail;
}
}
@@ -1353,6 +1335,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
out:
schedule_work(&cpu_policy->update);
+fail:
cpufreq_cpu_put(cpu_policy);
return ret;
}
@@ -1386,6 +1369,8 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
{
int ret;
+ WARN_ON(!init_cpufreq_transition_notifier_list_called);
+
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
ret = srcu_notifier_chain_register(
@@ -1848,7 +1833,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_debug_enable_ratelimit();
}
- return (ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 070421a5480e..ef09e069433b 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -114,7 +114,7 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
stat->freq_table[i]);
}
if (len >= PAGE_SIZE)
- return len;
+ return PAGE_SIZE;
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
@@ -131,8 +131,12 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
stat->trans_table[i*stat->max_state+j]);
}
+ if (len >= PAGE_SIZE)
+ break;
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
}
+ if (len >= PAGE_SIZE)
+ return PAGE_SIZE;
return len;
}
CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index d0e5fa4ea51b..11f17440fea6 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -58,7 +58,7 @@ void __init reserve_ibft_region(void)
unsigned int len = 0;
void *virt;
- ibft_addr = 0;
+ ibft_addr = NULL;
for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
/* The table can't be inside the VGA BIOS reserved space,
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d8db2f8ee411..24c62b848bf9 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -43,6 +43,7 @@ struct gpio_desc {
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1
+#define FLAG_RESERVED 2
#ifdef CONFIG_DEBUG_FS
const char *label;
@@ -68,6 +69,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc)
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
desc_set_label(desc, "[auto]");
+ if (!try_module_get(desc->chip->owner))
+ pr_err("GPIO-%d: module can't be gotten \n",
+ (int)(desc - gpio_desc));
}
}
@@ -77,6 +81,76 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
return gpio_desc[gpio].chip;
}
+/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
+static int gpiochip_find_base(int ngpio)
+{
+ int i;
+ int spare = 0;
+ int base = -ENOSPC;
+
+ for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
+ struct gpio_desc *desc = &gpio_desc[i];
+ struct gpio_chip *chip = desc->chip;
+
+ if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
+ spare++;
+ if (spare == ngpio) {
+ base = i;
+ break;
+ }
+ } else {
+ spare = 0;
+ if (chip)
+ i -= chip->ngpio - 1;
+ }
+ }
+
+ if (gpio_is_valid(base))
+ pr_debug("%s: found new base at %d\n", __func__, base);
+ return base;
+}
+
+/**
+ * gpiochip_reserve() - reserve range of gpios to use with platform code only
+ * @start: starting gpio number
+ * @ngpio: number of gpios to reserve
+ * Context: platform init, potentially before irqs or kmalloc will work
+ *
+ * Returns a negative errno if any gpio within the range is already reserved
+ * or registered, else returns zero as a success code. Use this function
+ * to mark a range of gpios as unavailable for dynamic gpio number allocation,
+ * for example because its driver support is not yet loaded.
+ */
+int __init gpiochip_reserve(int start, int ngpio)
+{
+ int ret = 0;
+ unsigned long flags;
+ int i;
+
+ if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio))
+ return -EINVAL;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ for (i = start; i < start + ngpio; i++) {
+ struct gpio_desc *desc = &gpio_desc[i];
+
+ if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ set_bit(FLAG_RESERVED, &desc->flags);
+ }
+
+ pr_debug("%s: reserved gpios from %d to %d\n",
+ __func__, start, start + ngpio - 1);
+err:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return ret;
+}
+
/**
* gpiochip_add() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
@@ -85,38 +159,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
* Returns a negative errno if the chip can't be registered, such as
* because the chip->base is invalid or already associated with a
* different chip. Otherwise it returns zero as a success code.
+ *
+ * If chip->base is negative, this requests dynamic assignment of
+ * a range of valid GPIOs.
*/
int gpiochip_add(struct gpio_chip *chip)
{
unsigned long flags;
int status = 0;
unsigned id;
+ int base = chip->base;
- /* NOTE chip->base negative is reserved to mean a request for
- * dynamic allocation. We don't currently support that.
- */
-
- if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) {
+ if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
+ && base >= 0) {
status = -EINVAL;
goto fail;
}
spin_lock_irqsave(&gpio_lock, flags);
+ if (base < 0) {
+ base = gpiochip_find_base(chip->ngpio);
+ if (base < 0) {
+ status = base;
+ goto fail_unlock;
+ }
+ chip->base = base;
+ }
+
/* these GPIO numbers must not be managed by another gpio_chip */
- for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+ for (id = base; id < base + chip->ngpio; id++) {
if (gpio_desc[id].chip != NULL) {
status = -EBUSY;
break;
}
}
if (status == 0) {
- for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+ for (id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip = chip;
gpio_desc[id].flags = 0;
}
}
+fail_unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
fail:
/* failures here can mean systems won't boot... */
@@ -171,12 +256,15 @@ int gpio_request(unsigned gpio, const char *label)
spin_lock_irqsave(&gpio_lock, flags);
- if (gpio >= ARCH_NR_GPIOS)
+ if (!gpio_is_valid(gpio))
goto done;
desc = &gpio_desc[gpio];
if (desc->chip == NULL)
goto done;
+ if (!try_module_get(desc->chip->owner))
+ goto done;
+
/* NOTE: gpio_request() can be called in early boot,
* before IRQs are enabled.
*/
@@ -184,8 +272,10 @@ int gpio_request(unsigned gpio, const char *label)
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
desc_set_label(desc, label ? : "?");
status = 0;
- } else
+ } else {
status = -EBUSY;
+ module_put(desc->chip->owner);
+ }
done:
if (status)
@@ -201,7 +291,7 @@ void gpio_free(unsigned gpio)
unsigned long flags;
struct gpio_desc *desc;
- if (gpio >= ARCH_NR_GPIOS) {
+ if (!gpio_is_valid(gpio)) {
WARN_ON(extra_checks);
return;
}
@@ -209,9 +299,10 @@ void gpio_free(unsigned gpio)
spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
- if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags))
+ if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
desc_set_label(desc, NULL);
- else
+ module_put(desc->chip->owner);
+ } else
WARN_ON(extra_checks);
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -236,7 +327,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
{
unsigned gpio = chip->base + offset;
- if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip)
+ if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip)
return NULL;
if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
return NULL;
@@ -267,7 +358,7 @@ int gpio_direction_input(unsigned gpio)
spin_lock_irqsave(&gpio_lock, flags);
- if (gpio >= ARCH_NR_GPIOS)
+ if (!gpio_is_valid(gpio))
goto fail;
chip = desc->chip;
if (!chip || !chip->get || !chip->direction_input)
@@ -305,7 +396,7 @@ int gpio_direction_output(unsigned gpio, int value)
spin_lock_irqsave(&gpio_lock, flags);
- if (gpio >= ARCH_NR_GPIOS)
+ if (!gpio_is_valid(gpio))
goto fail;
chip = desc->chip;
if (!chip || !chip->set || !chip->direction_output)
@@ -522,7 +613,7 @@ static int gpiolib_show(struct seq_file *s, void *unused)
/* REVISIT this isn't locked against gpio_chip removal ... */
- for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
+ for (gpio = 0; gpio_is_valid(gpio); gpio++) {
if (chip == gpio_desc[gpio].chip)
continue;
chip = gpio_desc[gpio].chip;
diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c
index bb60e8c1a1f0..7fb5b9d009d4 100644
--- a/drivers/gpio/mcp23s08.c
+++ b/drivers/gpio/mcp23s08.c
@@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_device *spi)
mcp->chip.base = pdata->base;
mcp->chip.ngpio = 8;
mcp->chip.can_sleep = 1;
+ mcp->chip.owner = THIS_MODULE;
spi_set_drvdata(spi, mcp);
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 6e72fd31184d..e0e0af536108 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -189,6 +189,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->base = chip->gpio_start;
gc->ngpio = gpios;
gc->label = chip->client->name;
+ gc->owner = THIS_MODULE;
}
static int __devinit pca953x_probe(struct i2c_client *client)
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
index c6b3b5378384..1106aa15ac79 100644
--- a/drivers/gpio/pcf857x.c
+++ b/drivers/gpio/pcf857x.c
@@ -159,6 +159,7 @@ static int pcf857x_probe(struct i2c_client *client)
gpio->chip.base = pdata->gpio_base;
gpio->chip.can_sleep = 1;
+ gpio->chip.owner = THIS_MODULE;
/* NOTE: the OnSemi jlc1562b is also largely compatible with
* these parts, notably for output. It has a low-resolution
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index e0d805f1b2bf..01427c51c7cc 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -654,7 +654,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf),
+ ((HID_OUTPUT_REPORT + 1) << 8) | *buf,
interface->desc.bInterfaceNumber, buf + 1, count - 1,
USB_CTRL_SET_TIMEOUT);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 28ddc3fdd3d1..d3f8d9194f30 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -405,6 +405,9 @@
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+#define USB_VENDOR_ID_KYE 0x0458
+#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -698,6 +701,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560, HID_QUIRK_IGNORE },
{ 0, 0 }
};
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 87532034d105..f702f9152ce6 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -862,40 +862,6 @@ config BLK_DEV_IDE_BAST
Say Y here if you want to support the onboard IDE channels on the
Simtec BAST or the Thorcom VR1000
-config ETRAX_IDE
- tristate "ETRAX IDE support"
- depends on CRIS && BROKEN
- select BLK_DEV_IDEDMA
- help
- Enables the ETRAX IDE driver.
-
- You can't use parallel ports or SCSI ports at the same time.
-
-config ETRAX_IDE_DELAY
- int "Delay for drives to regain consciousness"
- depends on ETRAX_IDE && ETRAX_ARCH_V10
- default 15
- help
- Number of seconds to wait for IDE drives to spin up after an IDE
- reset.
-
-choice
- prompt "IDE reset pin"
- depends on ETRAX_IDE && ETRAX_ARCH_V10
- default ETRAX_IDE_PB7_RESET
-
-config ETRAX_IDE_PB7_RESET
- bool "Port_PB_Bit_7"
- help
- IDE reset on pin 7 on port B
-
-config ETRAX_IDE_G27_RESET
- bool "Port_G_Bit_27"
- help
- IDE reset on pin 27 on port G
-
-endchoice
-
config IDE_H8300
tristate "H8300 IDE support"
depends on H8300
@@ -1031,7 +997,7 @@ comment "Other IDE chipsets support"
comment "Note: most of these also require special kernel boot parameters"
config BLK_DEV_4DRIVES
- bool "Generic 4 drives/port support"
+ tristate "Generic 4 drives/port support"
help
Certain older chipsets, including the Tekram 690CD, use a single set
of I/O ports at 0x1f0 to control up to four drives, instead of the
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 571544c37bb2..f94b679b611e 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -35,7 +35,7 @@ ifeq ($(CONFIG_BLK_DEV_CMD640), y)
obj-y += cmd640-core.o
endif
-obj-$(CONFIG_BLK_DEV_IDE) += cris/ ppc/
+obj-$(CONFIG_BLK_DEV_IDE) += ppc/
obj-$(CONFIG_IDE_H8300) += h8300/
obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index ec46c44b061c..713cef20622e 100644
--- a/drivers/ide/arm/bast-ide.c
+++ b/drivers/ide/arm/bast-ide.c
@@ -21,6 +21,8 @@
#include <asm/arch/bast-map.h>
#include <asm/arch/bast-irq.h>
+#define DRV_NAME "bast-ide"
+
static int __init bastide_register(unsigned int base, unsigned int aux, int irq)
{
ide_hwif_t *hwif;
@@ -33,27 +35,23 @@ static int __init bastide_register(unsigned int base, unsigned int aux, int irq)
base += BAST_IDE_CS;
aux += BAST_IDE_CS;
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hw.io_ports[i] = (unsigned long)base;
+ for (i = 0; i <= 7; i++) {
+ hw.io_ports_array[i] = (unsigned long)base;
base += 0x20;
}
- hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
+ hw.io_ports.ctl_addr = aux + (6 * 0x20);
hw.irq = irq;
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif == NULL)
goto out;
i = hwif->index;
- if (hwif->present)
- ide_unregister(i);
- else
- ide_init_port_data(hwif, i);
-
+ ide_init_port_data(hwif, i);
ide_init_port_hw(hwif, &hw);
- hwif->quirkproc = NULL;
+ hwif->port_ops = NULL;
idx[0] = i;
@@ -64,6 +62,8 @@ out:
static int __init bastide_init(void)
{
+ unsigned long base = BAST_VA_IDEPRI + BAST_IDE_CS;
+
/* we can treat the VR1000 and the BAST the same */
if (!(machine_is_bast() || machine_is_vr1000()))
@@ -71,6 +71,11 @@ static int __init bastide_init(void)
printk("BAST: IDE driver, (c) 2003-2004 Simtec Electronics\n");
+ if (!request_mem_region(base, 0x400000, DRV_NAME)) {
+ printk(KERN_ERR "%s: resources busy\n", DRV_NAME);
+ return -EBUSY;
+ }
+
bastide_register(BAST_VA_IDEPRI, BAST_VA_IDEPRIAUX, IRQ_IDE0);
bastide_register(BAST_VA_IDESEC, BAST_VA_IDESECAUX, IRQ_IDE1);
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index e816b0ffcfe6..061456914ca3 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -191,6 +191,10 @@ static void icside_maskproc(ide_drive_t *drive, int mask)
local_irq_restore(flags);
}
+static const struct ide_port_ops icside_v6_no_dma_port_ops = {
+ .maskproc = icside_maskproc,
+};
+
#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
/*
* SG-DMA support.
@@ -266,6 +270,11 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
}
+static const struct ide_port_ops icside_v6_port_ops = {
+ .set_dma_mode = icside_set_dma_mode,
+ .maskproc = icside_maskproc,
+};
+
static void icside_dma_host_set(ide_drive_t *drive, int on)
{
}
@@ -375,48 +384,57 @@ static void icside_dma_lost_irq(ide_drive_t *drive)
printk(KERN_ERR "%s: IRQ lost\n", drive->name);
}
-static void icside_dma_init(ide_hwif_t *hwif)
+static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
{
hwif->dmatable_cpu = NULL;
hwif->dmatable_dma = 0;
- hwif->set_dma_mode = icside_set_dma_mode;
-
- hwif->dma_host_set = icside_dma_host_set;
- hwif->dma_setup = icside_dma_setup;
- hwif->dma_exec_cmd = icside_dma_exec_cmd;
- hwif->dma_start = icside_dma_start;
- hwif->ide_dma_end = icside_dma_end;
- hwif->ide_dma_test_irq = icside_dma_test_irq;
- hwif->dma_timeout = icside_dma_timeout;
- hwif->dma_lost_irq = icside_dma_lost_irq;
+
+ return 0;
}
+
+static const struct ide_dma_ops icside_v6_dma_ops = {
+ .dma_host_set = icside_dma_host_set,
+ .dma_setup = icside_dma_setup,
+ .dma_exec_cmd = icside_dma_exec_cmd,
+ .dma_start = icside_dma_start,
+ .dma_end = icside_dma_end,
+ .dma_test_irq = icside_dma_test_irq,
+ .dma_timeout = icside_dma_timeout,
+ .dma_lost_irq = icside_dma_lost_irq,
+};
#else
-#define icside_dma_init(hwif) (0)
+#define icside_v6_dma_ops NULL
#endif
+static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ return -EOPNOTSUPP;
+}
+
static ide_hwif_t *
icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *ec)
{
unsigned long port = (unsigned long)base + info->dataoffset;
ide_hwif_t *hwif;
- hwif = ide_find_port(port);
+ hwif = ide_find_port();
if (hwif) {
- int i;
-
/*
* Ensure we're using MMIO
*/
default_hwif_mmiops(hwif);
- hwif->mmio = 1;
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hwif->io_ports[i] = port;
- port += 1 << info->stepping;
- }
- hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
+ hwif->io_ports.data_addr = port;
+ hwif->io_ports.error_addr = port + (1 << info->stepping);
+ hwif->io_ports.nsect_addr = port + (2 << info->stepping);
+ hwif->io_ports.lbal_addr = port + (3 << info->stepping);
+ hwif->io_ports.lbam_addr = port + (4 << info->stepping);
+ hwif->io_ports.lbah_addr = port + (5 << info->stepping);
+ hwif->io_ports.device_addr = port + (6 << info->stepping);
+ hwif->io_ports.status_addr = port + (7 << info->stepping);
+ hwif->io_ports.ctl_addr =
+ (unsigned long)base + info->ctrloffset;
hwif->irq = ec->irq;
- hwif->noprobe = 0;
hwif->chipset = ide_acorn;
hwif->gendev.parent = &ec->dev;
hwif->dev = &ec->dev;
@@ -462,9 +480,10 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
}
static const struct ide_port_info icside_v6_port_info __initdata = {
- .host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
- IDE_HFLAG_NO_AUTOTUNE,
+ .init_dma = icside_dma_off_init,
+ .port_ops = &icside_v6_no_dma_port_ops,
+ .dma_ops = &icside_v6_dma_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
.mwdma_mask = ATA_MWDMA2,
.swdma_mask = ATA_SWDMA2,
};
@@ -526,21 +545,19 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
state->hwif[0] = hwif;
state->hwif[1] = mate;
- hwif->maskproc = icside_maskproc;
hwif->hwif_data = state;
hwif->config_data = (unsigned long)ioc_base;
hwif->select_data = sel;
- mate->maskproc = icside_maskproc;
mate->hwif_data = state;
mate->config_data = (unsigned long)ioc_base;
mate->select_data = sel | 1;
if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
- icside_dma_init(hwif);
- icside_dma_init(mate);
- } else
- d.mwdma_mask = d.swdma_mask = 0;
+ d.init_dma = icside_dma_init;
+ d.port_ops = &icside_v6_port_ops;
+ d.dma_ops = NULL;
+ }
idx[0] = hwif->index;
idx[1] = mate->index;
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index be9ff7334c52..4263ffd4ab20 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -14,6 +14,8 @@
#include <asm/mach-types.h>
#include <asm/irq.h>
+#define DRV_NAME "ide_arm"
+
#ifdef CONFIG_ARCH_CLPS7500
# include <asm/arch/hardware.h>
#
@@ -28,13 +30,27 @@ static int __init ide_arm_init(void)
{
ide_hwif_t *hwif;
hw_regs_t hw;
+ unsigned long base = IDE_ARM_IO, ctl = IDE_ARM_IO + 0x206;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
+ ide_std_init_ports(&hw, base, ctl);
hw.irq = IDE_ARM_IRQ;
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif) {
ide_init_port_hw(hwif, &hw);
idx[0] = hwif->index;
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
index 474162cdf665..96378ebfb31f 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -96,11 +96,11 @@ static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
u16 val16;
/* DMA Data Setup */
- t0 = (palm_bk3710_udmatimings[mode].cycletime + ide_palm_clk - 1)
- / ide_palm_clk - 1;
- tenv = (20 + ide_palm_clk - 1) / ide_palm_clk - 1;
- trp = (palm_bk3710_udmatimings[mode].rptime + ide_palm_clk - 1)
- / ide_palm_clk - 1;
+ t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime,
+ ide_palm_clk) - 1;
+ tenv = DIV_ROUND_UP(20, ide_palm_clk) - 1;
+ trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime,
+ ide_palm_clk) - 1;
/* udmatim Register */
val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
@@ -141,8 +141,8 @@ static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
cycletime = max_t(int, t->cycle, min_cycle);
/* DMA Data Setup */
- t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
- td = (t->active + ide_palm_clk - 1) / ide_palm_clk;
+ t0 = DIV_ROUND_UP(cycletime, ide_palm_clk);
+ td = DIV_ROUND_UP(t->active, ide_palm_clk);
tkw = t0 - td - 1;
td -= 1;
@@ -168,9 +168,9 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
struct ide_timing *t;
/* PIO Data Setup */
- t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
- t2 = (ide_timing_find_mode(XFER_PIO_0 + mode)->active +
- ide_palm_clk - 1) / ide_palm_clk;
+ t0 = DIV_ROUND_UP(cycletime, ide_palm_clk);
+ t2 = DIV_ROUND_UP(ide_timing_find_mode(XFER_PIO_0 + mode)->active,
+ ide_palm_clk);
t2i = t0 - t2 - 1;
t2 -= 1;
@@ -192,8 +192,8 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
/* TASKFILE Setup */
t = ide_timing_find_mode(XFER_PIO_0 + mode);
- t0 = (t->cyc8b + ide_palm_clk - 1) / ide_palm_clk;
- t2 = (t->act8b + ide_palm_clk - 1) / ide_palm_clk;
+ t0 = DIV_ROUND_UP(t->cyc8b, ide_palm_clk);
+ t2 = DIV_ROUND_UP(t->act8b, ide_palm_clk);
t2i = t0 - t2 - 1;
t2 -= 1;
@@ -317,17 +317,32 @@ static u8 __devinit palm_bk3710_cable_detect(ide_hwif_t *hwif)
return ATA_CBL_PATA80;
}
-static void __devinit palm_bk3710_init_hwif(ide_hwif_t *hwif)
+static int __devinit palm_bk3710_init_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
{
- hwif->set_pio_mode = palm_bk3710_set_pio_mode;
- hwif->set_dma_mode = palm_bk3710_set_dma_mode;
+ unsigned long base =
+ hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET;
- hwif->cable_detect = palm_bk3710_cable_detect;
+ printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ ide_setup_dma(hwif, base);
+
+ return 0;
}
+static const struct ide_port_ops palm_bk3710_ports_ops = {
+ .set_pio_mode = palm_bk3710_set_pio_mode,
+ .set_dma_mode = palm_bk3710_set_dma_mode,
+ .cable_detect = palm_bk3710_cable_detect,
+};
+
static const struct ide_port_info __devinitdata palm_bk3710_port_info = {
- .init_hwif = palm_bk3710_init_hwif,
- .host_flags = IDE_HFLAG_NO_DMA, /* hack (no PCI) */
+ .init_dma = palm_bk3710_init_dma,
+ .port_ops = &palm_bk3710_ports_ops,
+ .host_flags = IDE_HFLAG_MMIO,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA4, /* (input clk 99MHz) */
.mwdma_mask = ATA_MWDMA2,
@@ -372,30 +387,24 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev)
pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET;
for (i = 0; i < IDE_NR_PORTS - 2; i++)
- hw.io_ports[i] = pribase + i;
- hw.io_ports[IDE_CONTROL_OFFSET] = mem->start +
+ hw.io_ports_array[i] = pribase + i;
+ hw.io_ports.ctl_addr = mem->start +
IDE_PALM_ATA_PRI_CTL_OFFSET;
hw.irq = irq->start;
hw.chipset = ide_palm3710;
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif == NULL)
goto out;
i = hwif->index;
- if (hwif->present)
- ide_unregister(i);
- else
- ide_init_port_data(hwif, i);
-
+ ide_init_port_data(hwif, i);
ide_init_port_hw(hwif, &hw);
hwif->mmio = 1;
default_hwif_mmiops(hwif);
- ide_setup_dma(hwif, mem->start);
-
idx[0] = i;
ide_device_add(idx, &palm_bk3710_port_info);
@@ -409,9 +418,13 @@ out:
return -ENODEV;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:palm_bk3710");
+
static struct platform_driver platform_bk_driver = {
.driver = {
.name = "palm_bk3710",
+ .owner = THIS_MODULE,
},
.probe = palm_bk3710_probe,
.remove = NULL,
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index b30adcf321c3..1747b2358775 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -17,11 +17,11 @@ static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
unsigned long port = (unsigned long)base;
int i;
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hw->io_ports[i] = port;
+ for (i = 0; i <= 7; i++) {
+ hw->io_ports_array[i] = port;
port += sz;
}
- hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+ hw->io_ports.ctl_addr = (unsigned long)ctrl;
hw->irq = irq;
}
@@ -44,7 +44,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- hwif = ide_find_port((unsigned long)base);
+ hwif = ide_find_port();
if (hwif) {
memset(&hw, 0, sizeof(hw));
rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
@@ -53,7 +53,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
ide_init_port_hw(hwif, &hw);
- hwif->mmio = 1;
+ hwif->host_flags = IDE_HFLAG_MMIO;
default_hwif_mmiops(hwif);
idx[0] = hwif->index;
@@ -76,7 +76,7 @@ static void __devexit rapide_remove(struct expansion_card *ec)
ecard_set_drvdata(ec, NULL);
- ide_unregister(hwif->index);
+ ide_unregister(hwif);
ecard_release_resources(ec);
}
diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
deleted file mode 100644
index 20b95960531f..000000000000
--- a/drivers/ide/cris/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-EXTRA_CFLAGS += -Idrivers/ide
-
-obj-$(CONFIG_IDE_ETRAX) += ide-cris.o
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
deleted file mode 100644
index 31266d278095..000000000000
--- a/drivers/ide/cris/ide-cris.c
+++ /dev/null
@@ -1,1081 +0,0 @@
-/*
- * Etrax specific IDE functions, like init and PIO-mode setting etc.
- * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
- * Copyright (c) 2000-2005 Axis Communications AB
- *
- * Authors: Bjorn Wesen (initial version)
- * Mikael Starvik (crisv32 port)
- */
-
-/* Regarding DMA:
- *
- * There are two forms of DMA - "DMA handshaking" between the interface and the drive,
- * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
- * something built-in in the Etrax. However only some drives support the DMA-mode handshaking
- * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
- * device can't do DMA handshaking for some stupid reason. We don't need to do that.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-/* number of DMA descriptors */
-#define MAX_DMA_DESCRS 64
-
-/* number of times to retry busy-flags when reading/writing IDE-registers
- * this can't be too high because a hung harddisk might cause the watchdog
- * to trigger (sometimes INB and OUTB are called with irq's disabled)
- */
-
-#define IDE_REGISTER_TIMEOUT 300
-
-#define LOWDB(x)
-#define D(x)
-
-enum /* Transfer types */
-{
- TYPE_PIO,
- TYPE_DMA,
- TYPE_UDMA
-};
-
-/* CRISv32 specifics */
-#ifdef CONFIG_ETRAX_ARCH_V32
-#include <asm/arch/hwregs/ata_defs.h>
-#include <asm/arch/hwregs/dma_defs.h>
-#include <asm/arch/hwregs/dma.h>
-#include <asm/arch/pinmux.h>
-
-#define ATA_UDMA2_CYC 2
-#define ATA_UDMA2_DVS 3
-#define ATA_UDMA1_CYC 2
-#define ATA_UDMA1_DVS 4
-#define ATA_UDMA0_CYC 4
-#define ATA_UDMA0_DVS 6
-#define ATA_DMA2_STROBE 7
-#define ATA_DMA2_HOLD 1
-#define ATA_DMA1_STROBE 8
-#define ATA_DMA1_HOLD 3
-#define ATA_DMA0_STROBE 25
-#define ATA_DMA0_HOLD 19
-#define ATA_PIO4_SETUP 3
-#define ATA_PIO4_STROBE 7
-#define ATA_PIO4_HOLD 1
-#define ATA_PIO3_SETUP 3
-#define ATA_PIO3_STROBE 9
-#define ATA_PIO3_HOLD 3
-#define ATA_PIO2_SETUP 3
-#define ATA_PIO2_STROBE 13
-#define ATA_PIO2_HOLD 5
-#define ATA_PIO1_SETUP 5
-#define ATA_PIO1_STROBE 23
-#define ATA_PIO1_HOLD 9
-#define ATA_PIO0_SETUP 9
-#define ATA_PIO0_STROBE 39
-#define ATA_PIO0_HOLD 9
-
-int
-cris_ide_ack_intr(ide_hwif_t* hwif)
-{
- reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2,
- int, hwif->io_ports[0]);
- REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel);
- return 1;
-}
-
-static inline int
-cris_ide_busy(void)
-{
- reg_ata_rs_stat_data stat_data;
- stat_data = REG_RD(ata, regi_ata, rs_stat_data);
- return stat_data.busy;
-}
-
-static inline int
-cris_ide_ready(void)
-{
- return !cris_ide_busy();
-}
-
-static inline int
-cris_ide_data_available(unsigned short* data)
-{
- reg_ata_rs_stat_data stat_data;
- stat_data = REG_RD(ata, regi_ata, rs_stat_data);
- *data = stat_data.data;
- return stat_data.dav;
-}
-
-static void
-cris_ide_write_command(unsigned long command)
-{
- REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */
-}
-
-static void
-cris_ide_set_speed(int type, int setup, int strobe, int hold)
-{
- reg_ata_rw_ctrl0 ctrl0 = REG_RD(ata, regi_ata, rw_ctrl0);
- reg_ata_rw_ctrl1 ctrl1 = REG_RD(ata, regi_ata, rw_ctrl1);
-
- if (type == TYPE_PIO) {
- ctrl0.pio_setup = setup;
- ctrl0.pio_strb = strobe;
- ctrl0.pio_hold = hold;
- } else if (type == TYPE_DMA) {
- ctrl0.dma_strb = strobe;
- ctrl0.dma_hold = hold;
- } else if (type == TYPE_UDMA) {
- ctrl1.udma_tcyc = setup;
- ctrl1.udma_tdvs = strobe;
- }
- REG_WR(ata, regi_ata, rw_ctrl0, ctrl0);
- REG_WR(ata, regi_ata, rw_ctrl1, ctrl1);
-}
-
-static unsigned long
-cris_ide_base_address(int bus)
-{
- reg_ata_rw_ctrl2 ctrl2 = {0};
- ctrl2.sel = bus;
- return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2);
-}
-
-static unsigned long
-cris_ide_reg_addr(unsigned long addr, int cs0, int cs1)
-{
- reg_ata_rw_ctrl2 ctrl2 = {0};
- ctrl2.addr = addr;
- ctrl2.cs1 = cs1;
- ctrl2.cs0 = cs0;
- return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2);
-}
-
-static __init void
-cris_ide_reset(unsigned val)
-{
- reg_ata_rw_ctrl0 ctrl0 = {0};
- ctrl0.rst = val ? regk_ata_active : regk_ata_inactive;
- REG_WR(ata, regi_ata, rw_ctrl0, ctrl0);
-}
-
-static __init void
-cris_ide_init(void)
-{
- reg_ata_rw_ctrl0 ctrl0 = {0};
- reg_ata_rw_intr_mask intr_mask = {0};
-
- ctrl0.en = regk_ata_yes;
- REG_WR(ata, regi_ata, rw_ctrl0, ctrl0);
-
- intr_mask.bus0 = regk_ata_yes;
- intr_mask.bus1 = regk_ata_yes;
- intr_mask.bus2 = regk_ata_yes;
- intr_mask.bus3 = regk_ata_yes;
-
- REG_WR(ata, regi_ata, rw_intr_mask, intr_mask);
-
- crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);
- crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata);
-
- crisv32_pinmux_alloc_fixed(pinmux_ata);
- crisv32_pinmux_alloc_fixed(pinmux_ata0);
- crisv32_pinmux_alloc_fixed(pinmux_ata1);
- crisv32_pinmux_alloc_fixed(pinmux_ata2);
- crisv32_pinmux_alloc_fixed(pinmux_ata3);
-
- DMA_RESET(regi_dma2);
- DMA_ENABLE(regi_dma2);
- DMA_RESET(regi_dma3);
- DMA_ENABLE(regi_dma3);
-
- DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2);
- DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2);
-}
-
-static dma_descr_context mycontext __attribute__ ((__aligned__(32)));
-
-#define cris_dma_descr_type dma_descr_data
-#define cris_pio_read regk_ata_rd
-#define cris_ultra_mask 0x7
-#define MAX_DESCR_SIZE 0xffffffffUL
-
-static unsigned long
-cris_ide_get_reg(unsigned long reg)
-{
- return (reg & 0x0e000000) >> 25;
-}
-
-static void
-cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last)
-{
- d->buf = (char*)virt_to_phys(buf);
- d->after = d->buf + len;
- d->eol = last;
-}
-
-static void
-cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir,int type,int len)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int,
- hwif->io_ports[IDE_DATA_OFFSET]);
- reg_ata_rw_trf_cnt trf_cnt = {0};
-
- mycontext.saved_data = (dma_descr_data*)virt_to_phys(d);
- mycontext.saved_data_buf = d->buf;
- /* start the dma channel */
- DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext));
-
- /* initiate a multi word dma read using PIO handshaking */
- trf_cnt.cnt = len >> 1;
- /* Due to a "feature" the transfer count has to be one extra word for UDMA. */
- if (type == TYPE_UDMA)
- trf_cnt.cnt++;
- REG_WR(ata, regi_ata, rw_trf_cnt, trf_cnt);
-
- ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr;
- ctrl2.trf_mode = regk_ata_dma;
- ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio :
- type == TYPE_DMA ? regk_ata_dma : regk_ata_udma;
- ctrl2.multi = regk_ata_yes;
- ctrl2.dma_size = regk_ata_word;
- REG_WR(ata, regi_ata, rw_ctrl2, ctrl2);
-}
-
-static void
-cris_ide_wait_dma(int dir)
-{
- reg_dma_rw_stat status;
- do
- {
- status = REG_RD(dma, dir ? regi_dma3 : regi_dma2, rw_stat);
- } while(status.list_state != regk_dma_data_at_eol);
-}
-
-static int cris_dma_test_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- int intr = REG_RD_INT(ata, regi_ata, r_intr);
-
- reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int,
- hwif->io_ports[IDE_DATA_OFFSET]);
-
- return intr & (1 << ctrl2.sel) ? 1 : 0;
-}
-
-static void cris_ide_initialize_dma(int dir)
-{
-}
-
-#else
-/* CRISv10 specifics */
-#include <asm/arch/svinto.h>
-#include <asm/arch/io_interface_mux.h>
-
-/* PIO timing (in R_ATA_CONFIG)
- *
- * _____________________________
- * ADDRESS : ________/
- *
- * _______________
- * DIOR : ____________/ \__________
- *
- * _______________
- * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX
- *
- *
- * DIOR is unbuffered while address and data is buffered.
- * This creates two problems:
- * 1. The DIOR pulse is to early (because it is unbuffered)
- * 2. The rise time of DIOR is long
- *
- * There are at least three different plausible solutions
- * 1. Use a pad capable of larger currents in Etrax
- * 2. Use an external buffer
- * 3. Make the strobe pulse longer
- *
- * Some of the strobe timings below are modified to compensate
- * for this. This implies a slight performance decrease.
- *
- * THIS SHOULD NEVER BE CHANGED!
- *
- * TODO: Is this true for the latest LX boards still ?
- */
-
-#define ATA_UDMA2_CYC 0 /* No UDMA supported, just to make it compile. */
-#define ATA_UDMA2_DVS 0
-#define ATA_UDMA1_CYC 0
-#define ATA_UDMA1_DVS 0
-#define ATA_UDMA0_CYC 0
-#define ATA_UDMA0_DVS 0
-#define ATA_DMA2_STROBE 4
-#define ATA_DMA2_HOLD 0
-#define ATA_DMA1_STROBE 4
-#define ATA_DMA1_HOLD 1
-#define ATA_DMA0_STROBE 12
-#define ATA_DMA0_HOLD 9
-#define ATA_PIO4_SETUP 1
-#define ATA_PIO4_STROBE 5
-#define ATA_PIO4_HOLD 0
-#define ATA_PIO3_SETUP 1
-#define ATA_PIO3_STROBE 5
-#define ATA_PIO3_HOLD 1
-#define ATA_PIO2_SETUP 1
-#define ATA_PIO2_STROBE 6
-#define ATA_PIO2_HOLD 2
-#define ATA_PIO1_SETUP 2
-#define ATA_PIO1_STROBE 11
-#define ATA_PIO1_HOLD 4
-#define ATA_PIO0_SETUP 4
-#define ATA_PIO0_STROBE 19
-#define ATA_PIO0_HOLD 4
-
-int
-cris_ide_ack_intr(ide_hwif_t* hwif)
-{
- return 1;
-}
-
-static inline int
-cris_ide_busy(void)
-{
- return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ;
-}
-
-static inline int
-cris_ide_ready(void)
-{
- return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ;
-}
-
-static inline int
-cris_ide_data_available(unsigned short* data)
-{
- unsigned long status = *R_ATA_STATUS_DATA;
- *data = (unsigned short)status;
- return status & IO_MASK(R_ATA_STATUS_DATA, dav);
-}
-
-static void
-cris_ide_write_command(unsigned long command)
-{
- *R_ATA_CTRL_DATA = command;
-}
-
-static void
-cris_ide_set_speed(int type, int setup, int strobe, int hold)
-{
- static int pio_setup = ATA_PIO4_SETUP;
- static int pio_strobe = ATA_PIO4_STROBE;
- static int pio_hold = ATA_PIO4_HOLD;
- static int dma_strobe = ATA_DMA2_STROBE;
- static int dma_hold = ATA_DMA2_HOLD;
-
- if (type == TYPE_PIO) {
- pio_setup = setup;
- pio_strobe = strobe;
- pio_hold = hold;
- } else if (type == TYPE_DMA) {
- dma_strobe = strobe;
- dma_hold = hold;
- }
- *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
- IO_FIELD( R_ATA_CONFIG, dma_strobe, dma_strobe ) |
- IO_FIELD( R_ATA_CONFIG, dma_hold, dma_hold ) |
- IO_FIELD( R_ATA_CONFIG, pio_setup, pio_setup ) |
- IO_FIELD( R_ATA_CONFIG, pio_strobe, pio_strobe ) |
- IO_FIELD( R_ATA_CONFIG, pio_hold, pio_hold ) );
-}
-
-static unsigned long
-cris_ide_base_address(int bus)
-{
- return IO_FIELD(R_ATA_CTRL_DATA, sel, bus);
-}
-
-static unsigned long
-cris_ide_reg_addr(unsigned long addr, int cs0, int cs1)
-{
- return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) |
- IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) |
- IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1);
-}
-
-static __init void
-cris_ide_reset(unsigned val)
-{
-#ifdef CONFIG_ETRAX_IDE_G27_RESET
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val);
-#endif
-#ifdef CONFIG_ETRAX_IDE_PB7_RESET
- port_pb_dir_shadow = port_pb_dir_shadow |
- IO_STATE(R_PORT_PB_DIR, dir7, output);
- *R_PORT_PB_DIR = port_pb_dir_shadow;
- REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, val);
-#endif
-}
-
-static __init void
-cris_ide_init(void)
-{
- volatile unsigned int dummy;
-
- *R_ATA_CTRL_DATA = 0;
- *R_ATA_TRANSFER_CNT = 0;
- *R_ATA_CONFIG = 0;
-
- if (cris_request_io_interface(if_ata, "ETRAX100LX IDE")) {
- printk(KERN_CRIT "ide: Failed to get IO interface\n");
- return;
- } else if (cris_request_dma(ATA_TX_DMA_NBR,
- "ETRAX100LX IDE TX",
- DMA_VERBOSE_ON_ERROR,
- dma_ata)) {
- cris_free_io_interface(if_ata);
- printk(KERN_CRIT "ide: Failed to get Tx DMA channel\n");
- return;
- } else if (cris_request_dma(ATA_RX_DMA_NBR,
- "ETRAX100LX IDE RX",
- DMA_VERBOSE_ON_ERROR,
- dma_ata)) {
- cris_free_dma(ATA_TX_DMA_NBR, "ETRAX100LX IDE Tx");
- cris_free_io_interface(if_ata);
- printk(KERN_CRIT "ide: Failed to get Rx DMA channel\n");
- return;
- }
-
- /* make a dummy read to set the ata controller in a proper state */
- dummy = *R_ATA_STATUS_DATA;
-
- *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ));
- *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) |
- IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) );
-
- while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
-
- *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
- IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
- IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
- IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
-
- /* reset the dma channels we will use */
-
- RESET_DMA(ATA_TX_DMA_NBR);
- RESET_DMA(ATA_RX_DMA_NBR);
- WAIT_DMA(ATA_TX_DMA_NBR);
- WAIT_DMA(ATA_RX_DMA_NBR);
-}
-
-#define cris_dma_descr_type etrax_dma_descr
-#define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read)
-#define cris_ultra_mask 0x0
-#define MAX_DESCR_SIZE 0x10000UL
-
-static unsigned long
-cris_ide_get_reg(unsigned long reg)
-{
- return (reg & 0x0e000000) >> 25;
-}
-
-static void
-cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last)
-{
- d->buf = virt_to_phys(buf);
- d->sw_len = len == MAX_DESCR_SIZE ? 0 : len;
- if (last)
- d->ctrl |= d_eol;
-}
-
-static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len)
-{
- unsigned long cmd;
-
- if (dir) {
- /* need to do this before RX DMA due to a chip bug
- * it is enough to just flush the part of the cache that
- * corresponds to the buffers we start, but since HD transfers
- * usually are more than 8 kB, it is easier to optimize for the
- * normal case and just flush the entire cache. its the only
- * way to be sure! (OB movie quote)
- */
- flush_etrax_cache();
- *R_DMA_CH3_FIRST = virt_to_phys(d);
- *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
-
- } else {
- *R_DMA_CH2_FIRST = virt_to_phys(d);
- *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
- }
-
- /* initiate a multi word dma read using DMA handshaking */
-
- *R_ATA_TRANSFER_CNT =
- IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1);
-
- cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write);
- cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) :
- IO_STATE(R_ATA_CTRL_DATA, handsh, dma);
- *R_ATA_CTRL_DATA =
- cmd |
- IO_FIELD(R_ATA_CTRL_DATA, data,
- drive->hwif->io_ports[IDE_DATA_OFFSET]) |
- IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
- IO_STATE(R_ATA_CTRL_DATA, multi, on) |
- IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
-}
-
-static void
-cris_ide_wait_dma(int dir)
-{
- if (dir)
- WAIT_DMA(ATA_RX_DMA_NBR);
- else
- WAIT_DMA(ATA_TX_DMA_NBR);
-}
-
-static int cris_dma_test_irq(ide_drive_t *drive)
-{
- int intr = *R_IRQ_MASK0_RD;
- int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel,
- drive->hwif->io_ports[IDE_DATA_OFFSET]);
-
- return intr & (1 << (bus + IO_BITNR(R_IRQ_MASK0_RD, ata_irq0))) ? 1 : 0;
-}
-
-
-static void cris_ide_initialize_dma(int dir)
-{
- if (dir)
- {
- RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
- WAIT_DMA(ATA_RX_DMA_NBR);
- }
- else
- {
- RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
- WAIT_DMA(ATA_TX_DMA_NBR);
- }
-}
-
-#endif
-
-void
-cris_ide_outw(unsigned short data, unsigned long reg) {
- int timeleft;
-
- LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
-
- /* note the lack of handling any timeouts. we stop waiting, but we don't
- * really notify anybody.
- */
-
- timeleft = IDE_REGISTER_TIMEOUT;
- /* wait for busy flag */
- do {
- timeleft--;
- } while(timeleft && cris_ide_busy());
-
- /*
- * Fall through at a timeout, so the ongoing command will be
- * aborted by the write below, which is expected to be a dummy
- * command to the command register. This happens when a faulty
- * drive times out on a command. See comment on timeout in
- * INB.
- */
- if(!timeleft)
- printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
-
- cris_ide_write_command(reg|data); /* write data to the drive's register */
-
- timeleft = IDE_REGISTER_TIMEOUT;
- /* wait for transmitter ready */
- do {
- timeleft--;
- } while(timeleft && !cris_ide_ready());
-}
-
-void
-cris_ide_outb(unsigned char data, unsigned long reg)
-{
- cris_ide_outw(data, reg);
-}
-
-void
-cris_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
-{
- cris_ide_outw(addr, port);
-}
-
-unsigned short
-cris_ide_inw(unsigned long reg) {
- int timeleft;
- unsigned short val;
-
- timeleft = IDE_REGISTER_TIMEOUT;
- /* wait for busy flag */
- do {
- timeleft--;
- } while(timeleft && cris_ide_busy());
-
- if(!timeleft) {
- /*
- * If we're asked to read the status register, like for
- * example when a command does not complete for an
- * extended time, but the ATA interface is stuck in a
- * busy state at the *ETRAX* ATA interface level (as has
- * happened repeatedly with at least one bad disk), then
- * the best thing to do is to pretend that we read
- * "busy" in the status register, so the IDE driver will
- * time-out, abort the ongoing command and perform a
- * reset sequence. Note that the subsequent OUT_BYTE
- * call will also timeout on busy, but as long as the
- * write is still performed, everything will be fine.
- */
- if (cris_ide_get_reg(reg) == IDE_STATUS_OFFSET)
- return BUSY_STAT;
- else
- /* For other rare cases we assume 0 is good enough. */
- return 0;
- }
-
- cris_ide_write_command(reg | cris_pio_read);
-
- timeleft = IDE_REGISTER_TIMEOUT;
- /* wait for available */
- do {
- timeleft--;
- } while(timeleft && !cris_ide_data_available(&val));
-
- if(!timeleft)
- return 0;
-
- LOWDB(printk("inb: 0x%x from reg 0x%x\n", val & 0xff, reg));
-
- return val;
-}
-
-unsigned char
-cris_ide_inb(unsigned long reg)
-{
- return (unsigned char)cris_ide_inw(reg);
-}
-
-static int cris_dma_end (ide_drive_t *drive);
-static int cris_dma_setup (ide_drive_t *drive);
-static void cris_dma_exec_cmd (ide_drive_t *drive, u8 command);
-static int cris_dma_test_irq(ide_drive_t *drive);
-static void cris_dma_start(ide_drive_t *drive);
-static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
-static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
-static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
-static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
-
-static void cris_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio)
-{
- int setup, strobe, hold;
-
- switch(pio)
- {
- case 0:
- setup = ATA_PIO0_SETUP;
- strobe = ATA_PIO0_STROBE;
- hold = ATA_PIO0_HOLD;
- break;
- case 1:
- setup = ATA_PIO1_SETUP;
- strobe = ATA_PIO1_STROBE;
- hold = ATA_PIO1_HOLD;
- break;
- case 2:
- setup = ATA_PIO2_SETUP;
- strobe = ATA_PIO2_STROBE;
- hold = ATA_PIO2_HOLD;
- break;
- case 3:
- setup = ATA_PIO3_SETUP;
- strobe = ATA_PIO3_STROBE;
- hold = ATA_PIO3_HOLD;
- break;
- case 4:
- setup = ATA_PIO4_SETUP;
- strobe = ATA_PIO4_STROBE;
- hold = ATA_PIO4_HOLD;
- break;
- default:
- return;
- }
-
- cris_ide_set_speed(TYPE_PIO, setup, strobe, hold);
-}
-
-static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
-{
- int cyc = 0, dvs = 0, strobe = 0, hold = 0;
-
- switch(speed)
- {
- case XFER_UDMA_0:
- cyc = ATA_UDMA0_CYC;
- dvs = ATA_UDMA0_DVS;
- break;
- case XFER_UDMA_1:
- cyc = ATA_UDMA1_CYC;
- dvs = ATA_UDMA1_DVS;
- break;
- case XFER_UDMA_2:
- cyc = ATA_UDMA2_CYC;
- dvs = ATA_UDMA2_DVS;
- break;
- case XFER_MW_DMA_0:
- strobe = ATA_DMA0_STROBE;
- hold = ATA_DMA0_HOLD;
- break;
- case XFER_MW_DMA_1:
- strobe = ATA_DMA1_STROBE;
- hold = ATA_DMA1_HOLD;
- break;
- case XFER_MW_DMA_2:
- strobe = ATA_DMA2_STROBE;
- hold = ATA_DMA2_HOLD;
- break;
- }
-
- if (speed >= XFER_UDMA_0)
- cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0);
- else
- cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
-}
-
-static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base)
-{
- int i;
-
- memset(hw, 0, sizeof(*hw));
-
- for (i = 0; i <= 7; i++)
- hw->io_ports[i] = base + cris_ide_reg_addr(i, 0, 1);
-
- /*
- * the IDE control register is at ATA address 6,
- * with CS1 active instead of CS0
- */
- hw->io_ports[IDE_CONTROL_OFFSET] = base + cris_ide_reg_addr(6, 1, 0);
-
- hw->irq = ide_default_irq(0);
- hw->ack_intr = cris_ide_ack_intr;
-}
-
-static const struct ide_port_info cris_port_info __initdata = {
- .chipset = ide_etrax100,
- .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_NO_DMA, /* no SFF-style DMA */
- .pio_mask = ATA_PIO4,
- .udma_mask = cris_ultra_mask,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-static int __init init_e100_ide(void)
-{
- hw_regs_t hw;
- int h;
- u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-
- printk("ide: ETRAX FS built-in ATA DMA controller\n");
-
- for (h = 0; h < 4; h++) {
- ide_hwif_t *hwif = NULL;
-
- cris_setup_ports(&hw, cris_ide_base_address(h));
-
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
- if (hwif == NULL)
- continue;
- ide_init_port_data(hwif, hwif->index);
- ide_init_port_hw(hwif, &hw);
- hwif->mmio = 1;
- hwif->set_pio_mode = &cris_set_pio_mode;
- hwif->set_dma_mode = &cris_set_dma_mode;
- hwif->ata_input_data = &cris_ide_input_data;
- hwif->ata_output_data = &cris_ide_output_data;
- hwif->atapi_input_bytes = &cris_atapi_input_bytes;
- hwif->atapi_output_bytes = &cris_atapi_output_bytes;
- hwif->dma_host_set = &cris_dma_host_set;
- hwif->ide_dma_end = &cris_dma_end;
- hwif->dma_setup = &cris_dma_setup;
- hwif->dma_exec_cmd = &cris_dma_exec_cmd;
- hwif->ide_dma_test_irq = &cris_dma_test_irq;
- hwif->dma_start = &cris_dma_start;
- hwif->OUTB = &cris_ide_outb;
- hwif->OUTW = &cris_ide_outw;
- hwif->OUTBSYNC = &cris_ide_outbsync;
- hwif->INB = &cris_ide_inb;
- hwif->INW = &cris_ide_inw;
- hwif->cbl = ATA_CBL_PATA40;
-
- idx[h] = hwif->index;
- }
-
- /* Reset pulse */
- cris_ide_reset(0);
- udelay(25);
- cris_ide_reset(1);
-
- cris_ide_init();
-
- cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
- cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
- cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
-
- ide_device_add(idx, &cris_port_info);
-
- return 0;
-}
-
-static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-static void
-cris_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
- D(printk("atapi_input_bytes, buffer 0x%x, count %d\n",
- buffer, bytecount));
-
- if(bytecount & 1) {
- printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
- bytecount++; /* to round off */
- }
-
- /* setup DMA and start transfer */
-
- cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1);
- cris_ide_start_dma(drive, &mydescr, 1, TYPE_PIO, bytecount);
-
- /* wait for completion */
- LED_DISK_READ(1);
- cris_ide_wait_dma(1);
- LED_DISK_READ(0);
-}
-
-static void
-cris_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
- D(printk("atapi_output_bytes, buffer 0x%x, count %d\n",
- buffer, bytecount));
-
- if(bytecount & 1) {
- printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
- bytecount++;
- }
-
- cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1);
- cris_ide_start_dma(drive, &mydescr, 0, TYPE_PIO, bytecount);
-
- /* wait for completion */
-
- LED_DISK_WRITE(1);
- LED_DISK_READ(1);
- cris_ide_wait_dma(0);
- LED_DISK_WRITE(0);
-}
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-static void
-cris_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- cris_atapi_input_bytes(drive, buffer, wcount << 2);
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-static void
-cris_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
- cris_atapi_output_bytes(drive, buffer, wcount << 2);
-}
-
-/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
-static cris_dma_descr_type ata_descrs[MAX_DMA_DESCRS] __attribute__ ((__aligned__(16)));
-static unsigned int ata_tot_size;
-
-/*
- * cris_ide_build_dmatable() prepares a dma request.
- * Returns 0 if all went okay, returns 1 otherwise.
- */
-static int cris_ide_build_dmatable (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct scatterlist* sg;
- struct request *rq = drive->hwif->hwgroup->rq;
- unsigned long size, addr;
- unsigned int count = 0;
- int i = 0;
-
- sg = hwif->sg_table;
-
- ata_tot_size = 0;
-
- ide_map_sg(drive, rq);
- i = hwif->sg_nents;
-
- while(i) {
- /*
- * Determine addr and size of next buffer area. We assume that
- * individual virtual buffers are always composed linearly in
- * physical memory. For example, we assume that any 8kB buffer
- * is always composed of two adjacent physical 4kB pages rather
- * than two possibly non-adjacent physical 4kB pages.
- */
- /* group sequential buffers into one large buffer */
- addr = sg_phys(sg);
- size = sg_dma_len(sg);
- while (--i) {
- sg = sg_next(sg);
- if ((addr + size) != sg_phys(sg))
- break;
- size += sg_dma_len(sg);
- }
-
- /* did we run out of descriptors? */
-
- if(count >= MAX_DMA_DESCRS) {
- printk("%s: too few DMA descriptors\n", drive->name);
- return 1;
- }
-
- /* however, this case is more difficult - rw_trf_cnt cannot be more
- than 65536 words per transfer, so in that case we need to either
- 1) use a DMA interrupt to re-trigger rw_trf_cnt and continue with
- the descriptors, or
- 2) simply do the request here, and get dma_intr to only ide_end_request on
- those blocks that were actually set-up for transfer.
- */
-
- if(ata_tot_size + size > 131072) {
- printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
- return 1;
- }
-
- /* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. Since we
- don't handle size > 131072 only one split is necessary */
-
- if(size > MAX_DESCR_SIZE) {
- cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, MAX_DESCR_SIZE, 0);
- count++;
- ata_tot_size += MAX_DESCR_SIZE;
- size -= MAX_DESCR_SIZE;
- addr += MAX_DESCR_SIZE;
- }
-
- cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, size,i ? 0 : 1);
- count++;
- ata_tot_size += size;
- }
-
- if (count) {
- /* return and say all is ok */
- return 0;
- }
-
- printk("%s: empty DMA table?\n", drive->name);
- return 1; /* let the PIO routines handle this weirdness */
-}
-
-/*
- * cris_dma_intr() is the handler for disk read/write DMA interrupts
- */
-static ide_startstop_t cris_dma_intr (ide_drive_t *drive)
-{
- LED_DISK_READ(0);
- LED_DISK_WRITE(0);
-
- return ide_dma_intr(drive);
-}
-
-/*
- * Functions below initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA. All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * cris_dma_start afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- */
-
-static int cris_dma_end(ide_drive_t *drive)
-{
- drive->waiting_for_dma = 0;
- return 0;
-}
-
-static int cris_dma_setup(ide_drive_t *drive)
-{
- struct request *rq = drive->hwif->hwgroup->rq;
-
- cris_ide_initialize_dma(!rq_data_dir(rq));
- if (cris_ide_build_dmatable (drive)) {
- ide_map_sg(drive, rq);
- return 1;
- }
-
- drive->waiting_for_dma = 1;
- return 0;
-}
-
-static void cris_dma_exec_cmd(ide_drive_t *drive, u8 command)
-{
- ide_execute_command(drive, command, &cris_dma_intr, WAIT_CMD, NULL);
-}
-
-static void cris_dma_start(ide_drive_t *drive)
-{
- struct request *rq = drive->hwif->hwgroup->rq;
- int writing = rq_data_dir(rq);
- int type = TYPE_DMA;
-
- if (drive->current_speed >= XFER_UDMA_0)
- type = TYPE_UDMA;
-
- cris_ide_start_dma(drive, &ata_descrs[0], writing ? 0 : 1, type, ata_tot_size);
-
- if (writing) {
- LED_DISK_WRITE(1);
- } else {
- LED_DISK_READ(1);
- }
-}
-
-module_init(init_e100_ide);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 4108ec4ffa7f..ecf53bb0d2aa 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -42,6 +42,91 @@ static u16 mm_inw(unsigned long a)
return r;
}
+static void h8300_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ ide_set_irq(drive, 1);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA)
+ mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ outb((tf->device & HIHI) | drive->select.all,
+ io_ports->device_addr);
+}
+
+static void h8300_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data = mm_inw(io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ outb(drive->ctl & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ outb(drive->ctl | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = inb(io_ports->lbah_addr);
+ }
+}
+
static void mm_outsw(unsigned long addr, void *buf, u32 len)
{
unsigned short *bp = (unsigned short *)buf;
@@ -56,6 +141,18 @@ static void mm_insw(unsigned long addr, void *buf, u32 len)
*bp = bswap(*(volatile u16 *)addr);
}
+static void h8300_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void h8300_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
#define H8300_IDE_GAP (2)
static inline void hw_setup(hw_regs_t *hw)
@@ -63,9 +160,9 @@ static inline void hw_setup(hw_regs_t *hw)
int i;
memset(hw, 0, sizeof(hw_regs_t));
- for (i = 0; i <= IDE_STATUS_OFFSET; i++)
- hw->io_ports[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
- hw->io_ports[IDE_CONTROL_OFFSET] = CONFIG_H8300_IDE_ALT;
+ for (i = 0; i <= 7; i++)
+ hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
+ hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT;
hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
hw->chipset = ide_generic;
}
@@ -74,13 +171,11 @@ static inline void hwif_setup(ide_hwif_t *hwif)
{
default_hwif_iops(hwif);
- hwif->mmio = 1;
- hwif->OUTW = mm_outw;
- hwif->OUTSW = mm_outsw;
- hwif->INW = mm_inw;
- hwif->INSW = mm_insw;
- hwif->OUTSL = NULL;
- hwif->INSL = NULL;
+ hwif->tf_load = h8300_tf_load;
+ hwif->tf_read = h8300_tf_read;
+
+ hwif->input_data = h8300_input_data;
+ hwif->output_data = h8300_output_data;
}
static int __init h8300_ide_init(void)
@@ -99,8 +194,7 @@ static int __init h8300_ide_init(void)
hw_setup(&hw);
- /* register if */
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif == NULL) {
printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
return -ENOENT;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 0f6fb6b72dd9..9d3601fa5680 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -55,14 +55,22 @@ struct ide_acpi_hwif_link {
/* note: adds function name and KERN_DEBUG */
#ifdef DEBUGGING
#define DEBPRINT(fmt, args...) \
- printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+ printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
#else
#define DEBPRINT(fmt, args...) do {} while (0)
#endif /* DEBUGGING */
-extern int ide_noacpi;
-extern int ide_noacpitfs;
-extern int ide_noacpionboot;
+int ide_noacpi;
+module_param_named(noacpi, ide_noacpi, bool, 0);
+MODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
+
+int ide_acpigtf;
+module_param_named(acpigtf, ide_acpigtf, bool, 0);
+MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
+
+int ide_acpionboot;
+module_param_named(acpionboot, ide_acpionboot, bool, 0);
+MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
static bool ide_noacpi_psx;
static int no_acpi_psx(const struct dmi_system_id *id)
@@ -309,7 +317,7 @@ static int do_drive_get_GTF(ide_drive_t *drive,
if (ACPI_FAILURE(status)) {
printk(KERN_DEBUG
"%s: Run _GTF error: status = 0x%x\n",
- __FUNCTION__, status);
+ __func__, status);
goto out;
}
@@ -335,7 +343,7 @@ static int do_drive_get_GTF(ide_drive_t *drive,
out_obj->buffer.length % REGS_PER_GTF) {
printk(KERN_ERR
"%s: unexpected GTF length (%d) or addr (0x%p)\n",
- __FUNCTION__, out_obj->buffer.length,
+ __func__, out_obj->buffer.length,
out_obj->buffer.pointer);
err = -ENOENT;
kfree(output.pointer);
@@ -376,7 +384,7 @@ static int taskfile_load_raw(ide_drive_t *drive,
memcpy(&args.tf_array[7], &gtf->tfa, 7);
args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
- if (ide_noacpitfs) {
+ if (!ide_acpigtf) {
DEBPRINT("_GTF execution disabled\n");
return err;
}
@@ -384,7 +392,7 @@ static int taskfile_load_raw(ide_drive_t *drive,
err = ide_no_data_taskfile(drive, &args);
if (err)
printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
- __FUNCTION__, err);
+ __func__, err);
return err;
}
@@ -422,7 +430,7 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
if (gtf_length % REGS_PER_GTF) {
printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
- __FUNCTION__, gtf_length);
+ __func__, gtf_length);
goto out;
}
@@ -547,7 +555,7 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
printk(KERN_ERR
"%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
"addr (0x%p)\n",
- __FUNCTION__, out_obj->buffer.length,
+ __func__, out_obj->buffer.length,
sizeof(struct GTM_buffer), out_obj->buffer.pointer);
return;
}
@@ -721,7 +729,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
drive->name, err);
}
- if (ide_noacpionboot) {
+ if (!ide_acpionboot) {
DEBPRINT("ACPI methods disabled on boot\n");
return;
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index fe5aefbf8339..fe9df38f62cc 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -13,8 +13,8 @@
*
* Suggestions are welcome. Patches that work are more welcome though. ;-)
* For those wishing to work on this driver, please be sure you download
- * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
- * (SFF-8020i rev 2.6) standards. These documents can be obtained by
+ * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
+ * (SFF-8020i rev 2.6) standards. These documents can be obtained by
* anonymous ftp from:
* ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
* ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
@@ -39,19 +39,20 @@
#include <linux/mutex.h>
#include <linux/bcd.h>
-#include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */
+/* For SCSI -> ATAPI command conversion */
+#include <scsi/scsi.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/io.h>
#include <asm/byteorder.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include "ide-cd.h"
static DEFINE_MUTEX(idecd_ref_mutex);
-#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
+#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
#define ide_cd_g(disk) \
container_of((disk)->private_data, struct cdrom_info, driver)
@@ -77,19 +78,17 @@ static void ide_cd_put(struct cdrom_info *cd)
mutex_unlock(&idecd_ref_mutex);
}
-/****************************************************************************
+/*
* Generic packet command support and error handling routines.
*/
-/* Mark that we've seen a media change, and invalidate our internal
- buffers. */
-static void cdrom_saw_media_change (ide_drive_t *drive)
+/* Mark that we've seen a media change and invalidate our internal buffers. */
+static void cdrom_saw_media_change(ide_drive_t *drive)
{
struct cdrom_info *cd = drive->driver_data;
cd->cd_flags |= IDE_CD_FLAG_MEDIA_CHANGED;
cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
- cd->nsectors_buffered = 0;
}
static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
@@ -101,66 +100,65 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
return 0;
switch (sense->sense_key) {
- case NO_SENSE: case RECOVERED_ERROR:
- break;
- case NOT_READY:
- /*
- * don't care about tray state messages for
- * e.g. capacity commands or in-progress or
- * becoming ready
- */
- if (sense->asc == 0x3a || sense->asc == 0x04)
- break;
- log = 1;
- break;
- case ILLEGAL_REQUEST:
- /*
- * don't log START_STOP unit with LoEj set, since
- * we cannot reliably check if drive can auto-close
- */
- if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
- break;
- log = 1;
- break;
- case UNIT_ATTENTION:
- /*
- * Make good and sure we've seen this potential media
- * change. Some drives (i.e. Creative) fail to present
- * the correct sense key in the error register.
- */
- cdrom_saw_media_change(drive);
+ case NO_SENSE:
+ case RECOVERED_ERROR:
+ break;
+ case NOT_READY:
+ /*
+ * don't care about tray state messages for e.g. capacity
+ * commands or in-progress or becoming ready
+ */
+ if (sense->asc == 0x3a || sense->asc == 0x04)
break;
- default:
- log = 1;
+ log = 1;
+ break;
+ case ILLEGAL_REQUEST:
+ /*
+ * don't log START_STOP unit with LoEj set, since we cannot
+ * reliably check if drive can auto-close
+ */
+ if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
break;
+ log = 1;
+ break;
+ case UNIT_ATTENTION:
+ /*
+ * Make good and sure we've seen this potential media change.
+ * Some drives (i.e. Creative) fail to present the correct sense
+ * key in the error register.
+ */
+ cdrom_saw_media_change(drive);
+ break;
+ default:
+ log = 1;
+ break;
}
return log;
}
-static
-void cdrom_analyze_sense_data(ide_drive_t *drive,
+static void cdrom_analyze_sense_data(ide_drive_t *drive,
struct request *failed_command,
struct request_sense *sense)
{
unsigned long sector;
unsigned long bio_sectors;
- unsigned long valid;
struct cdrom_info *info = drive->driver_data;
if (!cdrom_log_sense(drive, failed_command, sense))
return;
/*
- * If a read toc is executed for a CD-R or CD-RW medium where
- * the first toc has not been recorded yet, it will fail with
- * 05/24/00 (which is a confusing error)
+ * If a read toc is executed for a CD-R or CD-RW medium where the first
+ * toc has not been recorded yet, it will fail with 05/24/00 (which is a
+ * confusing error)
*/
if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
if (sense->sense_key == 0x05 && sense->asc == 0x24)
return;
- if (sense->error_code == 0x70) { /* Current Error */
- switch(sense->sense_key) {
+ /* current error */
+ if (sense->error_code == 0x70) {
+ switch (sense->sense_key) {
case MEDIUM_ERROR:
case VOLUME_OVERFLOW:
case ILLEGAL_REQUEST:
@@ -174,29 +172,23 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
(sense->information[2] << 8) |
(sense->information[3]);
- bio_sectors = bio_sectors(failed_command->bio);
- if (bio_sectors < 4)
- bio_sectors = 4;
if (drive->queue->hardsect_size == 2048)
- sector <<= 2; /* Device sector size is 2K */
- sector &= ~(bio_sectors -1);
- valid = (sector - failed_command->sector) << 9;
+ /* device sector size is 2K */
+ sector <<= 2;
+
+ bio_sectors = max(bio_sectors(failed_command->bio), 4U);
+ sector &= ~(bio_sectors - 1);
- if (valid < 0)
- valid = 0;
if (sector < get_capacity(info->disk) &&
- drive->probed_capacity - sector < 4 * 75) {
+ drive->probed_capacity - sector < 4 * 75)
set_capacity(info->disk, sector);
- }
- }
- }
+ }
+ }
ide_cd_log_error(drive->name, failed_command, sense);
}
-/*
- * Initialize a ide-cd packet command request
- */
+/* Initialize a ide-cd packet command request */
void ide_cd_init_rq(ide_drive_t *drive, struct request *rq)
{
struct cdrom_info *cd = drive->driver_data;
@@ -220,7 +212,8 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
rq->data = sense;
rq->cmd[0] = GPCMD_REQUEST_SENSE;
- rq->cmd[4] = rq->data_len = 18;
+ rq->cmd[4] = 18;
+ rq->data_len = 18;
rq->cmd_type = REQ_TYPE_SENSE;
@@ -230,7 +223,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
-static void cdrom_end_request (ide_drive_t *drive, int uptodate)
+static void cdrom_end_request(ide_drive_t *drive, int uptodate)
{
struct request *rq = HWGROUP(drive)->rq;
int nsectors = rq->hard_cur_sectors;
@@ -252,7 +245,7 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
}
cdrom_analyze_sense_data(drive, failed, sense);
/*
- * now end failed request
+ * now end the failed request
*/
if (blk_fs_request(failed)) {
if (ide_end_dequeued_request(drive, failed, 0,
@@ -280,21 +273,24 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
ide_end_request(drive, uptodate, nsectors);
}
-static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
{
- if (stat & 0x80)
+ if (st & 0x80)
return;
- ide_dump_status(drive, msg, stat);
+ ide_dump_status(drive, msg, st);
}
-/* Returns 0 if the request should be continued.
- Returns 1 if the request was ended. */
+/*
+ * Returns:
+ * 0: if the request should be continued.
+ * 1: if the request was ended.
+ */
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
{
struct request *rq = HWGROUP(drive)->rq;
int stat, err, sense_key;
-
- /* Check for errors. */
+
+ /* check for errors */
stat = ide_read_status(drive);
if (stat_ret)
@@ -303,20 +299,22 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
if (OK_STAT(stat, good_stat, BAD_R_STAT))
return 0;
- /* Get the IDE error register. */
+ /* get the IDE error register */
err = ide_read_error(drive);
sense_key = err >> 4;
if (rq == NULL) {
- printk("%s: missing rq in cdrom_decode_status\n", drive->name);
+ printk(KERN_ERR "%s: missing rq in %s\n",
+ drive->name, __func__);
return 1;
}
if (blk_sense_request(rq)) {
- /* We got an error trying to get sense info
- from the drive (probably while trying
- to recover from a former error). Just give up. */
-
+ /*
+ * We got an error trying to get sense info from the drive
+ * (probably while trying to recover from a former error).
+ * Just give up.
+ */
rq->cmd_flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
ide_error(drive, "request sense failure", stat);
@@ -332,28 +330,27 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
if (blk_pc_request(rq) && !rq->errors)
rq->errors = SAM_STAT_CHECK_CONDITION;
- /* Check for tray open. */
+ /* check for tray open */
if (sense_key == NOT_READY) {
- cdrom_saw_media_change (drive);
+ cdrom_saw_media_change(drive);
} else if (sense_key == UNIT_ATTENTION) {
- /* Check for media change. */
- cdrom_saw_media_change (drive);
- /*printk("%s: media changed\n",drive->name);*/
+ /* check for media change */
+ cdrom_saw_media_change(drive);
return 0;
- } else if ((sense_key == ILLEGAL_REQUEST) &&
- (rq->cmd[0] == GPCMD_START_STOP_UNIT)) {
- /*
- * Don't print error message for this condition--
- * SFF8090i indicates that 5/24/00 is the correct
- * response to a request to close the tray if the
- * drive doesn't have that capability.
- * cdrom_log_sense() knows this!
- */
+ } else if (sense_key == ILLEGAL_REQUEST &&
+ rq->cmd[0] == GPCMD_START_STOP_UNIT) {
+ /*
+ * Don't print error message for this condition--
+ * SFF8090i indicates that 5/24/00 is the correct
+ * response to a request to close the tray if the
+ * drive doesn't have that capability.
+ * cdrom_log_sense() knows this!
+ */
} else if (!(rq->cmd_flags & REQ_QUIET)) {
- /* Otherwise, print an error. */
+ /* otherwise, print an error */
ide_dump_status(drive, "packet command error", stat);
}
-
+
rq->cmd_flags |= REQ_FAILED;
/*
@@ -366,27 +363,30 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
} else if (blk_fs_request(rq)) {
int do_end_request = 0;
- /* Handle errors from READ and WRITE requests. */
+ /* handle errors from READ and WRITE requests */
if (blk_noretry_request(rq))
do_end_request = 1;
if (sense_key == NOT_READY) {
- /* Tray open. */
+ /* tray open */
if (rq_data_dir(rq) == READ) {
- cdrom_saw_media_change (drive);
+ cdrom_saw_media_change(drive);
- /* Fail the request. */
- printk ("%s: tray open\n", drive->name);
+ /* fail the request */
+ printk(KERN_ERR "%s: tray open\n", drive->name);
do_end_request = 1;
} else {
struct cdrom_info *info = drive->driver_data;
- /* allow the drive 5 seconds to recover, some
+ /*
+ * Allow the drive 5 seconds to recover, some
* devices will return this error while flushing
- * data from cache */
+ * data from cache.
+ */
if (!rq->errors)
- info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY;
+ info->write_timeout = jiffies +
+ ATAPI_WAIT_WRITE_BUSY;
rq->errors = 1;
if (time_after(jiffies, info->write_timeout))
do_end_request = 1;
@@ -394,59 +394,68 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
unsigned long flags;
/*
- * take a breather relying on the
- * unplug timer to kick us again
+ * take a breather relying on the unplug
+ * timer to kick us again
*/
spin_lock_irqsave(&ide_lock, flags);
blk_plug_device(drive->queue);
- spin_unlock_irqrestore(&ide_lock,flags);
+ spin_unlock_irqrestore(&ide_lock,
+ flags);
return 1;
}
}
} else if (sense_key == UNIT_ATTENTION) {
- /* Media change. */
- cdrom_saw_media_change (drive);
+ /* media change */
+ cdrom_saw_media_change(drive);
- /* Arrange to retry the request.
- But be sure to give up if we've retried
- too many times. */
+ /*
+ * Arrange to retry the request but be sure to give up
+ * if we've retried too many times.
+ */
if (++rq->errors > ERROR_MAX)
do_end_request = 1;
} else if (sense_key == ILLEGAL_REQUEST ||
sense_key == DATA_PROTECT) {
- /* No point in retrying after an illegal
- request or data protect error.*/
- ide_dump_status_no_sense (drive, "command error", stat);
+ /*
+ * No point in retrying after an illegal request or data
+ * protect error.
+ */
+ ide_dump_status_no_sense(drive, "command error", stat);
do_end_request = 1;
} else if (sense_key == MEDIUM_ERROR) {
- /* No point in re-trying a zillion times on a bad
- * sector... If we got here the error is not correctable */
- ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
+ /*
+ * No point in re-trying a zillion times on a bad
+ * sector. If we got here the error is not correctable.
+ */
+ ide_dump_status_no_sense(drive,
+ "media error (bad sector)",
+ stat);
do_end_request = 1;
} else if (sense_key == BLANK_CHECK) {
- /* Disk appears blank ?? */
- ide_dump_status_no_sense (drive, "media error (blank)", stat);
+ /* disk appears blank ?? */
+ ide_dump_status_no_sense(drive, "media error (blank)",
+ stat);
do_end_request = 1;
} else if ((err & ~ABRT_ERR) != 0) {
- /* Go to the default handler
- for other errors. */
+ /* go to the default handler for other errors */
ide_error(drive, "cdrom_decode_status", stat);
return 1;
} else if ((++rq->errors > ERROR_MAX)) {
- /* We've racked up too many retries. Abort. */
+ /* we've racked up too many retries, abort */
do_end_request = 1;
}
- /* End a request through request sense analysis when we have
- sense data. We need this in order to perform end of media
- processing */
-
+ /*
+ * End a request through request sense analysis when we have
+ * sense data. We need this in order to perform end of media
+ * processing.
+ */
if (do_end_request)
goto end_request;
/*
- * If we got a CHECK_CONDITION status,
- * queue a request sense command.
+ * If we got a CHECK_CONDITION status, queue
+ * a request sense command.
*/
if (stat & ERR_STAT)
cdrom_queue_request_sense(drive, NULL, NULL);
@@ -455,7 +464,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
cdrom_end_request(drive, 0);
}
- /* Retry, or handle the next request. */
+ /* retry, or handle the next request */
return 1;
end_request:
@@ -480,35 +489,37 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
unsigned long wait = 0;
/*
- * Some commands are *slow* and normally take a long time to
- * complete. Usually we can use the ATAPI "disconnect" to bypass
- * this, but not all commands/drives support that. Let
- * ide_timer_expiry keep polling us for these.
+ * Some commands are *slow* and normally take a long time to complete.
+ * Usually we can use the ATAPI "disconnect" to bypass this, but not all
+ * commands/drives support that. Let ide_timer_expiry keep polling us
+ * for these.
*/
switch (rq->cmd[0]) {
- case GPCMD_BLANK:
- case GPCMD_FORMAT_UNIT:
- case GPCMD_RESERVE_RZONE_TRACK:
- case GPCMD_CLOSE_TRACK:
- case GPCMD_FLUSH_CACHE:
- wait = ATAPI_WAIT_PC;
- break;
- default:
- if (!(rq->cmd_flags & REQ_QUIET))
- printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]);
- wait = 0;
- break;
+ case GPCMD_BLANK:
+ case GPCMD_FORMAT_UNIT:
+ case GPCMD_RESERVE_RZONE_TRACK:
+ case GPCMD_CLOSE_TRACK:
+ case GPCMD_FLUSH_CACHE:
+ wait = ATAPI_WAIT_PC;
+ break;
+ default:
+ if (!(rq->cmd_flags & REQ_QUIET))
+ printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n",
+ rq->cmd[0]);
+ wait = 0;
+ break;
}
return wait;
}
-/* Set up the device registers for transferring a packet command on DEV,
- expecting to later transfer XFERLEN bytes. HANDLER is the routine
- which actually transfers the command to the drive. If this is a
- drq_interrupt device, this routine will arrange for HANDLER to be
- called when the interrupt from the drive arrives. Otherwise, HANDLER
- will be called immediately after the drive is prepared for the transfer. */
-
+/*
+ * Set up the device registers for transferring a packet command on DEV,
+ * expecting to later transfer XFERLEN bytes. HANDLER is the routine
+ * which actually transfers the command to the drive. If this is a
+ * drq_interrupt device, this routine will arrange for HANDLER to be
+ * called when the interrupt from the drive arrives. Otherwise, HANDLER
+ * will be called immediately after the drive is prepared for the transfer.
+ */
static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
int xferlen,
ide_handler_t *handler)
@@ -517,15 +528,15 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
struct cdrom_info *info = drive->driver_data;
ide_hwif_t *hwif = drive->hwif;
- /* Wait for the controller to be idle. */
+ /* wait for the controller to be idle */
if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
return startstop;
/* FIXME: for Virtual DMA we must check harder */
if (info->dma)
- info->dma = !hwif->dma_setup(drive);
+ info->dma = !hwif->dma_ops->dma_setup(drive);
- /* Set up the controller registers. */
+ /* set up the controller registers */
ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
@@ -535,29 +546,24 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
drive->waiting_for_dma = 0;
/* packet command */
- ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
+ ide_execute_command(drive, WIN_PACKETCMD, handler,
+ ATAPI_WAIT_PC, cdrom_timer_expiry);
return ide_started;
} else {
- unsigned long flags;
-
- /* packet command */
- spin_lock_irqsave(&ide_lock, flags);
- hwif->OUTBSYNC(drive, WIN_PACKETCMD,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
- ndelay(400);
- spin_unlock_irqrestore(&ide_lock, flags);
+ ide_execute_pkt_cmd(drive);
return (*handler) (drive);
}
}
-/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
- The device registers must have already been prepared
- by cdrom_start_packet_command.
- HANDLER is the interrupt handler to call when the command completes
- or there's data ready. */
+/*
+ * Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. The device
+ * registers must have already been prepared by cdrom_start_packet_command.
+ * HANDLER is the interrupt handler to call when the command completes or
+ * there's data ready.
+ */
#define ATAPI_MIN_CDB_BYTES 12
-static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
struct request *rq,
ide_handler_t *handler)
{
@@ -567,24 +573,26 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
ide_startstop_t startstop;
if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
- /* Here we should have been called after receiving an interrupt
- from the device. DRQ should how be set. */
+ /*
+ * Here we should have been called after receiving an interrupt
+ * from the device. DRQ should how be set.
+ */
- /* Check for errors. */
+ /* check for errors */
if (cdrom_decode_status(drive, DRQ_STAT, NULL))
return ide_stopped;
- /* Ok, next interrupt will be DMA interrupt. */
+ /* ok, next interrupt will be DMA interrupt */
if (info->dma)
drive->waiting_for_dma = 1;
} else {
- /* Otherwise, we must wait for DRQ to get set. */
+ /* otherwise, we must wait for DRQ to get set */
if (ide_wait_stat(&startstop, drive, DRQ_STAT,
BUSY_STAT, WAIT_READY))
return startstop;
}
- /* Arm the interrupt handler. */
+ /* arm the interrupt handler */
ide_set_handler(drive, handler, rq->timeout, cdrom_timer_expiry);
/* ATAPI commands get padded out to 12 bytes minimum */
@@ -592,25 +600,24 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
if (cmd_len < ATAPI_MIN_CDB_BYTES)
cmd_len = ATAPI_MIN_CDB_BYTES;
- /* Send the command to the device. */
- HWIF(drive)->atapi_output_bytes(drive, rq->cmd, cmd_len);
+ /* send the command to the device */
+ hwif->output_data(drive, NULL, rq->cmd, cmd_len);
- /* Start the DMA if need be */
+ /* start the DMA if need be */
if (info->dma)
- hwif->dma_start(drive);
+ hwif->dma_ops->dma_start(drive);
return ide_started;
}
-/****************************************************************************
+/*
* Block read functions.
*/
-
static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len)
{
while (len > 0) {
int dum = 0;
- xf(drive, &dum, sizeof(dum));
+ xf(drive, NULL, &dum, sizeof(dum));
len -= sizeof(dum);
}
}
@@ -620,53 +627,12 @@ static void ide_cd_drain_data(ide_drive_t *drive, int nsects)
while (nsects > 0) {
static char dum[SECTOR_SIZE];
- drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum));
+ drive->hwif->input_data(drive, NULL, dum, sizeof(dum));
nsects--;
}
}
/*
- * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
- * buffer. Once the first sector is added, any subsequent sectors are
- * assumed to be continuous (until the buffer is cleared). For the first
- * sector added, SECTOR is its sector number. (SECTOR is then ignored until
- * the buffer is cleared.)
- */
-static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
- int sectors_to_transfer)
-{
- struct cdrom_info *info = drive->driver_data;
-
- /* Number of sectors to read into the buffer. */
- int sectors_to_buffer = min_t(int, sectors_to_transfer,
- (SECTOR_BUFFER_SIZE >> SECTOR_BITS) -
- info->nsectors_buffered);
-
- char *dest;
-
- /* If we couldn't get a buffer, don't try to buffer anything... */
- if (info->buffer == NULL)
- sectors_to_buffer = 0;
-
- /* If this is the first sector in the buffer, remember its number. */
- if (info->nsectors_buffered == 0)
- info->sector_buffered = sector;
-
- /* Read the data into the buffer. */
- dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
- while (sectors_to_buffer > 0) {
- HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE);
- --sectors_to_buffer;
- --sectors_to_transfer;
- ++info->nsectors_buffered;
- dest += SECTOR_SIZE;
- }
-
- /* Throw away any remaining data. */
- ide_cd_drain_data(drive, sectors_to_transfer);
-}
-
-/*
* Check the contents of the interrupt reason register from the cdrom
* and attempt to recover if there are problems. Returns 0 if everything's
* ok; nonzero if the request has been terminated.
@@ -684,22 +650,23 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
ide_hwif_t *hwif = drive->hwif;
xfer_func_t *xf;
- /* Whoops... */
+ /* whoops... */
printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
- drive->name, __FUNCTION__);
+ drive->name, __func__);
- xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes;
+ xf = rw ? hwif->output_data : hwif->input_data;
ide_cd_pad_transfer(drive, xf, len);
} else if (rw == 0 && ireason == 1) {
- /* Some drives (ASUS) seem to tell us that status
- * info is available. just get it and ignore.
+ /*
+ * Some drives (ASUS) seem to tell us that status info is
+ * available. Just get it and ignore.
*/
(void)ide_read_status(drive);
return 0;
} else {
- /* Drive wants a command packet, or invalid ireason... */
+ /* drive wants a command packet, or invalid ireason... */
printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
- drive->name, __FUNCTION__, ireason);
+ drive->name, __func__, ireason);
}
if (rq->cmd_type == REQ_TYPE_ATA_PC)
@@ -721,7 +688,7 @@ static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
return 0;
printk(KERN_ERR "%s: %s: Bad transfer size %d\n",
- drive->name, __FUNCTION__, len);
+ drive->name, __func__, len);
if (cd->cd_flags & IDE_CD_FLAG_LIMIT_NFRAMES)
printk(KERN_ERR " This drive is not supported by "
@@ -734,72 +701,13 @@ static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
return 1;
}
-/*
- * Try to satisfy some of the current read request from our cached data.
- * Returns nonzero if the request has been completed, zero otherwise.
- */
-static int cdrom_read_from_buffer (ide_drive_t *drive)
-{
- struct cdrom_info *info = drive->driver_data;
- struct request *rq = HWGROUP(drive)->rq;
- unsigned short sectors_per_frame;
-
- sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
-
- /* Can't do anything if there's no buffer. */
- if (info->buffer == NULL) return 0;
-
- /* Loop while this request needs data and the next block is present
- in our cache. */
- while (rq->nr_sectors > 0 &&
- rq->sector >= info->sector_buffered &&
- rq->sector < info->sector_buffered + info->nsectors_buffered) {
- if (rq->current_nr_sectors == 0)
- cdrom_end_request(drive, 1);
-
- memcpy (rq->buffer,
- info->buffer +
- (rq->sector - info->sector_buffered) * SECTOR_SIZE,
- SECTOR_SIZE);
- rq->buffer += SECTOR_SIZE;
- --rq->current_nr_sectors;
- --rq->nr_sectors;
- ++rq->sector;
- }
-
- /* If we've satisfied the current request,
- terminate it successfully. */
- if (rq->nr_sectors == 0) {
- cdrom_end_request(drive, 1);
- return -1;
- }
-
- /* Move on to the next buffer if needed. */
- if (rq->current_nr_sectors == 0)
- cdrom_end_request(drive, 1);
-
- /* If this condition does not hold, then the kluge i use to
- represent the number of sectors to skip at the start of a transfer
- will fail. I think that this will never happen, but let's be
- paranoid and check. */
- if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) &&
- (rq->sector & (sectors_per_frame - 1))) {
- printk(KERN_ERR "%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
- drive->name, (long)rq->sector);
- cdrom_end_request(drive, 0);
- return -1;
- }
-
- return 0;
-}
-
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
/*
- * Routine to send a read/write packet command to the drive.
- * This is usually called directly from cdrom_start_{read,write}().
- * However, for drq_interrupt devices, it is called from an interrupt
- * when the drive is ready to accept the command.
+ * Routine to send a read/write packet command to the drive. This is usually
+ * called directly from cdrom_start_{read,write}(). However, for drq_interrupt
+ * devices, it is called from an interrupt when the drive is ready to accept
+ * the command.
*/
static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
{
@@ -821,11 +729,11 @@ static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
* is larger than the buffer size.
*/
if (nskip > 0) {
- /* Sanity check... */
+ /* sanity check... */
if (rq->current_nr_sectors !=
bio_cur_sectors(rq->bio)) {
printk(KERN_ERR "%s: %s: buffer botch (%u)\n",
- drive->name, __FUNCTION__,
+ drive->name, __func__,
rq->current_nr_sectors);
cdrom_end_request(drive, 0);
return ide_stopped;
@@ -838,10 +746,10 @@ static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
/* the immediate bit */
rq->cmd[1] = 1 << 3;
#endif
- /* Set up the command */
+ /* set up the command */
rq->timeout = ATAPI_WAIT_PC;
- /* Send the command to the drive and return. */
+ /* send the command to the drive and return */
return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
}
@@ -849,7 +757,7 @@ static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
#define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */
#define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */
-static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_seek_intr(ide_drive_t *drive)
{
struct cdrom_info *info = drive->driver_data;
int stat;
@@ -861,19 +769,13 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
info->cd_flags |= IDE_CD_FLAG_SEEKING;
if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
- if (--retry == 0) {
- /*
- * this condition is far too common, to bother
- * users about it
- */
- /* printk("%s: disabled DSC seek overlap\n", drive->name);*/
+ if (--retry == 0)
drive->dsc_overlap = 0;
- }
}
return ide_stopped;
}
-static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
sector_t frame = rq->sector;
@@ -888,36 +790,40 @@ static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
}
-static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
+static ide_startstop_t cdrom_start_seek(ide_drive_t *drive, unsigned int block)
{
struct cdrom_info *info = drive->driver_data;
info->dma = 0;
info->start_seek = jiffies;
- return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
+ return cdrom_start_packet_command(drive, 0,
+ cdrom_start_seek_continuation);
}
-/* Fix up a possibly partially-processed request so that we can
- start it over entirely, or even put it back on the request queue. */
-static void restore_request (struct request *rq)
+/*
+ * Fix up a possibly partially-processed request so that we can start it over
+ * entirely, or even put it back on the request queue.
+ */
+static void restore_request(struct request *rq)
{
if (rq->buffer != bio_data(rq->bio)) {
- sector_t n = (rq->buffer - (char *) bio_data(rq->bio)) / SECTOR_SIZE;
+ sector_t n =
+ (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
rq->buffer = bio_data(rq->bio);
rq->nr_sectors += n;
rq->sector -= n;
}
- rq->hard_cur_sectors = rq->current_nr_sectors = bio_cur_sectors(rq->bio);
+ rq->current_nr_sectors = bio_cur_sectors(rq->bio);
+ rq->hard_cur_sectors = rq->current_nr_sectors;
rq->hard_nr_sectors = rq->nr_sectors;
rq->hard_sector = rq->sector;
rq->q->prep_rq_fn(rq->q, rq);
}
-/****************************************************************************
- * Execute all other packet commands.
+/*
+ * All other packet commands.
*/
-
static void ide_cd_request_sense_fixup(struct request *rq)
{
/*
@@ -941,7 +847,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq)
if (rq->sense == NULL)
rq->sense = &sense;
- /* Start of retry loop. */
+ /* start of retry loop */
do {
int error;
unsigned long time = jiffies;
@@ -950,41 +856,45 @@ int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq)
error = ide_do_drive_cmd(drive, rq, ide_wait);
time = jiffies - time;
- /* FIXME: we should probably abort/retry or something
- * in case of failure */
+ /*
+ * FIXME: we should probably abort/retry or something in case of
+ * failure.
+ */
if (rq->cmd_flags & REQ_FAILED) {
- /* The request failed. Retry if it was due to a unit
- attention status
- (usually means media was changed). */
+ /*
+ * The request failed. Retry if it was due to a unit
+ * attention status (usually means media was changed).
+ */
struct request_sense *reqbuf = rq->sense;
if (reqbuf->sense_key == UNIT_ATTENTION)
cdrom_saw_media_change(drive);
else if (reqbuf->sense_key == NOT_READY &&
reqbuf->asc == 4 && reqbuf->ascq != 4) {
- /* The drive is in the process of loading
- a disk. Retry, but wait a little to give
- the drive time to complete the load. */
+ /*
+ * The drive is in the process of loading
+ * a disk. Retry, but wait a little to give
+ * the drive time to complete the load.
+ */
ssleep(2);
} else {
- /* Otherwise, don't retry. */
+ /* otherwise, don't retry */
retries = 0;
}
--retries;
}
- /* End of retry loop. */
+ /* end of retry loop */
} while ((rq->cmd_flags & REQ_FAILED) && retries >= 0);
- /* Return an error if the command failed. */
+ /* return an error if the command failed */
return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
}
/*
- * Called from blk_end_request_callback() after the data of the request
- * is completed and before the request is completed.
- * By returning value '1', blk_end_request_callback() returns immediately
- * without completing the request.
+ * Called from blk_end_request_callback() after the data of the request is
+ * completed and before the request itself is completed. By returning value '1',
+ * blk_end_request_callback() returns immediately without completing it.
*/
static int cdrom_newpc_intr_dummy_cb(struct request *rq)
{
@@ -1003,11 +913,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
unsigned int timeout;
u8 lowcyl, highcyl;
- /* Check for errors. */
+ /* check for errors */
dma = info->dma;
if (dma) {
info->dma = 0;
- dma_error = HWIF(drive)->ide_dma_end(drive);
+ dma_error = hwif->dma_ops->dma_end(drive);
if (dma_error) {
printk(KERN_ERR "%s: DMA %s error\n", drive->name,
write ? "write" : "read");
@@ -1018,9 +928,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (cdrom_decode_status(drive, 0, &stat))
return ide_stopped;
- /*
- * using dma, transfer is complete now
- */
+ /* using dma, transfer is complete now */
if (dma) {
if (dma_error)
return ide_error(drive, "dma error", stat);
@@ -1031,12 +939,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
goto end_request;
}
- /*
- * ok we fall to pio :/
- */
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]) & 0x3;
- lowcyl = hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]);
- highcyl = hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]);
+ /* ok we fall to pio :/ */
+ ireason = hwif->INB(hwif->io_ports.nsect_addr) & 0x3;
+ lowcyl = hwif->INB(hwif->io_ports.lbam_addr);
+ highcyl = hwif->INB(hwif->io_ports.lbah_addr);
len = lowcyl + (256 * highcyl);
@@ -1044,9 +950,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (thislen > len)
thislen = len;
- /*
- * If DRQ is clear, the command has completed.
- */
+ /* If DRQ is clear, the command has completed. */
if ((stat & DRQ_STAT) == 0) {
if (blk_fs_request(rq)) {
/*
@@ -1057,7 +961,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (rq->current_nr_sectors > 0) {
printk(KERN_ERR "%s: %s: data underrun "
"(%d blocks)\n",
- drive->name, __FUNCTION__,
+ drive->name, __func__,
rq->current_nr_sectors);
if (!write)
rq->cmd_flags |= REQ_FAILED;
@@ -1067,15 +971,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
return ide_stopped;
} else if (!blk_pc_request(rq)) {
ide_cd_request_sense_fixup(rq);
- /* Complain if we still have data left to transfer. */
+ /* complain if we still have data left to transfer */
uptodate = rq->data_len ? 0 : 1;
}
goto end_request;
}
- /*
- * check which way to transfer data
- */
+ /* check which way to transfer data */
if (ide_cd_check_ireason(drive, rq, len, ireason, write))
return ide_stopped;
@@ -1105,22 +1007,18 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (ireason == 0) {
write = 1;
- xferfunc = HWIF(drive)->atapi_output_bytes;
+ xferfunc = hwif->output_data;
} else {
write = 0;
- xferfunc = HWIF(drive)->atapi_input_bytes;
+ xferfunc = hwif->input_data;
}
- /*
- * transfer data
- */
+ /* transfer data */
while (thislen > 0) {
u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
int blen = rq->data_len;
- /*
- * bio backed?
- */
+ /* bio backed? */
if (rq->bio) {
if (blk_fs_request(rq)) {
ptr = rq->buffer;
@@ -1134,11 +1032,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (!ptr) {
if (blk_fs_request(rq) && !write)
/*
- * If the buffers are full, cache the rest
- * of the data in our internal buffer.
+ * If the buffers are full, pipe the rest into
+ * oblivion.
*/
- cdrom_buffer_sectors(drive, rq->sector,
- thislen >> 9);
+ ide_cd_drain_data(drive, thislen >> 9);
else {
printk(KERN_ERR "%s: confused, missing data\n",
drive->name);
@@ -1152,7 +1049,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (blen > thislen)
blen = thislen;
- xferfunc(drive, ptr, blen);
+ xferfunc(drive, NULL, ptr, blen);
thislen -= blen;
len -= blen;
@@ -1184,9 +1081,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
rq->sense_len += blen;
}
- /*
- * pad, if necessary
- */
+ /* pad, if necessary */
if (!blk_fs_request(rq) && len > 0)
ide_cd_pad_transfer(drive, xferfunc, len);
@@ -1230,9 +1125,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
queue_hardsect_size(drive->queue) >> SECTOR_BITS;
if (write) {
- /*
- * disk has become write protected
- */
+ /* disk has become write protected */
if (cd->disk->policy) {
cdrom_end_request(drive, 0);
return ide_stopped;
@@ -1243,15 +1136,9 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
* weirdness which might be present in the request packet.
*/
restore_request(rq);
-
- /* Satisfy whatever we can of this request from our cache. */
- if (cdrom_read_from_buffer(drive))
- return ide_stopped;
}
- /*
- * use DMA, if possible / writes *must* be hardware frame aligned
- */
+ /* use DMA, if possible / writes *must* be hardware frame aligned */
if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
(rq->sector & (sectors_per_frame - 1))) {
if (write) {
@@ -1262,13 +1149,10 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
} else
cd->dma = drive->using_dma;
- /* Clear the local sector buffer. */
- cd->nsectors_buffered = 0;
-
if (write)
cd->devinfo.media_written = 1;
- /* Start sending the read/write request to the drive. */
+ /* start sending the read/write request to the drive */
return cdrom_start_packet_command(drive, 32768, cdrom_start_rw_cont);
}
@@ -1293,12 +1177,11 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
info->dma = 0;
- /*
- * sg request
- */
+ /* sg request */
if (rq->bio) {
int mask = drive->queue->dma_alignment;
- unsigned long addr = (unsigned long) page_address(bio_page(rq->bio));
+ unsigned long addr =
+ (unsigned long)page_address(bio_page(rq->bio));
info->dma = drive->using_dma;
@@ -1312,15 +1195,16 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
info->dma = 0;
}
- /* Start sending the command to the drive. */
- return cdrom_start_packet_command(drive, rq->data_len, cdrom_do_newpc_cont);
+ /* start sending the command to the drive */
+ return cdrom_start_packet_command(drive, rq->data_len,
+ cdrom_do_newpc_cont);
}
-/****************************************************************************
+/*
* cdrom driver request routine.
*/
-static ide_startstop_t
-ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
+static ide_startstop_t ide_do_rw_cdrom(ide_drive_t *drive, struct request *rq,
+ sector_t block)
{
ide_startstop_t action;
struct cdrom_info *info = drive->driver_data;
@@ -1332,16 +1216,21 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
if ((stat & SEEK_STAT) != SEEK_STAT) {
if (elapsed < IDECD_SEEK_TIMEOUT) {
- ide_stall_queue(drive, IDECD_SEEK_TIMER);
+ ide_stall_queue(drive,
+ IDECD_SEEK_TIMER);
return ide_stopped;
}
- printk (KERN_ERR "%s: DSC timeout\n", drive->name);
+ printk(KERN_ERR "%s: DSC timeout\n",
+ drive->name);
}
info->cd_flags &= ~IDE_CD_FLAG_SEEKING;
}
- if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
+ if (rq_data_dir(rq) == READ &&
+ IDE_LARGE_SEEK(info->last_block, block,
+ IDECD_SEEK_THRESHOLD) &&
+ drive->dsc_overlap)
action = cdrom_start_seek(drive, block);
- } else
+ else
action = cdrom_start_rw(drive, rq);
info->last_block = block;
return action;
@@ -1349,9 +1238,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
rq->cmd_type == REQ_TYPE_ATA_PC) {
return cdrom_do_block_pc(drive, rq);
} else if (blk_special_request(rq)) {
- /*
- * right now this can only be a reset...
- */
+ /* right now this can only be a reset... */
cdrom_end_request(drive, 1);
return ide_stopped;
}
@@ -1363,18 +1250,16 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
-/****************************************************************************
+/*
* Ioctl handling.
*
- * Routines which queue packet commands take as a final argument a pointer
- * to a request_sense struct. If execution of the command results
- * in an error with a CHECK CONDITION status, this structure will be filled
- * with the results of the subsequent request sense command. The pointer
- * can also be NULL, in which case no sense information is returned.
+ * Routines which queue packet commands take as a final argument a pointer to a
+ * request_sense struct. If execution of the command results in an error with a
+ * CHECK CONDITION status, this structure will be filled with the results of the
+ * subsequent request sense command. The pointer can also be NULL, in which case
+ * no sense information is returned.
*/
-
-static
-void msf_from_bcd (struct atapi_msf *msf)
+static void msf_from_bcd(struct atapi_msf *msf)
{
msf->minute = BCD2BIN(msf->minute);
msf->second = BCD2BIN(msf->second);
@@ -1394,8 +1279,8 @@ int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
req.cmd_flags |= REQ_QUIET;
/*
- * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
- * switch CDs instead of supporting the LOAD_UNLOAD opcode.
+ * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs
+ * instead of supporting the LOAD_UNLOAD opcode.
*/
req.cmd[7] = cdi->sanyo_slot % 3;
@@ -1471,36 +1356,39 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
unsigned long sectors_per_frame = SECTORS_PER_FRAME;
if (toc == NULL) {
- /* Try to allocate space. */
+ /* try to allocate space */
toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
if (toc == NULL) {
- printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name);
+ printk(KERN_ERR "%s: No cdrom TOC buffer!\n",
+ drive->name);
return -ENOMEM;
}
info->toc = toc;
}
- /* Check to see if the existing data is still valid.
- If it is, just return. */
+ /*
+ * Check to see if the existing data is still valid. If it is,
+ * just return.
+ */
(void) cdrom_check_status(drive, sense);
if (info->cd_flags & IDE_CD_FLAG_TOC_VALID)
return 0;
- /* Try to get the total cdrom capacity and sector size. */
+ /* try to get the total cdrom capacity and sector size */
stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame,
sense);
if (stat)
toc->capacity = 0x1fffff;
set_capacity(info->disk, toc->capacity * sectors_per_frame);
- /* Save a private copy of te TOC capacity for error handling */
+ /* save a private copy of the TOC capacity for error handling */
drive->probed_capacity = toc->capacity * sectors_per_frame;
blk_queue_hardsect_size(drive->queue,
sectors_per_frame << SECTOR_BITS);
- /* First read just the header, so we know how long the TOC is. */
+ /* first read just the header, so we know how long the TOC is */
stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
sizeof(struct atapi_toc_header), sense);
if (stat)
@@ -1517,7 +1405,7 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
if (ntracks > MAX_TRACKS)
ntracks = MAX_TRACKS;
- /* Now read the whole schmeer. */
+ /* now read the whole schmeer */
stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
(char *)&toc->hdr,
sizeof(struct atapi_toc_header) +
@@ -1525,15 +1413,18 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
sizeof(struct atapi_toc_entry), sense);
if (stat && toc->hdr.first_track > 1) {
- /* Cds with CDI tracks only don't have any TOC entries,
- despite of this the returned values are
- first_track == last_track = number of CDI tracks + 1,
- so that this case is indistinguishable from the same
- layout plus an additional audio track.
- If we get an error for the regular case, we assume
- a CDI without additional audio tracks. In this case
- the readable TOC is empty (CDI tracks are not included)
- and only holds the Leadout entry. Heiko Eißfeldt */
+ /*
+ * Cds with CDI tracks only don't have any TOC entries, despite
+ * of this the returned values are
+ * first_track == last_track = number of CDI tracks + 1,
+ * so that this case is indistinguishable from the same layout
+ * plus an additional audio track. If we get an error for the
+ * regular case, we assume a CDI without additional audio
+ * tracks. In this case the readable TOC is empty (CDI tracks
+ * are not included) and only holds the Leadout entry.
+ *
+ * Heiko Eißfeldt.
+ */
ntracks = 0;
stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
(char *)&toc->hdr,
@@ -1569,14 +1460,13 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
toc->ent[i].track = BCD2BIN(toc->ent[i].track);
msf_from_bcd(&toc->ent[i].addr.msf);
}
- toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
- toc->ent[i].addr.msf.second,
- toc->ent[i].addr.msf.frame);
+ toc->ent[i].addr.lba = msf_to_lba(toc->ent[i].addr.msf.minute,
+ toc->ent[i].addr.msf.second,
+ toc->ent[i].addr.msf.frame);
}
- /* Read the multisession information. */
if (toc->hdr.first_track != CDROM_LEADOUT) {
- /* Read the multisession information. */
+ /* read the multisession information */
stat = cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
sizeof(ms_tmp), sense);
if (stat)
@@ -1584,26 +1474,27 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
} else {
- ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT;
+ ms_tmp.hdr.last_track = CDROM_LEADOUT;
+ ms_tmp.hdr.first_track = ms_tmp.hdr.last_track;
toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
}
if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) {
- /* Re-read multisession information using MSF format */
+ /* re-read multisession information using MSF format */
stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
sizeof(ms_tmp), sense);
if (stat)
return stat;
- msf_from_bcd (&ms_tmp.ent.addr.msf);
+ msf_from_bcd(&ms_tmp.ent.addr.msf);
toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
- ms_tmp.ent.addr.msf.second,
+ ms_tmp.ent.addr.msf.second,
ms_tmp.ent.addr.msf.frame);
}
toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
- /* Now try to get the total cdrom capacity. */
+ /* now try to get the total cdrom capacity */
stat = cdrom_get_last_written(cdi, &last_written);
if (!stat && (last_written > toc->capacity)) {
toc->capacity = last_written;
@@ -1628,7 +1519,8 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
- do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ do {
+ /* we seem to get stat=0x01,err=0x00 the first time (??) */
stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
if (!stat)
break;
@@ -1679,7 +1571,7 @@ static struct cdrom_device_ops ide_cdrom_dops = {
.generic_packet = ide_cdrom_packet,
};
-static int ide_cdrom_register (ide_drive_t *drive, int nslots)
+static int ide_cdrom_register(ide_drive_t *drive, int nslots)
{
struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *devinfo = &info->devinfo;
@@ -1697,8 +1589,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
return register_cdrom(devinfo);
}
-static
-int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
{
struct cdrom_info *cd = drive->driver_data;
struct cdrom_device_info *cdi = &cd->devinfo;
@@ -1712,7 +1603,8 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
if (drive->media == ide_optical) {
cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
- printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name);
+ printk(KERN_ERR "%s: ATAPI magneto-optical drive\n",
+ drive->name);
return nslots;
}
@@ -1723,11 +1615,10 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
}
/*
- * we have to cheat a little here. the packet will eventually
- * be queued with ide_cdrom_packet(), which extracts the
- * drive from cdi->handle. Since this device hasn't been
- * registered with the Uniform layer yet, it can't do this.
- * Same goes for cdi->ops.
+ * We have to cheat a little here. the packet will eventually be queued
+ * with ide_cdrom_packet(), which extracts the drive from cdi->handle.
+ * Since this device hasn't been registered with the Uniform layer yet,
+ * it can't do this. Same goes for cdi->ops.
*/
cdi->handle = drive;
cdi->ops = &ide_cdrom_dops;
@@ -1796,18 +1687,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
return nslots;
}
-#ifdef CONFIG_IDE_PROC_FS
-static void ide_cdrom_add_settings(ide_drive_t *drive)
-{
- ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
-}
-#else
-static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
-#endif
-
-/*
- * standard prep_rq_fn that builds 10 byte cmds
- */
+/* standard prep_rq_fn that builds 10 byte cmds */
static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
{
int hard_sect = queue_hardsect_size(q);
@@ -1846,9 +1726,7 @@ static int ide_cdrom_prep_pc(struct request *rq)
{
u8 *c = rq->cmd;
- /*
- * Transform 6-byte read/write commands to the 10-byte version
- */
+ /* transform 6-byte read/write commands to the 10-byte version */
if (c[0] == READ_6 || c[0] == WRITE_6) {
c[8] = c[4];
c[5] = c[3];
@@ -1870,7 +1748,7 @@ static int ide_cdrom_prep_pc(struct request *rq)
rq->errors = ILLEGAL_REQUEST;
return BLKPREP_KILL;
}
-
+
return BLKPREP_OK;
}
@@ -1890,6 +1768,41 @@ struct cd_list_entry {
unsigned int cd_flags;
};
+#ifdef CONFIG_IDE_PROC_FS
+static sector_t ide_cdrom_capacity(ide_drive_t *drive)
+{
+ unsigned long capacity, sectors_per_frame;
+
+ if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame, NULL))
+ return 0;
+
+ return capacity * sectors_per_frame;
+}
+
+static int proc_idecd_read_capacity(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ ide_drive_t *drive = data;
+ int len;
+
+ len = sprintf(page, "%llu\n", (long long)ide_cdrom_capacity(drive));
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static ide_proc_entry_t idecd_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+static void ide_cdrom_add_settings(ide_drive_t *drive)
+{
+ ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
+ &drive->dsc_overlap, NULL);
+}
+#else
+static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
+#endif
+
static const struct cd_list_entry ide_cd_quirks_list[] = {
/* Limit transfer size per interrupt. */
{ "SAMSUNG CD-ROM SCR-2430", NULL, IDE_CD_FLAG_LIMIT_NFRAMES },
@@ -1947,8 +1860,7 @@ static unsigned int ide_cd_flags(struct hd_driveid *id)
return 0;
}
-static
-int ide_cdrom_setup (ide_drive_t *drive)
+static int ide_cdrom_setup(ide_drive_t *drive)
{
struct cdrom_info *cd = drive->driver_data;
struct cdrom_device_info *cdi = &cd->devinfo;
@@ -1977,21 +1889,19 @@ int ide_cdrom_setup (ide_drive_t *drive)
id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
cd->cd_flags |= IDE_CD_FLAG_TOCTRACKS_AS_BCD;
else if (cd->cd_flags & IDE_CD_FLAG_SANYO_3CD)
- cdi->sanyo_slot = 3; /* 3 => use CD in slot 0 */
+ /* 3 => use CD in slot 0 */
+ cdi->sanyo_slot = 3;
- nslots = ide_cdrom_probe_capabilities (drive);
+ nslots = ide_cdrom_probe_capabilities(drive);
- /*
- * set correct block size
- */
+ /* set correct block size */
blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
- if (drive->autotune == IDE_TUNE_DEFAULT ||
- drive->autotune == IDE_TUNE_AUTO)
- drive->dsc_overlap = (drive->next != drive);
+ drive->dsc_overlap = (drive->next != drive);
if (ide_cdrom_register(drive, nslots)) {
- printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
+ printk(KERN_ERR "%s: %s failed to register device with the"
+ " cdrom driver.\n", drive->name, __func__);
cd->devinfo.handle = NULL;
return 1;
}
@@ -1999,19 +1909,6 @@ int ide_cdrom_setup (ide_drive_t *drive)
return 0;
}
-#ifdef CONFIG_IDE_PROC_FS
-static
-sector_t ide_cdrom_capacity (ide_drive_t *drive)
-{
- unsigned long capacity, sectors_per_frame;
-
- if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame, NULL))
- return 0;
-
- return capacity * sectors_per_frame;
-}
-#endif
-
static void ide_cd_remove(ide_drive_t *drive)
{
struct cdrom_info *info = drive->driver_data;
@@ -2030,7 +1927,6 @@ static void ide_cd_release(struct kref *kref)
ide_drive_t *drive = info->drive;
struct gendisk *g = info->disk;
- kfree(info->buffer);
kfree(info->toc);
if (devinfo->handle == drive)
unregister_cdrom(devinfo);
@@ -2044,23 +1940,6 @@ static void ide_cd_release(struct kref *kref)
static int ide_cd_probe(ide_drive_t *);
-#ifdef CONFIG_IDE_PROC_FS
-static int proc_idecd_read_capacity
- (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- ide_drive_t *drive = data;
- int len;
-
- len = sprintf(page,"%llu\n", (long long)ide_cdrom_capacity(drive));
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static ide_proc_entry_t idecd_proc[] = {
- { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
- { NULL, 0, NULL, NULL }
-};
-#endif
-
static ide_driver_t ide_cdrom_driver = {
.gen_driver = {
.owner = THIS_MODULE,
@@ -2081,20 +1960,17 @@ static ide_driver_t ide_cdrom_driver = {
#endif
};
-static int idecd_open(struct inode * inode, struct file * file)
+static int idecd_open(struct inode *inode, struct file *file)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct cdrom_info *info;
int rc = -ENOMEM;
- if (!(info = ide_cd_get(disk)))
+ info = ide_cd_get(disk);
+ if (!info)
return -ENXIO;
- if (!info->buffer)
- info->buffer = kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL|__GFP_REPEAT);
-
- if (info->buffer)
- rc = cdrom_open(&info->devinfo, inode, file);
+ rc = cdrom_open(&info->devinfo, inode, file);
if (rc < 0)
ide_cd_put(info);
@@ -2102,12 +1978,12 @@ static int idecd_open(struct inode * inode, struct file * file)
return rc;
}
-static int idecd_release(struct inode * inode, struct file * file)
+static int idecd_release(struct inode *inode, struct file *file)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct cdrom_info *info = ide_cd_g(disk);
- cdrom_release (&info->devinfo, file);
+ cdrom_release(&info->devinfo, file);
ide_cd_put(info);
@@ -2139,7 +2015,7 @@ static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
struct packet_command cgc;
char buffer[16];
int stat;
- char spindown;
+ char spindown;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
@@ -2148,12 +2024,12 @@ static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
return stat;
spindown = buffer[11] & 0x0f;
- if (copy_to_user((void __user *)arg, &spindown, sizeof (char)))
+ if (copy_to_user((void __user *)arg, &spindown, sizeof(char)))
return -EFAULT;
return 0;
}
-static int idecd_ioctl (struct inode *inode, struct file *file,
+static int idecd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
@@ -2161,13 +2037,13 @@ static int idecd_ioctl (struct inode *inode, struct file *file,
int err;
switch (cmd) {
- case CDROMSETSPINDOWN:
+ case CDROMSETSPINDOWN:
return idecd_set_spindown(&info->devinfo, arg);
- case CDROMGETSPINDOWN:
+ case CDROMGETSPINDOWN:
return idecd_get_spindown(&info->devinfo, arg);
default:
break;
- }
+ }
err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
if (err == -EINVAL)
@@ -2193,16 +2069,16 @@ static int idecd_revalidate_disk(struct gendisk *disk)
}
static struct block_device_operations idecd_ops = {
- .owner = THIS_MODULE,
- .open = idecd_open,
- .release = idecd_release,
- .ioctl = idecd_ioctl,
- .media_changed = idecd_media_changed,
- .revalidate_disk= idecd_revalidate_disk
+ .owner = THIS_MODULE,
+ .open = idecd_open,
+ .release = idecd_release,
+ .ioctl = idecd_ioctl,
+ .media_changed = idecd_media_changed,
+ .revalidate_disk = idecd_revalidate_disk
};
-/* options */
-static char *ignore = NULL;
+/* module options */
+static char *ignore;
module_param(ignore, charp, 0400);
MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
@@ -2222,17 +2098,20 @@ static int ide_cd_probe(ide_drive_t *drive)
/* skip drives that we were told to ignore */
if (ignore != NULL) {
if (strstr(ignore, drive->name)) {
- printk(KERN_INFO "ide-cd: ignoring drive %s\n", drive->name);
+ printk(KERN_INFO "ide-cd: ignoring drive %s\n",
+ drive->name);
goto failed;
}
}
if (drive->scsi) {
- printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+ printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi "
+ "emulation.\n", drive->name);
goto failed;
}
info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
if (info == NULL) {
- printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
+ printk(KERN_ERR "%s: Can't allocate a cdrom structure\n",
+ drive->name);
goto failed;
}
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 22e3751a681e..a58801c4484d 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -119,10 +119,6 @@ struct cdrom_info {
struct atapi_toc *toc;
- unsigned long sector_buffered;
- unsigned long nsectors_buffered;
- unsigned char *buffer;
-
/* The result of the last successful request sense command
on this device. */
struct request_sense sense_data;
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 39501d130256..8e08d083fce9 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -16,8 +16,6 @@
#define IDEDISK_VERSION "1.18"
-//#define DEBUG
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -88,7 +86,7 @@ static void ide_disk_put(struct ide_disk_obj *idkp)
*
* It is called only once for each drive.
*/
-static int lba_capacity_is_ok (struct hd_driveid *id)
+static int lba_capacity_is_ok(struct hd_driveid *id)
{
unsigned long lba_sects, chs_sects, head, tail;
@@ -176,7 +174,8 @@ static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
* __ide_do_rw_disk() issues READ and WRITE commands to a disk,
* using LBA if supported, or CHS otherwise, to address sectors.
*/
-static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block)
+static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ sector_t block)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned int dma = drive->using_dma;
@@ -228,7 +227,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
tf->device = (block >> 8) & 0xf;
}
} else {
- unsigned int sect,head,cyl,track;
+ unsigned int sect, head, cyl, track;
+
track = (int)block / drive->sect;
sect = (int)block % drive->sect + 1;
head = track % drive->head;
@@ -271,7 +271,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
* 1073741822 == 549756 MB or 48bit addressing fake drive
*/
-static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)
+static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ sector_t block)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -452,7 +453,7 @@ static void idedisk_check_hpa(ide_drive_t *drive)
* in above order (i.e., if value of higher priority is available,
* reset will be ignored).
*/
-static void init_idedisk_capacity (ide_drive_t *drive)
+static void init_idedisk_capacity(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
/*
@@ -479,7 +480,7 @@ static void init_idedisk_capacity (ide_drive_t *drive)
}
}
-static sector_t idedisk_capacity (ide_drive_t *drive)
+static sector_t idedisk_capacity(ide_drive_t *drive)
{
return drive->capacity64 - drive->sect0;
}
@@ -524,10 +525,11 @@ static int proc_idedisk_read_cache
int len;
if (drive->id_read)
- len = sprintf(out,"%i\n", drive->id->buf_size / 2);
+ len = sprintf(out, "%i\n", drive->id->buf_size / 2);
else
- len = sprintf(out,"(none)\n");
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ len = sprintf(out, "(none)\n");
+
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static int proc_idedisk_read_capacity
@@ -536,54 +538,52 @@ static int proc_idedisk_read_capacity
ide_drive_t*drive = (ide_drive_t *)data;
int len;
- len = sprintf(page,"%llu\n", (long long)idedisk_capacity(drive));
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ len = sprintf(page, "%llu\n", (long long)idedisk_capacity(drive));
+
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
-static int proc_idedisk_read_smart_thresholds
- (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int proc_idedisk_read_smart(char *page, char **start, off_t off,
+ int count, int *eof, void *data, u8 sub_cmd)
{
ide_drive_t *drive = (ide_drive_t *)data;
int len = 0, i = 0;
- if (get_smart_data(drive, page, SMART_READ_THRESHOLDS) == 0) {
+ if (get_smart_data(drive, page, sub_cmd) == 0) {
unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
do {
- out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+ out += sprintf(out, "%04x%c", le16_to_cpu(*val),
+ (++i & 7) ? ' ' : '\n');
val += 1;
} while (i < (SECTOR_WORDS * 2));
len = out - page;
}
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
-static int proc_idedisk_read_smart_values
+static int proc_idedisk_read_sv
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_drive_t *drive = (ide_drive_t *)data;
- int len = 0, i = 0;
+ return proc_idedisk_read_smart(page, start, off, count, eof, data,
+ SMART_READ_VALUES);
+}
- if (get_smart_data(drive, page, SMART_READ_VALUES) == 0) {
- unsigned short *val = (unsigned short *) page;
- char *out = ((char *)val) + (SECTOR_WORDS * 4);
- page = out;
- do {
- out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
- val += 1;
- } while (i < (SECTOR_WORDS * 2));
- len = out - page;
- }
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+static int proc_idedisk_read_st
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return proc_idedisk_read_smart(page, start, off, count, eof, data,
+ SMART_READ_THRESHOLDS);
}
static ide_proc_entry_t idedisk_proc[] = {
- { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
- { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
- { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
- { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_smart_values, NULL },
- { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL },
+ { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
+ { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
+ { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
+ { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
+ { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
{ NULL, 0, NULL, NULL }
};
#endif /* CONFIG_IDE_PROC_FS */
@@ -625,12 +625,13 @@ static int set_multcount(ide_drive_t *drive, int arg)
if (drive->special.b.set_multmode)
return -EBUSY;
- ide_init_drive_cmd (&rq);
+ ide_init_drive_cmd(&rq);
rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+ (void)ide_do_drive_cmd(drive, &rq, ide_wait);
+
return (drive->mult_count == arg) ? 0 : -EIO;
}
@@ -706,7 +707,7 @@ static int write_cache(ide_drive_t *drive, int arg)
return err;
}
-static int do_idedisk_flushcache (ide_drive_t *drive)
+static int do_idedisk_flushcache(ide_drive_t *drive)
{
ide_task_t args;
@@ -719,7 +720,7 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
return ide_no_data_taskfile(drive, &args);
}
-static int set_acoustic (ide_drive_t *drive, int arg)
+static int set_acoustic(ide_drive_t *drive, int arg)
{
ide_task_t args;
@@ -753,7 +754,7 @@ static int set_lba_addressing(ide_drive_t *drive, int arg)
return 0;
if (!idedisk_supports_lba48(drive->id))
- return -EIO;
+ return -EIO;
drive->addressing = arg;
return 0;
}
@@ -763,23 +764,35 @@ static void idedisk_add_settings(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL);
- ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
- ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
- ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1, &drive->addressing, set_lba_addressing);
- ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0, id->max_multsect, 1, 1, &drive->mult_count, set_multcount);
- ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr);
- ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL);
- ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->wcache, write_cache);
- ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic);
- ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL);
- ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
+ &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
+ &drive->bios_head, NULL);
+ ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1,
+ &drive->bios_sect, NULL);
+ ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1,
+ &drive->addressing, set_lba_addressing);
+ ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0,
+ id->max_multsect, 1, 1, &drive->mult_count,
+ set_multcount);
+ ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
+ &drive->nowerr, set_nowerr);
+ ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1,
+ &drive->lun, NULL);
+ ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1,
+ &drive->wcache, write_cache);
+ ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1,
+ &drive->acoustic, set_acoustic);
+ ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1,
+ &drive->failures, NULL);
+ ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535,
+ 1, 1, &drive->max_failures, NULL);
}
#else
static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
#endif
-static void idedisk_setup (ide_drive_t *drive)
+static void idedisk_setup(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
@@ -792,11 +805,10 @@ static void idedisk_setup (ide_drive_t *drive)
if (drive->removable) {
/*
- * Removable disks (eg. SYQUEST); ignore 'WD' drives
+ * Removable disks (eg. SYQUEST); ignore 'WD' drives
*/
- if (id->model[0] != 'W' || id->model[1] != 'D') {
+ if (id->model[0] != 'W' || id->model[1] != 'D')
drive->doorlocking = 1;
- }
}
(void)set_lba_addressing(drive, 1);
@@ -810,10 +822,11 @@ static void idedisk_setup (ide_drive_t *drive)
blk_queue_max_sectors(drive->queue, max_s);
}
- printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2);
+ printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
+ drive->queue->max_sectors / 2);
/* calculate drive capacity, and select LBA if possible */
- init_idedisk_capacity (drive);
+ init_idedisk_capacity(drive);
/* limit drive capacity to 137GB if LBA48 cannot be used */
if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {
@@ -826,9 +839,9 @@ static void idedisk_setup (ide_drive_t *drive)
if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) {
if (drive->capacity64 > 1ULL << 28) {
- printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will"
- " be used for accessing sectors > %u\n",
- drive->name, 1 << 28);
+ printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
+ " will be used for accessing sectors "
+ "> %u\n", drive->name, 1 << 28);
} else
drive->addressing = 0;
}
@@ -837,7 +850,8 @@ static void idedisk_setup (ide_drive_t *drive)
* if possible, give fdisk access to more of the drive,
* by correcting bios_cyls:
*/
- capacity = idedisk_capacity (drive);
+ capacity = idedisk_capacity(drive);
+
if (!drive->forced_geom) {
if (idedisk_supports_lba48(drive->id)) {
@@ -993,7 +1007,8 @@ static int idedisk_open(struct inode *inode, struct file *filp)
struct ide_disk_obj *idkp;
ide_drive_t *drive;
- if (!(idkp = ide_disk_get(disk)))
+ idkp = ide_disk_get(disk);
+ if (idkp == NULL)
return -ENXIO;
drive = idkp->drive;
@@ -1115,13 +1130,13 @@ static int idedisk_revalidate_disk(struct gendisk *disk)
}
static struct block_device_operations idedisk_ops = {
- .owner = THIS_MODULE,
- .open = idedisk_open,
- .release = idedisk_release,
- .ioctl = idedisk_ioctl,
- .getgeo = idedisk_getgeo,
- .media_changed = idedisk_media_changed,
- .revalidate_disk= idedisk_revalidate_disk
+ .owner = THIS_MODULE,
+ .open = idedisk_open,
+ .release = idedisk_release,
+ .ioctl = idedisk_ioctl,
+ .getgeo = idedisk_getgeo,
+ .media_changed = idedisk_media_changed,
+ .revalidate_disk = idedisk_revalidate_disk
};
MODULE_DESCRIPTION("ATA DISK Driver");
@@ -1184,7 +1199,7 @@ failed:
return -ENODEV;
}
-static void __exit idedisk_exit (void)
+static void __exit idedisk_exit(void)
{
driver_unregister(&idedisk_driver.gen_driver);
}
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index d61e5788d310..653b1ade13d3 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -102,7 +102,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
{
u8 stat = 0, dma_stat = 0;
- dma_stat = HWIF(drive)->ide_dma_end(drive);
+ dma_stat = drive->hwif->dma_ops->dma_end(drive);
stat = ide_read_status(drive);
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
@@ -394,7 +394,7 @@ void ide_dma_off_quietly(ide_drive_t *drive)
drive->using_dma = 0;
ide_toggle_bounce(drive, 0);
- drive->hwif->dma_host_set(drive, 0);
+ drive->hwif->dma_ops->dma_host_set(drive, 0);
}
EXPORT_SYMBOL(ide_dma_off_quietly);
@@ -427,7 +427,7 @@ void ide_dma_on(ide_drive_t *drive)
drive->using_dma = 1;
ide_toggle_bounce(drive, 1);
- drive->hwif->dma_host_set(drive, 1);
+ drive->hwif->dma_ops->dma_host_set(drive, 1);
}
#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
@@ -464,9 +464,10 @@ int ide_dma_setup(ide_drive_t *drive)
/* PRD table */
if (hwif->mmio)
- writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable);
+ writel(hwif->dmatable_dma,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
else
- outl(hwif->dmatable_dma, hwif->dma_prdtable);
+ outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
/* specify r/w */
hwif->OUTB(reading, hwif->dma_command);
@@ -482,11 +483,12 @@ int ide_dma_setup(ide_drive_t *drive)
EXPORT_SYMBOL_GPL(ide_dma_setup);
-static void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
{
/* issue cmd to drive */
ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
}
+EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
void ide_dma_start(ide_drive_t *drive)
{
@@ -532,7 +534,7 @@ int __ide_dma_end (ide_drive_t *drive)
EXPORT_SYMBOL(__ide_dma_end);
/* returns 1 if dma irq issued, 0 otherwise */
-static int __ide_dma_test_irq(ide_drive_t *drive)
+int ide_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u8 dma_stat = hwif->INB(hwif->dma_status);
@@ -542,9 +544,10 @@ static int __ide_dma_test_irq(ide_drive_t *drive)
return 1;
if (!drive->waiting_for_dma)
printk(KERN_WARNING "%s: (%s) called while not waiting\n",
- drive->name, __FUNCTION__);
+ drive->name, __func__);
return 0;
}
+EXPORT_SYMBOL_GPL(ide_dma_test_irq);
#else
static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
@@ -574,6 +577,7 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
unsigned int mask = 0;
switch(base) {
@@ -581,8 +585,8 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
if ((id->field_valid & 4) == 0)
break;
- if (hwif->udma_filter)
- mask = hwif->udma_filter(drive);
+ if (port_ops && port_ops->udma_filter)
+ mask = port_ops->udma_filter(drive);
else
mask = hwif->ultra_mask;
mask &= id->dma_ultra;
@@ -598,8 +602,8 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
case XFER_MW_DMA_0:
if ((id->field_valid & 2) == 0)
break;
- if (hwif->mdma_filter)
- mask = hwif->mdma_filter(drive);
+ if (port_ops && port_ops->mdma_filter)
+ mask = port_ops->mdma_filter(drive);
else
mask = hwif->mwdma_mask;
mask &= id->dma_mword;
@@ -703,17 +707,8 @@ static int ide_tune_dma(ide_drive_t *drive)
speed = ide_max_dma_mode(drive);
- if (!speed) {
- /* is this really correct/needed? */
- if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
- ide_dma_good_drive(drive))
- return 1;
- else
- return 0;
- }
-
- if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
- return 1;
+ if (!speed)
+ return 0;
if (ide_set_dma_mode(drive, speed))
return 0;
@@ -810,15 +805,15 @@ void ide_dma_timeout (ide_drive_t *drive)
printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
- if (hwif->ide_dma_test_irq(drive))
+ if (hwif->dma_ops->dma_test_irq(drive))
return;
- hwif->ide_dma_end(drive);
+ hwif->dma_ops->dma_end(drive);
}
EXPORT_SYMBOL(ide_dma_timeout);
-static void ide_release_dma_engine(ide_hwif_t *hwif)
+void ide_release_dma_engine(ide_hwif_t *hwif)
{
if (hwif->dmatable_cpu) {
struct pci_dev *pdev = to_pci_dev(hwif->dev);
@@ -829,28 +824,7 @@ static void ide_release_dma_engine(ide_hwif_t *hwif)
}
}
-static int ide_release_iomio_dma(ide_hwif_t *hwif)
-{
- release_region(hwif->dma_base, 8);
- if (hwif->extra_ports)
- release_region(hwif->extra_base, hwif->extra_ports);
- return 1;
-}
-
-/*
- * Needed for allowing full modular support of ide-driver
- */
-int ide_release_dma(ide_hwif_t *hwif)
-{
- ide_release_dma_engine(hwif);
-
- if (hwif->mmio)
- return 1;
- else
- return ide_release_iomio_dma(hwif);
-}
-
-static int ide_allocate_dma_engine(ide_hwif_t *hwif)
+int ide_allocate_dma_engine(ide_hwif_t *hwif)
{
struct pci_dev *pdev = to_pci_dev(hwif->dev);
@@ -862,99 +836,33 @@ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
return 0;
printk(KERN_ERR "%s: -- Error, unable to allocate DMA table.\n",
- hwif->cds->name);
+ hwif->name);
return 1;
}
-
-static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base)
-{
- printk(KERN_INFO " %s: MMIO-DMA ", hwif->name);
-
- return 0;
-}
-
-static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base)
-{
- printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx",
- hwif->name, base, base + 7);
-
- if (!request_region(base, 8, hwif->name)) {
- printk(" -- Error, ports in use.\n");
- return 1;
- }
-
- if (hwif->cds->extra) {
- hwif->extra_base = base + (hwif->channel ? 8 : 16);
-
- if (!hwif->mate || !hwif->mate->extra_ports) {
- if (!request_region(hwif->extra_base,
- hwif->cds->extra, hwif->cds->name)) {
- printk(" -- Error, extra ports in use.\n");
- release_region(base, 8);
- return 1;
- }
- hwif->extra_ports = hwif->cds->extra;
- }
- }
-
- return 0;
-}
-
-static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base)
-{
- if (hwif->mmio)
- return ide_mapped_mmio_dma(hwif, base);
-
- return ide_iomio_dma(hwif, base);
-}
+EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
+
+static const struct ide_dma_ops sff_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
+};
void ide_setup_dma(ide_hwif_t *hwif, unsigned long base)
{
- u8 dma_stat;
-
- if (ide_dma_iobase(hwif, base))
- return;
-
- if (ide_allocate_dma_engine(hwif)) {
- ide_release_dma(hwif);
- return;
- }
-
hwif->dma_base = base;
if (!hwif->dma_command)
hwif->dma_command = hwif->dma_base + 0;
- if (!hwif->dma_vendor1)
- hwif->dma_vendor1 = hwif->dma_base + 1;
if (!hwif->dma_status)
hwif->dma_status = hwif->dma_base + 2;
- if (!hwif->dma_vendor3)
- hwif->dma_vendor3 = hwif->dma_base + 3;
- if (!hwif->dma_prdtable)
- hwif->dma_prdtable = hwif->dma_base + 4;
-
- if (!hwif->dma_host_set)
- hwif->dma_host_set = &ide_dma_host_set;
- if (!hwif->dma_setup)
- hwif->dma_setup = &ide_dma_setup;
- if (!hwif->dma_exec_cmd)
- hwif->dma_exec_cmd = &ide_dma_exec_cmd;
- if (!hwif->dma_start)
- hwif->dma_start = &ide_dma_start;
- if (!hwif->ide_dma_end)
- hwif->ide_dma_end = &__ide_dma_end;
- if (!hwif->ide_dma_test_irq)
- hwif->ide_dma_test_irq = &__ide_dma_test_irq;
- if (!hwif->dma_timeout)
- hwif->dma_timeout = &ide_dma_timeout;
- if (!hwif->dma_lost_irq)
- hwif->dma_lost_irq = &ide_dma_lost_irq;
- dma_stat = hwif->INB(hwif->dma_status);
- printk(KERN_CONT ", BIOS settings: %s:%s, %s:%s\n",
- hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "PIO",
- hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "PIO");
+ hwif->dma_ops = &sff_dma_ops;
}
EXPORT_SYMBOL_GPL(ide_setup_dma);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 5f133dfb541c..f05fbc2bd7a8 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -231,6 +231,7 @@ static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
unsigned int bcount, int direction)
{
+ ide_hwif_t *hwif = drive->hwif;
struct request *rq = pc->rq;
struct req_iterator iter;
struct bio_vec *bvec;
@@ -246,9 +247,9 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
data = bvec_kmap_irq(bvec, &flags);
if (direction)
- drive->hwif->atapi_output_bytes(drive, data, count);
+ hwif->output_data(drive, NULL, data, count);
else
- drive->hwif->atapi_input_bytes(drive, data, count);
+ hwif->input_data(drive, NULL, data, count);
bvec_kunmap_irq(data, &flags);
bcount -= count;
@@ -261,10 +262,7 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
if (bcount) {
printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
drive->name, __func__, bcount);
- if (direction)
- ide_atapi_write_zeros(drive, bcount);
- else
- ide_atapi_discard_data(drive, bcount);
+ ide_pad_transfer(drive, direction, bcount);
}
}
@@ -396,7 +394,7 @@ static void idefloppy_retry_pc(ide_drive_t *drive)
}
/* The usual interrupt handler called during a packet command. */
-static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
ide_hwif_t *hwif = drive->hwif;
@@ -411,7 +409,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
debug_log("Reached %s interrupt handler\n", __func__);
if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
- dma_error = hwif->ide_dma_end(drive);
+ dma_error = hwif->dma_ops->dma_end(drive);
if (dma_error) {
printk(KERN_ERR "%s: DMA %s error\n", drive->name,
rq_data_dir(rq) ? "write" : "read");
@@ -465,10 +463,10 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
}
/* Get the number of bytes to transfer */
- bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) |
- hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]);
+ bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) |
+ hwif->INB(hwif->io_ports.lbam_addr);
/* on this interrupt */
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if (ireason & CD) {
printk(KERN_ERR "ide-floppy: CoD != 0 in %s\n", __func__);
@@ -490,7 +488,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
printk(KERN_ERR "ide-floppy: The floppy wants "
"to send us more data than expected "
"- discarding data\n");
- ide_atapi_discard_data(drive, bcount);
+ ide_pad_transfer(drive, 0, bcount);
ide_set_handler(drive,
&idefloppy_pc_intr,
@@ -503,12 +501,12 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
}
}
if (pc->flags & PC_FLAG_WRITING)
- xferfunc = hwif->atapi_output_bytes;
+ xferfunc = hwif->output_data;
else
- xferfunc = hwif->atapi_input_bytes;
+ xferfunc = hwif->input_data;
if (pc->buf)
- xferfunc(drive, pc->cur_pos, bcount);
+ xferfunc(drive, NULL, pc->cur_pos, bcount);
else
ide_floppy_io_buffers(drive, pc, bcount,
!!(pc->flags & PC_FLAG_WRITING));
@@ -539,7 +537,7 @@ static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive)
"initiated yet DRQ isn't asserted\n");
return startstop;
}
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if ((ireason & CD) == 0 || (ireason & IO)) {
printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
"issuing a packet command\n");
@@ -548,8 +546,10 @@ static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive)
/* Set the interrupt routine */
ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+
/* Send the actual packet */
- HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+ hwif->output_data(drive, NULL, floppy->pc->c, 12);
+
return ide_started;
}
@@ -569,7 +569,8 @@ static int idefloppy_transfer_pc2(ide_drive_t *drive)
idefloppy_floppy_t *floppy = drive->driver_data;
/* Send the actual packet */
- HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+ drive->hwif->output_data(drive, NULL, floppy->pc->c, 12);
+
/* Timeout for the packet command */
return IDEFLOPPY_WAIT_CMD;
}
@@ -586,7 +587,7 @@ static ide_startstop_t idefloppy_transfer_pc1(ide_drive_t *drive)
"initiated yet DRQ isn't asserted\n");
return startstop;
}
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if ((ireason & CD) == 0 || (ireason & IO)) {
printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
"while issuing a packet command\n");
@@ -663,7 +664,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
dma = 0;
if ((pc->flags & PC_FLAG_DMA_RECOMMENDED) && drive->using_dma)
- dma = !hwif->dma_setup(drive);
+ dma = !hwif->dma_ops->dma_setup(drive);
ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
IDE_TFLAG_OUT_DEVICE, bcount, dma);
@@ -671,7 +672,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
if (dma) {
/* Begin DMA, if necessary */
pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
- hwif->dma_start(drive);
+ hwif->dma_ops->dma_start(drive);
}
/* Can we transfer the packet when we get the interrupt or wait? */
@@ -692,7 +693,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
return ide_started;
} else {
/* Issue the packet command */
- hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ ide_execute_pkt_cmd(drive);
return (*pkt_xfer_routine) (drive);
}
}
@@ -1596,13 +1597,13 @@ static int idefloppy_revalidate_disk(struct gendisk *disk)
}
static struct block_device_operations idefloppy_ops = {
- .owner = THIS_MODULE,
- .open = idefloppy_open,
- .release = idefloppy_release,
- .ioctl = idefloppy_ioctl,
- .getgeo = idefloppy_getgeo,
- .media_changed = idefloppy_media_changed,
- .revalidate_disk= idefloppy_revalidate_disk
+ .owner = THIS_MODULE,
+ .open = idefloppy_open,
+ .release = idefloppy_release,
+ .ioctl = idefloppy_ioctl,
+ .getgeo = idefloppy_getgeo,
+ .media_changed = idefloppy_media_changed,
+ .revalidate_disk = idefloppy_revalidate_disk
};
static int ide_floppy_probe(ide_drive_t *drive)
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 25fda0a3263f..a6073e248f45 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -33,7 +33,7 @@ static ssize_t store_add(struct class *cls, const char *buf, size_t n)
if (sscanf(buf, "%x:%x:%d", &base, &ctl, &irq) != 3)
return -EINVAL;
- hwif = ide_find_port(base);
+ hwif = ide_find_port();
if (hwif == NULL)
return -ENOENT;
@@ -90,19 +90,45 @@ static int __init ide_generic_init(void)
int i;
for (i = 0; i < MAX_HWIFS; i++) {
- ide_hwif_t *hwif = &ide_hwifs[i];
+ ide_hwif_t *hwif;
unsigned long io_addr = ide_default_io_base(i);
hw_regs_t hw;
- if (hwif->chipset == ide_unknown && io_addr) {
+ idx[i] = 0xff;
+
+ if (io_addr) {
+ if (!request_region(io_addr, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
+ "not free.\n",
+ DRV_NAME, io_addr, io_addr + 7);
+ continue;
+ }
+
+ if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX "
+ "not free.\n",
+ DRV_NAME, io_addr + 0x206);
+ release_region(io_addr, 8);
+ continue;
+ }
+
+ /*
+ * Skip probing if the corresponding
+ * slot is already occupied.
+ */
+ hwif = ide_find_port();
+ if (hwif == NULL || hwif->index != i) {
+ idx[i] = 0xff;
+ continue;
+ }
+
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
hw.irq = ide_default_irq(io_addr);
ide_init_port_hw(hwif, &hw);
idx[i] = i;
- } else
- idx[i] = 0xff;
+ }
}
ide_device_add_all(idx, NULL);
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 31e5afadb7e9..788783da9025 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -218,7 +218,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
* we could be smarter and check for current xfer_speed
* in struct drive etc...
*/
- if (drive->hwif->dma_host_set == NULL)
+ if (drive->hwif->dma_ops == NULL)
break;
/*
* TODO: respect ->using_dma setting
@@ -295,54 +295,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
spin_unlock_irqrestore(&ide_lock, flags);
}
-void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_taskfile *tf = &task->tf;
-
- if (task->tf_flags & IDE_TFLAG_IN_DATA) {
- u16 data = hwif->INW(hwif->io_ports[IDE_DATA_OFFSET]);
-
- tf->data = data & 0xff;
- tf->hob_data = (data >> 8) & 0xff;
- }
-
- /* be sure we're looking at the low order bits */
- hwif->OUTB(drive->ctl & ~0x80, hwif->io_ports[IDE_CONTROL_OFFSET]);
-
- if (task->tf_flags & IDE_TFLAG_IN_NSECT)
- tf->nsect = hwif->INB(hwif->io_ports[IDE_NSECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_LBAL)
- tf->lbal = hwif->INB(hwif->io_ports[IDE_SECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_LBAM)
- tf->lbam = hwif->INB(hwif->io_ports[IDE_LCYL_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_LBAH)
- tf->lbah = hwif->INB(hwif->io_ports[IDE_HCYL_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
- tf->device = hwif->INB(hwif->io_ports[IDE_SELECT_OFFSET]);
-
- if (task->tf_flags & IDE_TFLAG_LBA48) {
- hwif->OUTB(drive->ctl | 0x80,
- hwif->io_ports[IDE_CONTROL_OFFSET]);
-
- if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
- tf->hob_feature =
- hwif->INB(hwif->io_ports[IDE_FEATURE_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
- tf->hob_nsect =
- hwif->INB(hwif->io_ports[IDE_NSECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
- tf->hob_lbal =
- hwif->INB(hwif->io_ports[IDE_SECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
- tf->hob_lbam =
- hwif->INB(hwif->io_ports[IDE_LCYL_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
- tf->hob_lbah =
- hwif->INB(hwif->io_ports[IDE_HCYL_OFFSET]);
- }
-}
-
/**
* ide_end_drive_cmd - end an explicit drive command
* @drive: command
@@ -378,7 +330,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
tf->error = err;
tf->status = stat;
- ide_tf_read(drive, task);
+ drive->hwif->tf_read(drive, task);
if (task->tf_flags & IDE_TFLAG_DYN)
kfree(task);
@@ -427,7 +379,7 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
u32 wcount = (i > 16) ? 16 : i;
i -= wcount;
- HWIF(drive)->ata_input_data(drive, buffer, wcount);
+ drive->hwif->input_data(drive, NULL, buffer, wcount * 4);
}
}
@@ -454,7 +406,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
if (err == ABRT_ERR) {
if (drive->select.b.lba &&
/* some newer drives don't support WIN_SPECIFY */
- hwif->INB(hwif->io_ports[IDE_COMMAND_OFFSET]) ==
+ hwif->INB(hwif->io_ports.command_addr) ==
WIN_SPECIFY)
return ide_stopped;
} else if ((err & BAD_CRC) == BAD_CRC) {
@@ -507,8 +459,8 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u
if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
/* force an abort */
- hwif->OUTB(WIN_IDLEIMMEDIATE,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, WIN_IDLEIMMEDIATE,
+ hwif->io_ports.command_addr);
if (rq->errors >= ERROR_MAX) {
ide_kill_rq(drive, rq);
@@ -721,15 +673,12 @@ static ide_startstop_t do_special (ide_drive_t *drive)
#endif
if (s->b.set_tune) {
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
u8 req_pio = drive->tune_req;
s->b.set_tune = 0;
if (set_pio_mode_abuse(drive->hwif, req_pio)) {
-
- if (hwif->set_pio_mode == NULL)
- return ide_stopped;
-
/*
* take ide_lock for drive->[no_]unmask/[no_]io_32bit
*/
@@ -737,10 +686,10 @@ static ide_startstop_t do_special (ide_drive_t *drive)
unsigned long flags;
spin_lock_irqsave(&ide_lock, flags);
- hwif->set_pio_mode(drive, req_pio);
+ port_ops->set_pio_mode(drive, req_pio);
spin_unlock_irqrestore(&ide_lock, flags);
} else
- hwif->set_pio_mode(drive, req_pio);
+ port_ops->set_pio_mode(drive, req_pio);
} else {
int keep_dma = drive->using_dma;
@@ -1241,12 +1190,12 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
if (error < 0) {
printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
- (void)HWIF(drive)->ide_dma_end(drive);
+ (void)hwif->dma_ops->dma_end(drive);
ret = ide_error(drive, "dma timeout error",
ide_read_status(drive));
} else {
printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
- hwif->dma_timeout(drive);
+ hwif->dma_ops->dma_timeout(drive);
}
/*
@@ -1358,7 +1307,7 @@ void ide_timer_expiry (unsigned long data)
startstop = handler(drive);
} else if (drive_is_ready(drive)) {
if (drive->waiting_for_dma)
- hwgroup->hwif->dma_lost_irq(drive);
+ hwif->dma_ops->dma_lost_irq(drive);
(void)ide_ack_intr(hwif);
printk(KERN_WARNING "%s: lost interrupt\n", drive->name);
startstop = handler(drive);
@@ -1424,7 +1373,7 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
*/
do {
if (hwif->irq == irq) {
- stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ stat = hwif->INB(hwif->io_ports.status_addr);
if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
/* Try to not flood the console with msgs */
static unsigned long last_msgtime, count;
@@ -1514,7 +1463,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
* Whack the status register, just in case
* we have a leftover pending IRQ.
*/
- (void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ (void) hwif->INB(hwif->io_ports.status_addr);
#endif /* CONFIG_BLK_DEV_IDEPCI */
}
spin_unlock_irqrestore(&ide_lock, flags);
@@ -1688,7 +1637,23 @@ void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
task.tf.lbam = bcount & 0xff;
task.tf.lbah = (bcount >> 8) & 0xff;
- ide_tf_load(drive, &task);
+ ide_tf_dump(drive->name, &task.tf);
+ drive->hwif->tf_load(drive, &task);
}
EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
+
+void ide_pad_transfer(ide_drive_t *drive, int write, int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 buf[4] = { 0 };
+
+ while (len > 0) {
+ if (write)
+ hwif->output_data(drive, NULL, buf, min(4, len));
+ else
+ hwif->input_data(drive, NULL, buf, min(4, len));
+ len -= 4;
+ }
+}
+EXPORT_SYMBOL_GPL(ide_pad_transfer);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 45944219eea0..57d9a9a79a6f 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -37,21 +37,6 @@ static u8 ide_inb (unsigned long port)
return (u8) inb(port);
}
-static u16 ide_inw (unsigned long port)
-{
- return (u16) inw(port);
-}
-
-static void ide_insw (unsigned long port, void *addr, u32 count)
-{
- insw(port, addr, count);
-}
-
-static void ide_insl (unsigned long port, void *addr, u32 count)
-{
- insl(port, addr, count);
-}
-
static void ide_outb (u8 val, unsigned long port)
{
outb(val, port);
@@ -62,32 +47,11 @@ static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port)
outb(addr, port);
}
-static void ide_outw (u16 val, unsigned long port)
-{
- outw(val, port);
-}
-
-static void ide_outsw (unsigned long port, void *addr, u32 count)
-{
- outsw(port, addr, count);
-}
-
-static void ide_outsl (unsigned long port, void *addr, u32 count)
-{
- outsl(port, addr, count);
-}
-
void default_hwif_iops (ide_hwif_t *hwif)
{
hwif->OUTB = ide_outb;
hwif->OUTBSYNC = ide_outbsync;
- hwif->OUTW = ide_outw;
- hwif->OUTSW = ide_outsw;
- hwif->OUTSL = ide_outsl;
hwif->INB = ide_inb;
- hwif->INW = ide_inw;
- hwif->INSW = ide_insw;
- hwif->INSL = ide_insl;
}
/*
@@ -99,21 +63,6 @@ static u8 ide_mm_inb (unsigned long port)
return (u8) readb((void __iomem *) port);
}
-static u16 ide_mm_inw (unsigned long port)
-{
- return (u16) readw((void __iomem *) port);
-}
-
-static void ide_mm_insw (unsigned long port, void *addr, u32 count)
-{
- __ide_mm_insw((void __iomem *) port, addr, count);
-}
-
-static void ide_mm_insl (unsigned long port, void *addr, u32 count)
-{
- __ide_mm_insl((void __iomem *) port, addr, count);
-}
-
static void ide_mm_outb (u8 value, unsigned long port)
{
writeb(value, (void __iomem *) port);
@@ -124,34 +73,13 @@ static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
writeb(value, (void __iomem *) port);
}
-static void ide_mm_outw (u16 value, unsigned long port)
-{
- writew(value, (void __iomem *) port);
-}
-
-static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
-{
- __ide_mm_outsw((void __iomem *) port, addr, count);
-}
-
-static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
-{
- __ide_mm_outsl((void __iomem *) port, addr, count);
-}
-
void default_hwif_mmiops (ide_hwif_t *hwif)
{
hwif->OUTB = ide_mm_outb;
/* Most systems will need to override OUTBSYNC, alas however
this one is controller specific! */
hwif->OUTBSYNC = ide_mm_outbsync;
- hwif->OUTW = ide_mm_outw;
- hwif->OUTSW = ide_mm_outsw;
- hwif->OUTSL = ide_mm_outsl;
hwif->INB = ide_mm_inb;
- hwif->INW = ide_mm_inw;
- hwif->INSW = ide_mm_insw;
- hwif->INSL = ide_mm_insl;
}
EXPORT_SYMBOL(default_hwif_mmiops);
@@ -159,17 +87,137 @@ EXPORT_SYMBOL(default_hwif_mmiops);
void SELECT_DRIVE (ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
- if (hwif->selectproc)
- hwif->selectproc(drive);
+ if (port_ops && port_ops->selectproc)
+ port_ops->selectproc(drive);
- hwif->OUTB(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
+ hwif->OUTB(drive->select.all, hwif->io_ports.device_addr);
}
void SELECT_MASK (ide_drive_t *drive, int mask)
{
- if (HWIF(drive)->maskproc)
- HWIF(drive)->maskproc(drive, mask);
+ const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+
+ if (port_ops && port_ops->maskproc)
+ port_ops->maskproc(drive, mask);
+}
+
+static void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ void (*tf_outb)(u8 addr, unsigned long port);
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (mmio)
+ tf_outb = ide_mm_outb;
+ else
+ tf_outb = ide_outb;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ ide_set_irq(drive, 1);
+
+ if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
+ SELECT_MASK(drive, 0);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+ u16 data = (tf->hob_data << 8) | tf->data;
+
+ if (mmio)
+ writew(data, (void __iomem *)io_ports->data_addr);
+ else
+ outw(data, io_ports->data_addr);
+ }
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ tf_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ tf_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ tf_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ tf_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ tf_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ tf_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ tf_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ tf_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ tf_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ tf_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ tf_outb((tf->device & HIHI) | drive->select.all,
+ io_ports->device_addr);
+}
+
+static void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ void (*tf_outb)(u8 addr, unsigned long port);
+ u8 (*tf_inb)(unsigned long port);
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+ if (mmio) {
+ tf_outb = ide_mm_outb;
+ tf_inb = ide_mm_inb;
+ } else {
+ tf_outb = ide_outb;
+ tf_inb = ide_inb;
+ }
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data;
+
+ if (mmio)
+ data = readw((void __iomem *)io_ports->data_addr);
+ else
+ data = inw(io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ tf_outb(drive->ctl & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = tf_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = tf_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = tf_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = tf_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = tf_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ tf_outb(drive->ctl | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = tf_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = tf_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = tf_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = tf_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = tf_inb(io_ports->lbah_addr);
+ }
}
/*
@@ -179,115 +227,112 @@ void SELECT_MASK (ide_drive_t *drive, int mask)
* of the sector count register location, with interrupts disabled
* to ensure that the reads all happen together.
*/
-static void ata_vlb_sync(ide_drive_t *drive, unsigned long port)
+static void ata_vlb_sync(unsigned long port)
{
- (void) HWIF(drive)->INB(port);
- (void) HWIF(drive)->INB(port);
- (void) HWIF(drive)->INB(port);
+ (void)inb(port);
+ (void)inb(port);
+ (void)inb(port);
}
/*
* This is used for most PIO data transfers *from* the IDE interface
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd len is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
*/
-static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
+static void ata_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 io_32bit = drive->io_32bit;
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long data_addr = io_ports->data_addr;
+ u8 io_32bit = drive->io_32bit;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+ len++;
if (io_32bit) {
- if (io_32bit & 2) {
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
+ if ((io_32bit & 2) && !mmio) {
local_irq_save(flags);
- ata_vlb_sync(drive, hwif->io_ports[IDE_NSECTOR_OFFSET]);
- hwif->INSL(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- wcount);
+ ata_vlb_sync(io_ports->nsect_addr);
+ }
+
+ if (mmio)
+ __ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
+ else
+ insl(data_addr, buf, len / 4);
+
+ if ((io_32bit & 2) && !mmio)
local_irq_restore(flags);
- } else
- hwif->INSL(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- wcount);
- } else
- hwif->INSW(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- wcount << 1);
+
+ if ((len & 3) >= 2) {
+ if (mmio)
+ __ide_mm_insw((void __iomem *)data_addr,
+ (u8 *)buf + (len & ~3), 1);
+ else
+ insw(data_addr, (u8 *)buf + (len & ~3), 1);
+ }
+ } else {
+ if (mmio)
+ __ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
+ else
+ insw(data_addr, buf, len / 2);
+ }
}
/*
* This is used for most PIO data transfers *to* the IDE interface
*/
-static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
+static void ata_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 io_32bit = drive->io_32bit;
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long data_addr = io_ports->data_addr;
+ u8 io_32bit = drive->io_32bit;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
if (io_32bit) {
- if (io_32bit & 2) {
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
+ if ((io_32bit & 2) && !mmio) {
local_irq_save(flags);
- ata_vlb_sync(drive, hwif->io_ports[IDE_NSECTOR_OFFSET]);
- hwif->OUTSL(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- wcount);
- local_irq_restore(flags);
- } else
- hwif->OUTSL(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- wcount);
- } else
- hwif->OUTSW(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- wcount << 1);
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-
-static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount)
-{
- ide_hwif_t *hwif = HWIF(drive);
+ ata_vlb_sync(io_ports->nsect_addr);
+ }
- ++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
- if (MACH_IS_ATARI || MACH_IS_Q40) {
- /* Atari has a byte-swapped IDE interface */
- insw_swapw(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- bytecount / 2);
- return;
- }
-#endif /* CONFIG_ATARI || CONFIG_Q40 */
- hwif->ata_input_data(drive, buffer, bytecount / 4);
- if ((bytecount & 0x03) >= 2)
- hwif->INSW(hwif->io_ports[IDE_DATA_OFFSET],
- (u8 *)buffer + (bytecount & ~0x03), 1);
-}
+ if (mmio)
+ __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
+ else
+ outsl(data_addr, buf, len / 4);
-static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount)
-{
- ide_hwif_t *hwif = HWIF(drive);
+ if ((io_32bit & 2) && !mmio)
+ local_irq_restore(flags);
- ++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
- if (MACH_IS_ATARI || MACH_IS_Q40) {
- /* Atari has a byte-swapped IDE interface */
- outsw_swapw(hwif->io_ports[IDE_DATA_OFFSET], buffer,
- bytecount / 2);
- return;
+ if ((len & 3) >= 2) {
+ if (mmio)
+ __ide_mm_outsw((void __iomem *)data_addr,
+ (u8 *)buf + (len & ~3), 1);
+ else
+ outsw(data_addr, (u8 *)buf + (len & ~3), 1);
+ }
+ } else {
+ if (mmio)
+ __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
+ else
+ outsw(data_addr, buf, len / 2);
}
-#endif /* CONFIG_ATARI || CONFIG_Q40 */
- hwif->ata_output_data(drive, buffer, bytecount / 4);
- if ((bytecount & 0x03) >= 2)
- hwif->OUTSW(hwif->io_ports[IDE_DATA_OFFSET],
- (u8 *)buffer + (bytecount & ~0x03), 1);
}
void default_hwif_transport(ide_hwif_t *hwif)
{
- hwif->ata_input_data = ata_input_data;
- hwif->ata_output_data = ata_output_data;
- hwif->atapi_input_bytes = atapi_input_bytes;
- hwif->atapi_output_bytes = atapi_output_bytes;
+ hwif->tf_load = ide_tf_load;
+ hwif->tf_read = ide_tf_read;
+
+ hwif->input_data = ata_input_data;
+ hwif->output_data = ata_output_data;
}
void ide_fix_driveid (struct hd_driveid *id)
@@ -429,7 +474,7 @@ int drive_is_ready (ide_drive_t *drive)
u8 stat = 0;
if (drive->waiting_for_dma)
- return hwif->ide_dma_test_irq(drive);
+ return hwif->dma_ops->dma_test_irq(drive);
#if 0
/* need to guarantee 400ns since last command was issued */
@@ -442,7 +487,7 @@ int drive_is_ready (ide_drive_t *drive)
* an interrupt with another pci card/device. We make no assumptions
* about possible isa-pnp and pci-pnp issues yet.
*/
- if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ if (hwif->io_ports.ctl_addr)
stat = ide_read_altstatus(drive);
else
/* Note: this may clear a pending IRQ!! */
@@ -580,6 +625,8 @@ static const struct drive_list_entry ivb_list[] = {
{ "TSSTcorp CDDVDW SH-S202J" , "SB01" },
{ "TSSTcorp CDDVDW SH-S202N" , "SB00" },
{ "TSSTcorp CDDVDW SH-S202N" , "SB01" },
+ { "TSSTcorp CDDVDW SH-S202H" , "SB00" },
+ { "TSSTcorp CDDVDW SH-S202H" , "SB01" },
{ NULL , NULL }
};
@@ -644,7 +691,7 @@ int ide_driveid_update(ide_drive_t *drive)
SELECT_MASK(drive, 1);
ide_set_irq(drive, 1);
msleep(50);
- hwif->OUTB(WIN_IDENTIFY, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, WIN_IDENTIFY, hwif->io_ports.command_addr);
timeout = jiffies + WAIT_WORSTCASE;
do {
if (time_after(jiffies, timeout)) {
@@ -671,7 +718,7 @@ int ide_driveid_update(ide_drive_t *drive)
local_irq_restore(flags);
return 0;
}
- hwif->ata_input_data(drive, id, SECTOR_WORDS);
+ hwif->input_data(drive, NULL, id, SECTOR_SIZE);
(void)ide_read_status(drive); /* clear drive IRQ */
local_irq_enable();
local_irq_restore(flags);
@@ -693,6 +740,7 @@ int ide_driveid_update(ide_drive_t *drive)
int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
{
ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
int error = 0;
u8 stat;
@@ -700,8 +748,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
// msleep(50);
#ifdef CONFIG_BLK_DEV_IDEDMA
- if (hwif->dma_host_set) /* check if host supports DMA */
- hwif->dma_host_set(drive, 0);
+ if (hwif->dma_ops) /* check if host supports DMA */
+ hwif->dma_ops->dma_host_set(drive, 0);
#endif
/* Skip setting PIO flow-control modes on pre-EIDE drives */
@@ -731,10 +779,9 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
SELECT_MASK(drive, 0);
udelay(1);
ide_set_irq(drive, 0);
- hwif->OUTB(speed, hwif->io_ports[IDE_NSECTOR_OFFSET]);
- hwif->OUTB(SETFEATURES_XFER, hwif->io_ports[IDE_FEATURE_OFFSET]);
- hwif->OUTBSYNC(drive, WIN_SETFEATURES,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTB(speed, io_ports->nsect_addr);
+ hwif->OUTB(SETFEATURES_XFER, io_ports->feature_addr);
+ hwif->OUTBSYNC(drive, WIN_SETFEATURES, io_ports->command_addr);
if (drive->quirk_list == 2)
ide_set_irq(drive, 1);
@@ -759,8 +806,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
#ifdef CONFIG_BLK_DEV_IDEDMA
if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) &&
drive->using_dma)
- hwif->dma_host_set(drive, 1);
- else if (hwif->dma_host_set) /* check if host supports DMA */
+ hwif->dma_ops->dma_host_set(drive, 1);
+ else if (hwif->dma_ops) /* check if host supports DMA */
ide_dma_off_quietly(drive);
#endif
@@ -842,7 +889,7 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
spin_lock_irqsave(&ide_lock, flags);
__ide_set_handler(drive, handler, timeout, expiry);
- hwif->OUTBSYNC(drive, cmd, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, cmd, hwif->io_ports.command_addr);
/*
* Drive takes 400nS to respond, we must avoid the IRQ being
* serviced before that.
@@ -852,9 +899,19 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
ndelay(400);
spin_unlock_irqrestore(&ide_lock, flags);
}
-
EXPORT_SYMBOL(ide_execute_command);
+void ide_execute_pkt_cmd(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif->OUTBSYNC(drive, WIN_PACKETCMD, hwif->io_ports.command_addr);
+ ndelay(400);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
/* needed below */
static ide_startstop_t do_reset1 (ide_drive_t *, int);
@@ -905,10 +962,11 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
+ const struct ide_port_ops *port_ops = hwif->port_ops;
u8 tmp;
- if (hwif->reset_poll != NULL) {
- if (hwif->reset_poll(drive)) {
+ if (port_ops && port_ops->reset_poll) {
+ if (port_ops->reset_poll(drive)) {
printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
hwif->name, drive->name);
return ide_stopped;
@@ -974,6 +1032,8 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
static void pre_reset(ide_drive_t *drive)
{
+ const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+
if (drive->media == ide_disk)
ide_disk_pre_reset(drive);
else
@@ -994,8 +1054,8 @@ static void pre_reset(ide_drive_t *drive)
return;
}
- if (HWIF(drive)->pre_reset != NULL)
- HWIF(drive)->pre_reset(drive);
+ if (port_ops && port_ops->pre_reset)
+ port_ops->pre_reset(drive);
if (drive->current_speed != 0xff)
drive->desired_speed = drive->current_speed;
@@ -1023,12 +1083,16 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
unsigned long flags;
ide_hwif_t *hwif;
ide_hwgroup_t *hwgroup;
+ struct ide_io_ports *io_ports;
+ const struct ide_port_ops *port_ops;
u8 ctl;
spin_lock_irqsave(&ide_lock, flags);
hwif = HWIF(drive);
hwgroup = HWGROUP(drive);
+ io_ports = &hwif->io_ports;
+
/* We must not reset with running handlers */
BUG_ON(hwgroup->handler != NULL);
@@ -1038,8 +1102,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
pre_reset(drive);
SELECT_DRIVE(drive);
udelay (20);
- hwif->OUTBSYNC(drive, WIN_SRST,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, WIN_SRST, io_ports->command_addr);
ndelay(400);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
hwgroup->polling = 1;
@@ -1055,7 +1118,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
for (unit = 0; unit < MAX_DRIVES; ++unit)
pre_reset(&hwif->drives[unit]);
- if (hwif->io_ports[IDE_CONTROL_OFFSET] == 0) {
+ if (io_ports->ctl_addr == 0) {
spin_unlock_irqrestore(&ide_lock, flags);
return ide_stopped;
}
@@ -1070,14 +1133,14 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
* recover from reset very quickly, saving us the first 50ms wait time.
*/
/* set SRST and nIEN */
- hwif->OUTBSYNC(drive, drive->ctl|6, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ hwif->OUTBSYNC(drive, drive->ctl|6, io_ports->ctl_addr);
/* more than enough time */
udelay(10);
if (drive->quirk_list == 2)
ctl = drive->ctl; /* clear SRST and nIEN */
else
ctl = drive->ctl | 2; /* clear SRST, leave nIEN */
- hwif->OUTBSYNC(drive, ctl, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ hwif->OUTBSYNC(drive, ctl, io_ports->ctl_addr);
/* more than enough time */
udelay(10);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
@@ -1089,8 +1152,9 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
* state when the disks are reset this way. At least, the Winbond
* 553 documentation says that
*/
- if (hwif->resetproc)
- hwif->resetproc(drive);
+ port_ops = hwif->port_ops;
+ if (port_ops && port_ops->resetproc)
+ port_ops->resetproc(drive);
spin_unlock_irqrestore(&ide_lock, flags);
return ide_started;
@@ -1121,7 +1185,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
* about locking issues (2.5 work ?).
*/
mdelay(1);
- stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ stat = hwif->INB(hwif->io_ports.status_addr);
if ((stat & BUSY_STAT) == 0)
return 0;
/*
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 7031a8dcf692..47af80df6872 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -85,7 +85,7 @@ static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
mode = XFER_PIO_4;
}
-// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
+/* printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */
return min(speed, mode);
}
@@ -274,16 +274,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
if (overridden)
printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
drive->name);
-
- /*
- * Conservative "downgrade" for all pre-ATA2 drives
- */
- if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 &&
- pio_mode && pio_mode < 4) {
- pio_mode--;
- printk(KERN_INFO "%s: applying conservative "
- "PIO \"downgrade\"\n", drive->name);
- }
}
if (pio_mode > max_mode)
@@ -298,9 +288,11 @@ EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
void ide_set_pio(ide_drive_t *drive, u8 req_pio)
{
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
u8 host_pio, pio;
- if (hwif->set_pio_mode == NULL)
+ if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
+ (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
return;
BUG_ON(hwif->pio_mask == 0x00);
@@ -352,26 +344,30 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
{
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ return 0;
- if (hwif->set_pio_mode == NULL)
+ if (port_ops == NULL || port_ops->set_pio_mode == NULL)
return -1;
/*
* TODO: temporary hack for some legacy host drivers that didn't
* set transfer mode on the device in ->set_pio_mode method...
*/
- if (hwif->set_dma_mode == NULL) {
- hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ if (port_ops->set_dma_mode == NULL) {
+ port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
return 0;
}
if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
if (ide_config_drive_speed(drive, mode))
return -1;
- hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
return 0;
} else {
- hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
return ide_config_drive_speed(drive, mode);
}
}
@@ -379,17 +375,21 @@ int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ return 0;
- if (hwif->set_dma_mode == NULL)
+ if (port_ops == NULL || port_ops->set_dma_mode == NULL)
return -1;
if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
if (ide_config_drive_speed(drive, mode))
return -1;
- hwif->set_dma_mode(drive, mode);
+ port_ops->set_dma_mode(drive, mode);
return 0;
} else {
- hwif->set_dma_mode(drive, mode);
+ port_ops->set_dma_mode(drive, mode);
return ide_config_drive_speed(drive, mode);
}
}
@@ -409,8 +409,10 @@ EXPORT_SYMBOL_GPL(ide_set_dma_mode);
int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
{
ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
- if (hwif->set_dma_mode == NULL)
+ if (port_ops == NULL || port_ops->set_dma_mode == NULL ||
+ (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
return -1;
rate = ide_rate_filter(drive, rate);
@@ -485,7 +487,7 @@ static void ide_dump_sector(ide_drive_t *drive)
else
task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
- ide_tf_read(drive, &task);
+ drive->hwif->tf_read(drive, &task);
if (lba48 || (tf->device & ATA_LBA))
printk(", LBAsect=%llu",
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 34c2ad36ce54..6a8953f68e9f 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -11,34 +11,52 @@
*
* You should have received a copy of the GNU General Public License
* (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/pnp.h>
#include <linux/ide.h>
+#define DRV_NAME "ide-pnp"
+
/* Add your devices here :)) */
static struct pnp_device_id idepnp_devices[] = {
- /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ /* Generic ESDI/IDE/ATA compatible hard disk controller */
{.id = "PNP0600", .driver_data = 0},
{.id = ""}
};
-static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
+static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
hw_regs_t hw;
ide_hwif_t *hwif;
+ unsigned long base, ctl;
if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
return -1;
+ base = pnp_port_start(dev, 0);
+ ctl = pnp_port_start(dev, 1);
+
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, pnp_port_start(dev, 0),
- pnp_port_start(dev, 1));
+ ide_std_init_ports(&hw, base, ctl);
hw.irq = pnp_irq(dev, 0);
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif) {
u8 index = hwif->index;
u8 idx[4] = { index, 0xff, 0xff, 0xff };
@@ -47,24 +65,27 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
ide_init_port_hw(hwif, &hw);
printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
- pnp_set_drvdata(dev,hwif);
+ pnp_set_drvdata(dev, hwif);
ide_device_add(idx, NULL);
return 0;
}
+ release_region(ctl, 1);
+ release_region(base, 8);
+
return -1;
}
-static void idepnp_remove(struct pnp_dev * dev)
+static void idepnp_remove(struct pnp_dev *dev)
{
ide_hwif_t *hwif = pnp_get_drvdata(dev);
- if (hwif)
- ide_unregister(hwif->index);
- else
- printk(KERN_ERR "idepnp: Unable to remove device, please report.\n");
+ ide_unregister(hwif);
+
+ release_region(pnp_port_start(dev, 1), 1);
+ release_region(pnp_port_start(dev, 0), 8);
}
static struct pnp_driver idepnp_driver = {
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 6a196c27b0aa..099a0fe1745b 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -124,7 +124,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
id = drive->id;
/* read 512 bytes of id info */
- hwif->ata_input_data(drive, id, SECTOR_WORDS);
+ hwif->input_data(drive, NULL, id, SECTOR_SIZE);
drive->id_read = 1;
local_irq_enable();
@@ -264,6 +264,7 @@ err_misc:
static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
{
ide_hwif_t *hwif = HWIF(drive);
+ struct ide_io_ports *io_ports = &hwif->io_ports;
int use_altstatus = 0, rc;
unsigned long timeout;
u8 s = 0, a = 0;
@@ -271,7 +272,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
/* take a deep breath */
msleep(50);
- if (hwif->io_ports[IDE_CONTROL_OFFSET]) {
+ if (io_ports->ctl_addr) {
a = ide_read_altstatus(drive);
s = ide_read_status(drive);
if ((a ^ s) & ~INDEX_STAT)
@@ -289,10 +290,10 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
*/
if ((cmd == WIN_PIDENTIFY))
/* disable dma & overlap */
- hwif->OUTB(0, hwif->io_ports[IDE_FEATURE_OFFSET]);
+ hwif->OUTB(0, io_ports->feature_addr);
/* ask drive for ID */
- hwif->OUTB(cmd, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, cmd, io_ports->command_addr);
timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
timeout += jiffies;
@@ -353,7 +354,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
* interrupts during the identify-phase that
* the irq handler isn't expecting.
*/
- if (hwif->io_ports[IDE_CONTROL_OFFSET]) {
+ if (hwif->io_ports.ctl_addr) {
if (!hwif->irq) {
autoprobe = 1;
cookie = probe_irq_on();
@@ -393,7 +394,7 @@ static int ide_busy_sleep(ide_hwif_t *hwif)
do {
msleep(50);
- stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ stat = hwif->INB(hwif->io_ports.status_addr);
if ((stat & BUSY_STAT) == 0)
return 0;
} while (time_before(jiffies, timeout));
@@ -425,6 +426,7 @@ static int ide_busy_sleep(ide_hwif_t *hwif)
static int do_probe (ide_drive_t *drive, u8 cmd)
{
ide_hwif_t *hwif = HWIF(drive);
+ struct ide_io_ports *io_ports = &hwif->io_ports;
int rc;
u8 stat;
@@ -445,7 +447,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
msleep(50);
SELECT_DRIVE(drive);
msleep(50);
- if (hwif->INB(hwif->io_ports[IDE_SELECT_OFFSET]) != drive->select.all &&
+ if (hwif->INB(io_ports->device_addr) != drive->select.all &&
!drive->present) {
if (drive->select.b.unit != 0) {
/* exit with drive0 selected */
@@ -472,17 +474,13 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
if (stat == (BUSY_STAT | READY_STAT))
return 4;
- if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
- ((drive->autotune == IDE_TUNE_DEFAULT) ||
- (drive->autotune == IDE_TUNE_AUTO))) {
+ if (rc == 1 && cmd == WIN_PIDENTIFY) {
printk(KERN_ERR "%s: no response (status = 0x%02x), "
"resetting drive\n", drive->name, stat);
msleep(50);
- hwif->OUTB(drive->select.all,
- hwif->io_ports[IDE_SELECT_OFFSET]);
+ hwif->OUTB(drive->select.all, io_ports->device_addr);
msleep(50);
- hwif->OUTB(WIN_SRST,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, WIN_SRST, io_ports->command_addr);
(void)ide_busy_sleep(hwif);
rc = try_to_identify(drive, cmd);
}
@@ -518,7 +516,7 @@ static void enable_nest (ide_drive_t *drive)
printk("%s: enabling %s -- ", hwif->name, drive->id->model);
SELECT_DRIVE(drive);
msleep(50);
- hwif->OUTB(EXABYTE_ENABLE_NEST, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, EXABYTE_ENABLE_NEST, hwif->io_ports.command_addr);
if (ide_busy_sleep(hwif)) {
printk(KERN_CONT "failed (timeout)\n");
@@ -644,7 +642,7 @@ static int ide_register_port(ide_hwif_t *hwif)
ret = device_register(&hwif->gendev);
if (ret < 0) {
printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
- __FUNCTION__, ret);
+ __func__, ret);
goto out;
}
@@ -773,8 +771,7 @@ static int ide_probe_port(ide_hwif_t *hwif)
BUG_ON(hwif->present);
- if (hwif->noprobe ||
- (hwif->drives[0].noprobe && hwif->drives[1].noprobe))
+ if (hwif->drives[0].noprobe && hwif->drives[1].noprobe)
return -EACCES;
/*
@@ -801,14 +798,9 @@ static int ide_probe_port(ide_hwif_t *hwif)
if (drive->present)
rc = 0;
}
- if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
- printk(KERN_WARNING "%s: reset\n", hwif->name);
- hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
- udelay(10);
- hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
- (void)ide_busy_sleep(hwif);
- }
+
local_irq_restore(flags);
+
/*
* Use cached IRQ number. It might be (and is...) changed by probe
* code above
@@ -821,29 +813,25 @@ static int ide_probe_port(ide_hwif_t *hwif)
static void ide_port_tune_devices(ide_hwif_t *hwif)
{
+ const struct ide_port_ops *port_ops = hwif->port_ops;
int unit;
for (unit = 0; unit < MAX_DRIVES; unit++) {
ide_drive_t *drive = &hwif->drives[unit];
- if (drive->present && hwif->quirkproc)
- hwif->quirkproc(drive);
+ if (drive->present && port_ops && port_ops->quirkproc)
+ port_ops->quirkproc(drive);
}
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present) {
- if (drive->autotune == IDE_TUNE_AUTO)
- ide_set_max_pio(drive);
-
- if (drive->autotune != IDE_TUNE_DEFAULT &&
- drive->autotune != IDE_TUNE_AUTO)
- continue;
+ ide_set_max_pio(drive);
drive->nice1 = 1;
- if (hwif->dma_host_set)
+ if (hwif->dma_ops)
ide_set_dma(drive);
}
}
@@ -994,6 +982,7 @@ static void ide_port_setup_devices(ide_hwif_t *hwif)
*/
static int init_irq (ide_hwif_t *hwif)
{
+ struct ide_io_ports *io_ports = &hwif->io_ports;
unsigned int index;
ide_hwgroup_t *hwgroup;
ide_hwif_t *match = NULL;
@@ -1077,9 +1066,9 @@ static int init_irq (ide_hwif_t *hwif)
if (IDE_CHIPSET_IS_PCI(hwif->chipset))
sa = IRQF_SHARED;
- if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ if (io_ports->ctl_addr)
/* clear nIEN */
- hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ hwif->OUTB(0x08, io_ports->ctl_addr);
if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup))
goto out_unlink;
@@ -1095,12 +1084,11 @@ static int init_irq (ide_hwif_t *hwif)
#if !defined(__mc68000__)
printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
- hwif->io_ports[IDE_DATA_OFFSET],
- hwif->io_ports[IDE_DATA_OFFSET]+7,
- hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
+ io_ports->data_addr, io_ports->status_addr,
+ io_ports->ctl_addr, hwif->irq);
#else
printk("%s at 0x%08lx on irq %d", hwif->name,
- hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
+ io_ports->data_addr, hwif->irq);
#endif /* __mc68000__ */
if (match)
printk(" (%sed with %s)",
@@ -1242,8 +1230,8 @@ static int hwif_init(ide_hwif_t *hwif)
int old_irq;
if (!hwif->irq) {
- if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
- {
+ hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+ if (!hwif->irq) {
printk("%s: DISABLED, NO IRQ\n", hwif->name);
return 0;
}
@@ -1272,7 +1260,8 @@ static int hwif_init(ide_hwif_t *hwif)
* It failed to initialise. Find the default IRQ for
* this port and try that.
*/
- if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+ hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+ if (!hwif->irq) {
printk("%s: Disabled unable to get IRQ %d.\n",
hwif->name, old_irq);
goto out;
@@ -1324,6 +1313,7 @@ static void hwif_register_devices(ide_hwif_t *hwif)
static void ide_port_init_devices(ide_hwif_t *hwif)
{
+ const struct ide_port_ops *port_ops = hwif->port_ops;
int i;
for (i = 0; i < MAX_DRIVES; i++) {
@@ -1335,12 +1325,10 @@ static void ide_port_init_devices(ide_hwif_t *hwif)
drive->unmask = 1;
if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
drive->no_unmask = 1;
- if ((hwif->host_flags & IDE_HFLAG_NO_AUTOTUNE) == 0)
- drive->autotune = 1;
}
- if (hwif->port_init_devs)
- hwif->port_init_devs(hwif);
+ if (port_ops && port_ops->port_init_devs)
+ port_ops->port_init_devs(hwif);
}
static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
@@ -1355,9 +1343,6 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
if (d->init_iops)
d->init_iops(hwif);
- if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0)
- ide_hwif_setup_dma(hwif, d);
-
if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
(d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
hwif->irq = port ? 15 : 14;
@@ -1365,16 +1350,36 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
hwif->host_flags = d->host_flags;
hwif->pio_mask = d->pio_mask;
- if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate)
- hwif->mate->serialized = hwif->serialized = 1;
+ /* ->set_pio_mode for DTC2278 is currently limited to port 0 */
+ if (hwif->chipset != ide_dtc2278 || hwif->channel == 0)
+ hwif->port_ops = d->port_ops;
+
+ if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
+ ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) {
+ if (hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
+ }
hwif->swdma_mask = d->swdma_mask;
hwif->mwdma_mask = d->mwdma_mask;
hwif->ultra_mask = d->udma_mask;
- /* reset DMA masks only for SFF-style DMA controllers */
- if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0 && hwif->dma_base == 0)
- hwif->swdma_mask = hwif->mwdma_mask = hwif->ultra_mask = 0;
+ if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
+ int rc;
+
+ if (d->init_dma)
+ rc = d->init_dma(hwif, d);
+ else
+ rc = ide_hwif_setup_dma(hwif, d);
+
+ if (rc < 0) {
+ printk(KERN_INFO "%s: DMA disabled\n", hwif->name);
+ hwif->swdma_mask = 0;
+ hwif->mwdma_mask = 0;
+ hwif->ultra_mask = 0;
+ } else if (d->dma_ops)
+ hwif->dma_ops = d->dma_ops;
+ }
if (d->host_flags & IDE_HFLAG_RQSIZE_256)
hwif->rqsize = 256;
@@ -1386,9 +1391,11 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
static void ide_port_cable_detect(ide_hwif_t *hwif)
{
- if (hwif->cable_detect && (hwif->ultra_mask & 0x78)) {
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) {
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = hwif->cable_detect(hwif);
+ hwif->cbl = port_ops->cable_detect(hwif);
}
}
@@ -1444,19 +1451,74 @@ static int ide_sysfs_register_port(ide_hwif_t *hwif)
return rc;
}
+/**
+ * ide_find_port_slot - find free ide_hwifs[] slot
+ * @d: IDE port info
+ *
+ * Return the new hwif. If we are out of free slots return NULL.
+ */
+
+ide_hwif_t *ide_find_port_slot(const struct ide_port_info *d)
+{
+ ide_hwif_t *hwif;
+ int i;
+ u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
+
+ /*
+ * Claim an unassigned slot.
+ *
+ * Give preference to claiming other slots before claiming ide0/ide1,
+ * just in case there's another interface yet-to-be-scanned
+ * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults).
+ *
+ * Unless there is a bootable card that does not use the standard
+ * ports 0x1f0/0x170 (the ide0/ide1 defaults).
+ */
+ if (bootable) {
+ i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;
+
+ for (; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->chipset == ide_unknown)
+ return hwif;
+ }
+ } else {
+ for (i = 2; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->chipset == ide_unknown)
+ return hwif;
+ }
+ for (i = 0; i < 2 && i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->chipset == ide_unknown)
+ return hwif;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(ide_find_port_slot);
+
int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
{
ide_hwif_t *hwif, *mate = NULL;
int i, rc = 0;
for (i = 0; i < MAX_HWIFS; i++) {
- if (d == NULL || idx[i] == 0xff) {
+ if (idx[i] == 0xff) {
mate = NULL;
continue;
}
hwif = &ide_hwifs[idx[i]];
+ ide_port_apply_params(hwif);
+
+ if (d == NULL) {
+ mate = NULL;
+ continue;
+ }
+
if (d->chipset != ide_etrax100 && (i & 1) && mate) {
hwif->mate = mate;
mate->mate = hwif;
@@ -1475,25 +1537,15 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
hwif = &ide_hwifs[idx[i]];
- if ((hwif->chipset != ide_4drives || !hwif->mate ||
- !hwif->mate->present) && ide_hwif_request_regions(hwif)) {
- printk(KERN_ERR "%s: ports already in use, "
- "skipping probe\n", hwif->name);
- continue;
- }
-
- if (ide_probe_port(hwif) < 0) {
- ide_hwif_release_regions(hwif);
- continue;
- }
-
- hwif->present = 1;
+ if (ide_probe_port(hwif) == 0)
+ hwif->present = 1;
if (hwif->chipset != ide_4drives || !hwif->mate ||
!hwif->mate->present)
ide_register_port(hwif);
- ide_port_tune_devices(hwif);
+ if (hwif->present)
+ ide_port_tune_devices(hwif);
}
for (i = 0; i < MAX_HWIFS; i++) {
@@ -1502,9 +1554,6 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
hwif = &ide_hwifs[idx[i]];
- if (!hwif->present)
- continue;
-
if (hwif_init(hwif) == 0) {
printk(KERN_INFO "%s: failed to initialize IDE "
"interface\n", hwif->name);
@@ -1513,10 +1562,13 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
continue;
}
- ide_port_setup_devices(hwif);
+ if (hwif->present)
+ ide_port_setup_devices(hwif);
ide_acpi_init(hwif);
- ide_acpi_port_init_devices(hwif);
+
+ if (hwif->present)
+ ide_acpi_port_init_devices(hwif);
}
for (i = 0; i < MAX_HWIFS; i++) {
@@ -1525,11 +1577,11 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
hwif = &ide_hwifs[idx[i]];
- if (hwif->present) {
- if (hwif->chipset == ide_unknown)
- hwif->chipset = ide_generic;
+ if (hwif->chipset == ide_unknown)
+ hwif->chipset = ide_generic;
+
+ if (hwif->present)
hwif_register_devices(hwif);
- }
}
for (i = 0; i < MAX_HWIFS; i++) {
@@ -1538,11 +1590,11 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
hwif = &ide_hwifs[idx[i]];
- if (hwif->present) {
- ide_sysfs_register_port(hwif);
- ide_proc_register_port(hwif);
+ ide_sysfs_register_port(hwif);
+ ide_proc_register_port(hwif);
+
+ if (hwif->present)
ide_proc_port_register_devices(hwif);
- }
}
return rc;
@@ -1563,6 +1615,7 @@ EXPORT_SYMBOL_GPL(ide_device_add);
void ide_port_scan(ide_hwif_t *hwif)
{
+ ide_port_apply_params(hwif);
ide_port_cable_detect(hwif);
ide_port_init_devices(hwif);
@@ -1578,3 +1631,67 @@ void ide_port_scan(ide_hwif_t *hwif)
ide_proc_port_register_devices(hwif);
}
EXPORT_SYMBOL_GPL(ide_port_scan);
+
+static void ide_legacy_init_one(u8 *idx, hw_regs_t *hw, u8 port_no,
+ const struct ide_port_info *d,
+ unsigned long config)
+{
+ ide_hwif_t *hwif;
+ unsigned long base, ctl;
+ int irq;
+
+ if (port_no == 0) {
+ base = 0x1f0;
+ ctl = 0x3f6;
+ irq = 14;
+ } else {
+ base = 0x170;
+ ctl = 0x376;
+ irq = 15;
+ }
+
+ if (!request_region(base, 8, d->name)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ d->name, base, base + 7);
+ return;
+ }
+
+ if (!request_region(ctl, 1, d->name)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ d->name, ctl);
+ release_region(base, 8);
+ return;
+ }
+
+ ide_std_init_ports(hw, base, ctl);
+ hw->irq = irq;
+
+ hwif = ide_find_port_slot(d);
+ if (hwif) {
+ ide_init_port_hw(hwif, hw);
+ if (config)
+ hwif->config_data = config;
+ idx[port_no] = hwif->index;
+ }
+}
+
+int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
+{
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ hw_regs_t hw[2];
+
+ memset(&hw, 0, sizeof(hw));
+
+ if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0)
+ ide_legacy_init_one(idx, &hw[0], 0, d, config);
+ ide_legacy_init_one(idx, &hw[1], 1, d, config);
+
+ if (idx[0] == 0xff && idx[1] == 0xff &&
+ (d->host_flags & IDE_HFLAG_SINGLE))
+ return -ENOENT;
+
+ ide_device_add(idx, d);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_legacy_device_add);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index edd7f186dc4d..7b2f3815a838 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -47,28 +47,28 @@ static int proc_ide_read_imodel
const char *name;
switch (hwif->chipset) {
- case ide_generic: name = "generic"; break;
- case ide_pci: name = "pci"; break;
- case ide_cmd640: name = "cmd640"; break;
- case ide_dtc2278: name = "dtc2278"; break;
- case ide_ali14xx: name = "ali14xx"; break;
- case ide_qd65xx: name = "qd65xx"; break;
- case ide_umc8672: name = "umc8672"; break;
- case ide_ht6560b: name = "ht6560b"; break;
- case ide_rz1000: name = "rz1000"; break;
- case ide_trm290: name = "trm290"; break;
- case ide_cmd646: name = "cmd646"; break;
- case ide_cy82c693: name = "cy82c693"; break;
- case ide_4drives: name = "4drives"; break;
- case ide_pmac: name = "mac-io"; break;
- case ide_au1xxx: name = "au1xxx"; break;
- case ide_palm3710: name = "palm3710"; break;
- case ide_etrax100: name = "etrax100"; break;
- case ide_acorn: name = "acorn"; break;
- default: name = "(unknown)"; break;
+ case ide_generic: name = "generic"; break;
+ case ide_pci: name = "pci"; break;
+ case ide_cmd640: name = "cmd640"; break;
+ case ide_dtc2278: name = "dtc2278"; break;
+ case ide_ali14xx: name = "ali14xx"; break;
+ case ide_qd65xx: name = "qd65xx"; break;
+ case ide_umc8672: name = "umc8672"; break;
+ case ide_ht6560b: name = "ht6560b"; break;
+ case ide_rz1000: name = "rz1000"; break;
+ case ide_trm290: name = "trm290"; break;
+ case ide_cmd646: name = "cmd646"; break;
+ case ide_cy82c693: name = "cy82c693"; break;
+ case ide_4drives: name = "4drives"; break;
+ case ide_pmac: name = "mac-io"; break;
+ case ide_au1xxx: name = "au1xxx"; break;
+ case ide_palm3710: name = "palm3710"; break;
+ case ide_etrax100: name = "etrax100"; break;
+ case ide_acorn: name = "acorn"; break;
+ default: name = "(unknown)"; break;
}
len = sprintf(page, "%s\n", name);
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static int proc_ide_read_mate
@@ -81,7 +81,7 @@ static int proc_ide_read_mate
len = sprintf(page, "%s\n", hwif->mate->name);
else
len = sprintf(page, "(none)\n");
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static int proc_ide_read_channel
@@ -93,7 +93,7 @@ static int proc_ide_read_channel
page[0] = hwif->channel ? '1' : '0';
page[1] = '\n';
len = 2;
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static int proc_ide_read_identify
@@ -120,7 +120,7 @@ static int proc_ide_read_identify
len = out - page;
}
}
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
/**
@@ -197,7 +197,7 @@ EXPORT_SYMBOL(ide_add_setting);
* The caller must hold the setting semaphore.
*/
-static void __ide_remove_setting (ide_drive_t *drive, char *name)
+static void __ide_remove_setting(ide_drive_t *drive, char *name)
{
ide_settings_t **p, *setting;
@@ -205,7 +205,8 @@ static void __ide_remove_setting (ide_drive_t *drive, char *name)
while ((*p) && strcmp((*p)->name, name))
p = &((*p)->next);
- if ((setting = (*p)) == NULL)
+ setting = (*p);
+ if (setting == NULL)
return;
(*p) = setting->next;
@@ -223,7 +224,7 @@ static void __ide_remove_setting (ide_drive_t *drive, char *name)
* caller must hold ide_setting_mtx.
*/
-static void auto_remove_settings (ide_drive_t *drive)
+static void auto_remove_settings(ide_drive_t *drive)
{
ide_settings_t *setting;
repeat:
@@ -279,16 +280,16 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
if ((setting->rw & SETTING_READ)) {
spin_lock_irqsave(&ide_lock, flags);
- switch(setting->data_type) {
- case TYPE_BYTE:
- val = *((u8 *) setting->data);
- break;
- case TYPE_SHORT:
- val = *((u16 *) setting->data);
- break;
- case TYPE_INT:
- val = *((u32 *) setting->data);
- break;
+ switch (setting->data_type) {
+ case TYPE_BYTE:
+ val = *((u8 *) setting->data);
+ break;
+ case TYPE_SHORT:
+ val = *((u16 *) setting->data);
+ break;
+ case TYPE_INT:
+ val = *((u32 *) setting->data);
+ break;
}
spin_unlock_irqrestore(&ide_lock, flags);
}
@@ -326,15 +327,15 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
if (ide_spin_wait_hwgroup(drive))
return -EBUSY;
switch (setting->data_type) {
- case TYPE_BYTE:
- *((u8 *) setting->data) = val;
- break;
- case TYPE_SHORT:
- *((u16 *) setting->data) = val;
- break;
- case TYPE_INT:
- *((u32 *) setting->data) = val;
- break;
+ case TYPE_BYTE:
+ *((u8 *) setting->data) = val;
+ break;
+ case TYPE_SHORT:
+ *((u16 *) setting->data) = val;
+ break;
+ case TYPE_INT:
+ *((u32 *) setting->data) = val;
+ break;
}
spin_unlock_irq(&ide_lock);
return 0;
@@ -390,7 +391,7 @@ void ide_add_generic_settings (ide_drive_t *drive)
static void proc_ide_settings_warn(void)
{
- static int warned = 0;
+ static int warned;
if (warned)
return;
@@ -413,11 +414,12 @@ static int proc_ide_read_settings
mutex_lock(&ide_setting_mtx);
out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
- while(setting) {
+ while (setting) {
mul_factor = setting->mul_factor;
div_factor = setting->div_factor;
out += sprintf(out, "%-24s", setting->name);
- if ((rc = ide_read_setting(drive, setting)) >= 0)
+ rc = ide_read_setting(drive, setting);
+ if (rc >= 0)
out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
else
out += sprintf(out, "%-16s", "write-only");
@@ -431,7 +433,7 @@ static int proc_ide_read_settings
}
len = out - page;
mutex_unlock(&ide_setting_mtx);
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
#define MAX_LEN 30
@@ -512,8 +514,7 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
mutex_lock(&ide_setting_mtx);
setting = ide_find_setting_by_name(drive, name);
- if (!setting)
- {
+ if (!setting) {
mutex_unlock(&ide_setting_mtx);
goto parse_error;
}
@@ -533,8 +534,8 @@ parse_error:
int proc_ide_read_capacity
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- int len = sprintf(page,"%llu\n", (long long)0x7fffffff);
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ int len = sprintf(page, "%llu\n", (long long)0x7fffffff);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
EXPORT_SYMBOL_GPL(proc_ide_read_capacity);
@@ -546,13 +547,13 @@ int proc_ide_read_geometry
char *out = page;
int len;
- out += sprintf(out,"physical %d/%d/%d\n",
+ out += sprintf(out, "physical %d/%d/%d\n",
drive->cyl, drive->head, drive->sect);
- out += sprintf(out,"logical %d/%d/%d\n",
+ out += sprintf(out, "logical %d/%d/%d\n",
drive->bios_cyl, drive->bios_head, drive->bios_sect);
len = out - page;
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
EXPORT_SYMBOL(proc_ide_read_geometry);
@@ -566,7 +567,7 @@ static int proc_ide_read_dmodel
len = sprintf(page, "%.40s\n",
(id && id->model[0]) ? (char *)id->model : "(none)");
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static int proc_ide_read_driver
@@ -583,7 +584,7 @@ static int proc_ide_read_driver
dev->driver->name, ide_drv->version);
} else
len = sprintf(page, "ide-default version 0.9.newide\n");
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
@@ -598,14 +599,14 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
err = device_attach(dev);
if (err < 0)
printk(KERN_WARNING "IDE: %s: device_attach error: %d\n",
- __FUNCTION__, err);
+ __func__, err);
drive->driver_req[0] = 0;
if (dev->driver == NULL) {
err = device_attach(dev);
if (err < 0)
printk(KERN_WARNING
"IDE: %s: device_attach(2) error: %d\n",
- __FUNCTION__, err);
+ __func__, err);
}
if (dev->driver && !strcmp(dev->driver->name, driver))
ret = 0;
@@ -639,30 +640,26 @@ static int proc_ide_read_media
int len;
switch (drive->media) {
- case ide_disk: media = "disk\n";
- break;
- case ide_cdrom: media = "cdrom\n";
- break;
- case ide_tape: media = "tape\n";
- break;
- case ide_floppy:media = "floppy\n";
- break;
- case ide_optical:media = "optical\n";
- break;
- default: media = "UNKNOWN\n";
- break;
+ case ide_disk: media = "disk\n"; break;
+ case ide_cdrom: media = "cdrom\n"; break;
+ case ide_tape: media = "tape\n"; break;
+ case ide_floppy: media = "floppy\n"; break;
+ case ide_optical: media = "optical\n"; break;
+ default: media = "UNKNOWN\n"; break;
}
- strcpy(page,media);
+ strcpy(page, media);
len = strlen(media);
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static ide_proc_entry_t generic_drive_entries[] = {
- { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver },
- { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL },
- { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL },
- { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL },
- { "settings", S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings, proc_ide_write_settings },
+ { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver,
+ proc_ide_write_driver },
+ { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL },
+ { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL },
+ { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL },
+ { "settings", S_IFREG|S_IRUSR|S_IWUSR, proc_ide_read_settings,
+ proc_ide_write_settings },
{ NULL, 0, NULL, NULL }
};
@@ -734,7 +731,6 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
spin_unlock_irqrestore(&ide_lock, flags);
mutex_unlock(&ide_setting_mtx);
}
-
EXPORT_SYMBOL(ide_proc_unregister_driver);
void ide_proc_port_register_devices(ide_hwif_t *hwif)
@@ -755,7 +751,7 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif)
drive->proc = proc_mkdir(drive->name, parent);
if (drive->proc)
ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
- sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+ sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name);
ent = proc_symlink(drive->name, proc_ide_root, name);
if (!ent) return;
}
@@ -790,15 +786,6 @@ void ide_proc_register_port(ide_hwif_t *hwif)
}
}
-#ifdef CONFIG_BLK_DEV_IDEPCI
-void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
-{
- create_proc_info_entry(name, 0, proc_ide_root, get_info);
-}
-
-EXPORT_SYMBOL_GPL(ide_pci_create_host_proc);
-#endif
-
void ide_proc_unregister_port(ide_hwif_t *hwif)
{
if (hwif->proc) {
@@ -825,7 +812,7 @@ static int ide_drivers_show(struct seq_file *s, void *p)
err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
if (err < 0)
printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
- __FUNCTION__, err);
+ __func__, err);
return 0;
}
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
index 98888da1b600..0e79efff1deb 100644
--- a/drivers/ide/ide-scan-pci.c
+++ b/drivers/ide/ide-scan-pci.c
@@ -102,7 +102,7 @@ static int __init ide_scan_pcibus(void)
if (__pci_register_driver(d, d->driver.owner,
d->driver.mod_name))
printk(KERN_ERR "%s: failed to register %s driver\n",
- __FUNCTION__, d->driver.mod_name);
+ __func__, d->driver.mod_name);
}
return 0;
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index f43fd070f1b6..54a43b044608 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -72,26 +72,6 @@ enum {
#endif
/**************************** Tunable parameters *****************************/
-
-
-/*
- * Pipelined mode parameters.
- *
- * We try to use the minimum number of stages which is enough to keep the tape
- * constantly streaming. To accomplish that, we implement a feedback loop around
- * the maximum number of stages:
- *
- * We start from MIN maximum stages (we will not even use MIN stages if we don't
- * need them), increment it by RATE*(MAX-MIN) whenever we sense that the
- * pipeline is empty, until we reach the optimum value or until we reach MAX.
- *
- * Setting the following parameter to 0 is illegal: the pipelined mode cannot be
- * disabled (idetape_calculate_speeds() divides by tape->max_stages.)
- */
-#define IDETAPE_MIN_PIPELINE_STAGES 1
-#define IDETAPE_MAX_PIPELINE_STAGES 400
-#define IDETAPE_INCREASE_STAGES_RATE 20
-
/*
* After each failed packet command we issue a request sense command and retry
* the packet command IDETAPE_MAX_PC_RETRIES times.
@@ -224,28 +204,17 @@ enum {
/* 0 When the tape position is unknown */
IDETAPE_FLAG_ADDRESS_VALID = (1 << 1),
/* Device already opened */
- IDETAPE_FLAG_BUSY = (1 << 2),
- /* Error detected in a pipeline stage */
- IDETAPE_FLAG_PIPELINE_ERR = (1 << 3),
+ IDETAPE_FLAG_BUSY = (1 << 2),
/* Attempt to auto-detect the current user block size */
- IDETAPE_FLAG_DETECT_BS = (1 << 4),
+ IDETAPE_FLAG_DETECT_BS = (1 << 3),
/* Currently on a filemark */
- IDETAPE_FLAG_FILEMARK = (1 << 5),
+ IDETAPE_FLAG_FILEMARK = (1 << 4),
/* DRQ interrupt device */
- IDETAPE_FLAG_DRQ_INTERRUPT = (1 << 6),
- /* pipeline active */
- IDETAPE_FLAG_PIPELINE_ACTIVE = (1 << 7),
+ IDETAPE_FLAG_DRQ_INTERRUPT = (1 << 5),
/* 0 = no tape is loaded, so we don't rewind after ejecting */
- IDETAPE_FLAG_MEDIUM_PRESENT = (1 << 8),
+ IDETAPE_FLAG_MEDIUM_PRESENT = (1 << 6),
};
-/* A pipeline stage. */
-typedef struct idetape_stage_s {
- struct request rq; /* The corresponding request */
- struct idetape_bh *bh; /* The data buffers */
- struct idetape_stage_s *next; /* Pointer to the next stage */
-} idetape_stage_t;
-
/*
* Most of our global data which we need to save even as we leave the driver due
* to an interrupt or a timer event is stored in the struct defined below.
@@ -289,9 +258,7 @@ typedef struct ide_tape_obj {
* While polling for DSC we use postponed_rq to postpone the current
* request so that ide.c will be able to service pending requests on the
* other device. Note that at most we will have only one DSC (usually
- * data transfer) request in the device request queue. Additional
- * requests can be queued in our internal pipeline, but they will be
- * visible to ide.c only one at a time.
+ * data transfer) request in the device request queue.
*/
struct request *postponed_rq;
/* The time in which we started polling for DSC */
@@ -331,43 +298,20 @@ typedef struct ide_tape_obj {
* At most, there is only one ide-tape originated data transfer request
* in the device request queue. This allows ide.c to easily service
* requests from the other device when we postpone our active request.
- * In the pipelined operation mode, we use our internal pipeline
- * structure to hold more data requests. The data buffer size is chosen
- * based on the tape's recommendation.
*/
- /* ptr to the request which is waiting in the device request queue */
- struct request *active_data_rq;
+
/* Data buffer size chosen based on the tape's recommendation */
- int stage_size;
- idetape_stage_t *merge_stage;
- int merge_stage_size;
+ int buffer_size;
+ /* merge buffer */
+ struct idetape_bh *merge_bh;
+ /* size of the merge buffer */
+ int merge_bh_size;
+ /* pointer to current buffer head within the merge buffer */
struct idetape_bh *bh;
char *b_data;
int b_count;
- /*
- * Pipeline parameters.
- *
- * To accomplish non-pipelined mode, we simply set the following
- * variables to zero (or NULL, where appropriate).
- */
- /* Number of currently used stages */
- int nr_stages;
- /* Number of pending stages */
- int nr_pending_stages;
- /* We will not allocate more than this number of stages */
- int max_stages, min_pipeline, max_pipeline;
- /* The first stage which will be removed from the pipeline */
- idetape_stage_t *first_stage;
- /* The currently active stage */
- idetape_stage_t *active_stage;
- /* Will be serviced after the currently active request */
- idetape_stage_t *next_stage;
- /* New requests will be added to the pipeline here */
- idetape_stage_t *last_stage;
- /* Optional free stage which we can use */
- idetape_stage_t *cache_stage;
- int pages_per_stage;
+ int pages_per_buffer;
/* Wasted space in each stage */
int excess_bh_size;
@@ -388,45 +332,6 @@ typedef struct ide_tape_obj {
/* the tape is write protected (hardware or opened as read-only) */
char write_prot;
- /*
- * Limit the number of times a request can be postponed, to avoid an
- * infinite postpone deadlock.
- */
- int postpone_cnt;
-
- /*
- * Measures number of frames:
- *
- * 1. written/read to/from the driver pipeline (pipeline_head).
- * 2. written/read to/from the tape buffers (idetape_bh).
- * 3. written/read by the tape to/from the media (tape_head).
- */
- int pipeline_head;
- int buffer_head;
- int tape_head;
- int last_tape_head;
-
- /* Speed control at the tape buffers input/output */
- unsigned long insert_time;
- int insert_size;
- int insert_speed;
- int max_insert_speed;
- int measure_insert_time;
-
- /* Speed regulation negative feedback loop */
- int speed_control;
- int pipeline_head_speed;
- int controlled_pipeline_head_speed;
- int uncontrolled_pipeline_head_speed;
- int controlled_last_pipeline_head;
- unsigned long uncontrolled_pipeline_head_time;
- unsigned long controlled_pipeline_head_time;
- int controlled_previous_pipeline_head;
- int uncontrolled_previous_pipeline_head;
- unsigned long controlled_previous_head_time;
- unsigned long uncontrolled_previous_head_time;
- int restart_speed_control_req;
-
u32 debug_mask;
} idetape_tape_t;
@@ -490,13 +395,13 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
if (bh == NULL) {
printk(KERN_ERR "ide-tape: bh == NULL in "
"idetape_input_buffers\n");
- ide_atapi_discard_data(drive, bcount);
+ ide_pad_transfer(drive, 0, bcount);
return;
}
count = min(
(unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
bcount);
- HWIF(drive)->atapi_input_bytes(drive, bh->b_data +
+ drive->hwif->input_data(drive, NULL, bh->b_data +
atomic_read(&bh->b_count), count);
bcount -= count;
atomic_add(count, &bh->b_count);
@@ -522,7 +427,7 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
return;
}
count = min((unsigned int)pc->b_count, (unsigned int)bcount);
- HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
+ drive->hwif->output_data(drive, NULL, pc->b_data, count);
bcount -= count;
pc->b_data += count;
pc->b_count -= count;
@@ -674,128 +579,36 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
}
}
-static void idetape_activate_next_stage(ide_drive_t *drive)
+/* Free data buffers completely. */
+static void ide_tape_kfree_buffer(idetape_tape_t *tape)
{
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage = tape->next_stage;
- struct request *rq = &stage->rq;
+ struct idetape_bh *prev_bh, *bh = tape->merge_bh;
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
+ while (bh) {
+ u32 size = bh->b_size;
- if (stage == NULL) {
- printk(KERN_ERR "ide-tape: bug: Trying to activate a non"
- " existing stage\n");
- return;
- }
+ while (size) {
+ unsigned int order = fls(size >> PAGE_SHIFT)-1;
- rq->rq_disk = tape->disk;
- rq->buffer = NULL;
- rq->special = (void *)stage->bh;
- tape->active_data_rq = rq;
- tape->active_stage = stage;
- tape->next_stage = stage->next;
-}
-
-/* Free a stage along with its related buffers completely. */
-static void __idetape_kfree_stage(idetape_stage_t *stage)
-{
- struct idetape_bh *prev_bh, *bh = stage->bh;
- int size;
-
- while (bh != NULL) {
- if (bh->b_data != NULL) {
- size = (int) bh->b_size;
- while (size > 0) {
- free_page((unsigned long) bh->b_data);
- size -= PAGE_SIZE;
- bh->b_data += PAGE_SIZE;
- }
+ if (bh->b_data)
+ free_pages((unsigned long)bh->b_data, order);
+
+ size &= (order-1);
+ bh->b_data += (1 << order) * PAGE_SIZE;
}
prev_bh = bh;
bh = bh->b_reqnext;
kfree(prev_bh);
}
- kfree(stage);
-}
-
-static void idetape_kfree_stage(idetape_tape_t *tape, idetape_stage_t *stage)
-{
- __idetape_kfree_stage(stage);
+ kfree(tape->merge_bh);
}
-/*
- * Remove tape->first_stage from the pipeline. The caller should avoid race
- * conditions.
- */
-static void idetape_remove_stage_head(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage;
-
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
-
- if (tape->first_stage == NULL) {
- printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
- return;
- }
- if (tape->active_stage == tape->first_stage) {
- printk(KERN_ERR "ide-tape: bug: Trying to free our active "
- "pipeline stage\n");
- return;
- }
- stage = tape->first_stage;
- tape->first_stage = stage->next;
- idetape_kfree_stage(tape, stage);
- tape->nr_stages--;
- if (tape->first_stage == NULL) {
- tape->last_stage = NULL;
- if (tape->next_stage != NULL)
- printk(KERN_ERR "ide-tape: bug: tape->next_stage !="
- " NULL\n");
- if (tape->nr_stages)
- printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 "
- "now\n");
- }
-}
-
-/*
- * This will free all the pipeline stages starting from new_last_stage->next
- * to the end of the list, and point tape->last_stage to new_last_stage.
- */
-static void idetape_abort_pipeline(ide_drive_t *drive,
- idetape_stage_t *new_last_stage)
-{
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage = new_last_stage->next;
- idetape_stage_t *nstage;
-
- debug_log(DBG_PROCS, "%s: Enter %s\n", tape->name, __func__);
-
- while (stage) {
- nstage = stage->next;
- idetape_kfree_stage(tape, stage);
- --tape->nr_stages;
- --tape->nr_pending_stages;
- stage = nstage;
- }
- if (new_last_stage)
- new_last_stage->next = NULL;
- tape->last_stage = new_last_stage;
- tape->next_stage = NULL;
-}
-
-/*
- * Finish servicing a request and insert a pending pipeline request into the
- * main device queue.
- */
static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
{
struct request *rq = HWGROUP(drive)->rq;
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
int error;
- int remove_stage = 0;
- idetape_stage_t *active_stage;
debug_log(DBG_PROCS, "Enter %s\n", __func__);
@@ -815,58 +628,8 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
spin_lock_irqsave(&tape->lock, flags);
- /* The request was a pipelined data transfer request */
- if (tape->active_data_rq == rq) {
- active_stage = tape->active_stage;
- tape->active_stage = NULL;
- tape->active_data_rq = NULL;
- tape->nr_pending_stages--;
- if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
- remove_stage = 1;
- if (error) {
- set_bit(IDETAPE_FLAG_PIPELINE_ERR,
- &tape->flags);
- if (error == IDETAPE_ERROR_EOD)
- idetape_abort_pipeline(drive,
- active_stage);
- }
- } else if (rq->cmd[0] & REQ_IDETAPE_READ) {
- if (error == IDETAPE_ERROR_EOD) {
- set_bit(IDETAPE_FLAG_PIPELINE_ERR,
- &tape->flags);
- idetape_abort_pipeline(drive, active_stage);
- }
- }
- if (tape->next_stage != NULL) {
- idetape_activate_next_stage(drive);
-
- /* Insert the next request into the request queue. */
- (void)ide_do_drive_cmd(drive, tape->active_data_rq,
- ide_end);
- } else if (!error) {
- /*
- * This is a part of the feedback loop which tries to
- * find the optimum number of stages. We are starting
- * from a minimum maximum number of stages, and if we
- * sense that the pipeline is empty, we try to increase
- * it, until we reach the user compile time memory
- * limit.
- */
- int i = (tape->max_pipeline - tape->min_pipeline) / 10;
-
- tape->max_stages += max(i, 1);
- tape->max_stages = max(tape->max_stages,
- tape->min_pipeline);
- tape->max_stages = min(tape->max_stages,
- tape->max_pipeline);
- }
- }
ide_end_drive_cmd(drive, 0, 0);
- if (remove_stage)
- idetape_remove_stage_head(drive);
- if (tape->active_data_rq == NULL)
- clear_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags);
spin_unlock_irqrestore(&tape->lock, flags);
return 0;
}
@@ -993,7 +756,7 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
stat = ide_read_status(drive);
if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
- if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
+ if (hwif->dma_ops->dma_end(drive) || (stat & ERR_STAT)) {
/*
* A DMA error is sometimes expected. For example,
* if the tape is crossing a filemark during a
@@ -1083,10 +846,10 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
return ide_do_reset(drive);
}
/* Get the number of bytes to transfer on this interrupt. */
- bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) |
- hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]);
+ bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) |
+ hwif->INB(hwif->io_ports.lbam_addr);
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if (ireason & CD) {
printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__);
@@ -1108,7 +871,7 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
printk(KERN_ERR "ide-tape: The tape wants to "
"send us more data than expected "
"- discarding data\n");
- ide_atapi_discard_data(drive, bcount);
+ ide_pad_transfer(drive, 0, bcount);
ide_set_handler(drive, &idetape_pc_intr,
IDETAPE_WAIT_CMD, NULL);
return ide_started;
@@ -1117,16 +880,16 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
"data than expected - allowing transfer\n");
}
iobuf = &idetape_input_buffers;
- xferfunc = hwif->atapi_input_bytes;
+ xferfunc = hwif->input_data;
} else {
iobuf = &idetape_output_buffers;
- xferfunc = hwif->atapi_output_bytes;
+ xferfunc = hwif->output_data;
}
if (pc->bh)
iobuf(drive, pc, bcount);
else
- xferfunc(drive, pc->cur_pos, bcount);
+ xferfunc(drive, NULL, pc->cur_pos, bcount);
/* Update the current position */
pc->xferred += bcount;
@@ -1190,12 +953,12 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
"yet DRQ isn't asserted\n");
return startstop;
}
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
"a packet command, retrying\n");
udelay(100);
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if (retries == 0) {
printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
"issuing a packet command, ignoring\n");
@@ -1213,10 +976,11 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
/* Begin DMA, if necessary */
if (pc->flags & PC_FLAG_DMA_IN_PROGRESS)
- hwif->dma_start(drive);
+ hwif->dma_ops->dma_start(drive);
#endif
/* Send the actual packet */
- HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
+ hwif->output_data(drive, NULL, pc->c, 12);
+
return ide_started;
}
@@ -1279,7 +1043,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
ide_dma_off(drive);
}
if ((pc->flags & PC_FLAG_DMA_RECOMMENDED) && drive->using_dma)
- dma_ok = !hwif->dma_setup(drive);
+ dma_ok = !hwif->dma_ops->dma_setup(drive);
ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
@@ -1292,7 +1056,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
IDETAPE_WAIT_CMD, NULL);
return ide_started;
} else {
- hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ ide_execute_pkt_cmd(drive);
return idetape_transfer_pc(drive);
}
}
@@ -1335,69 +1099,6 @@ static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
pc->idetape_callback = &idetape_pc_callback;
}
-static void idetape_calculate_speeds(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- if (time_after(jiffies,
- tape->controlled_pipeline_head_time + 120 * HZ)) {
- tape->controlled_previous_pipeline_head =
- tape->controlled_last_pipeline_head;
- tape->controlled_previous_head_time =
- tape->controlled_pipeline_head_time;
- tape->controlled_last_pipeline_head = tape->pipeline_head;
- tape->controlled_pipeline_head_time = jiffies;
- }
- if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
- tape->controlled_pipeline_head_speed = (tape->pipeline_head -
- tape->controlled_last_pipeline_head) * 32 * HZ /
- (jiffies - tape->controlled_pipeline_head_time);
- else if (time_after(jiffies, tape->controlled_previous_head_time))
- tape->controlled_pipeline_head_speed = (tape->pipeline_head -
- tape->controlled_previous_pipeline_head) * 32 *
- HZ / (jiffies - tape->controlled_previous_head_time);
-
- if (tape->nr_pending_stages < tape->max_stages/*- 1 */) {
- /* -1 for read mode error recovery */
- if (time_after(jiffies, tape->uncontrolled_previous_head_time +
- 10 * HZ)) {
- tape->uncontrolled_pipeline_head_time = jiffies;
- tape->uncontrolled_pipeline_head_speed =
- (tape->pipeline_head -
- tape->uncontrolled_previous_pipeline_head) *
- 32 * HZ / (jiffies -
- tape->uncontrolled_previous_head_time);
- }
- } else {
- tape->uncontrolled_previous_head_time = jiffies;
- tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
- if (time_after(jiffies, tape->uncontrolled_pipeline_head_time +
- 30 * HZ))
- tape->uncontrolled_pipeline_head_time = jiffies;
-
- }
- tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed,
- tape->controlled_pipeline_head_speed);
-
- if (tape->speed_control == 1) {
- if (tape->nr_pending_stages >= tape->max_stages / 2)
- tape->max_insert_speed = tape->pipeline_head_speed +
- (1100 - tape->pipeline_head_speed) * 2 *
- (tape->nr_pending_stages - tape->max_stages / 2)
- / tape->max_stages;
- else
- tape->max_insert_speed = 500 +
- (tape->pipeline_head_speed - 500) * 2 *
- tape->nr_pending_stages / tape->max_stages;
-
- if (tape->nr_pending_stages >= tape->max_stages * 99 / 100)
- tape->max_insert_speed = 5000;
- } else
- tape->max_insert_speed = tape->speed_control;
-
- tape->max_insert_speed = max(tape->max_insert_speed, 500);
-}
-
static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -1432,17 +1133,7 @@ static ide_startstop_t idetape_rw_callback(ide_drive_t *drive)
int blocks = tape->pc->xferred / tape->blk_size;
tape->avg_size += blocks * tape->blk_size;
- tape->insert_size += blocks * tape->blk_size;
- if (tape->insert_size > 1024 * 1024)
- tape->measure_insert_time = 1;
- if (tape->measure_insert_time) {
- tape->measure_insert_time = 0;
- tape->insert_time = jiffies;
- tape->insert_size = 0;
- }
- if (time_after(jiffies, tape->insert_time))
- tape->insert_speed = tape->insert_size / 1024 * HZ /
- (jiffies - tape->insert_time);
+
if (time_after_eq(jiffies, tape->avg_time + HZ)) {
tape->avg_speed = tape->avg_size * HZ /
(jiffies - tape->avg_time) / 1024;
@@ -1475,7 +1166,7 @@ static void idetape_create_read_cmd(idetape_tape_t *tape,
pc->buf = NULL;
pc->buf_size = length * tape->blk_size;
pc->req_xfer = pc->buf_size;
- if (pc->req_xfer == tape->stage_size)
+ if (pc->req_xfer == tape->buffer_size)
pc->flags |= PC_FLAG_DMA_RECOMMENDED;
}
@@ -1495,7 +1186,7 @@ static void idetape_create_write_cmd(idetape_tape_t *tape,
pc->buf = NULL;
pc->buf_size = length * tape->blk_size;
pc->req_xfer = pc->buf_size;
- if (pc->req_xfer == tape->stage_size)
+ if (pc->req_xfer == tape->buffer_size)
pc->flags |= PC_FLAG_DMA_RECOMMENDED;
}
@@ -1547,10 +1238,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
drive->post_reset = 0;
}
- if (time_after(jiffies, tape->insert_time))
- tape->insert_speed = tape->insert_size / 1024 * HZ /
- (jiffies - tape->insert_time);
- idetape_calculate_speeds(drive);
if (!test_and_clear_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags) &&
(stat & SEEK_STAT) == 0) {
if (postponed_rq == NULL) {
@@ -1574,16 +1261,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
return ide_stopped;
}
if (rq->cmd[0] & REQ_IDETAPE_READ) {
- tape->buffer_head++;
- tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
idetape_create_read_cmd(tape, pc, rq->current_nr_sectors,
(struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
- tape->buffer_head++;
- tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
idetape_create_write_cmd(tape, pc, rq->current_nr_sectors,
(struct idetape_bh *)rq->special);
@@ -1604,111 +1287,91 @@ out:
return idetape_issue_pc(drive, pc);
}
-/* Pipeline related functions */
-static inline int idetape_pipeline_active(idetape_tape_t *tape)
-{
- int rc1, rc2;
-
- rc1 = test_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags);
- rc2 = (tape->active_data_rq != NULL);
- return rc1;
-}
-
/*
- * The function below uses __get_free_page to allocate a pipeline stage, along
- * with all the necessary small buffers which together make a buffer of size
- * tape->stage_size (or a bit more). We attempt to combine sequential pages as
+ * The function below uses __get_free_pages to allocate a data buffer of size
+ * tape->buffer_size (or a bit more). We attempt to combine sequential pages as
* much as possible.
*
- * It returns a pointer to the new allocated stage, or NULL if we can't (or
- * don't want to) allocate a stage.
- *
- * Pipeline stages are optional and are used to increase performance. If we
- * can't allocate them, we'll manage without them.
+ * It returns a pointer to the newly allocated buffer, or NULL in case of
+ * failure.
*/
-static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full,
- int clear)
+static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape,
+ int full, int clear)
{
- idetape_stage_t *stage;
- struct idetape_bh *prev_bh, *bh;
- int pages = tape->pages_per_stage;
+ struct idetape_bh *prev_bh, *bh, *merge_bh;
+ int pages = tape->pages_per_buffer;
+ unsigned int order, b_allocd;
char *b_data = NULL;
- stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL);
- if (!stage)
- return NULL;
- stage->next = NULL;
-
- stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
- bh = stage->bh;
+ merge_bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ bh = merge_bh;
if (bh == NULL)
goto abort;
- bh->b_reqnext = NULL;
- bh->b_data = (char *) __get_free_page(GFP_KERNEL);
+
+ order = fls(pages) - 1;
+ bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order);
if (!bh->b_data)
goto abort;
+ b_allocd = (1 << order) * PAGE_SIZE;
+ pages &= (order-1);
+
if (clear)
- memset(bh->b_data, 0, PAGE_SIZE);
- bh->b_size = PAGE_SIZE;
+ memset(bh->b_data, 0, b_allocd);
+ bh->b_reqnext = NULL;
+ bh->b_size = b_allocd;
atomic_set(&bh->b_count, full ? bh->b_size : 0);
- while (--pages) {
- b_data = (char *) __get_free_page(GFP_KERNEL);
+ while (pages) {
+ order = fls(pages) - 1;
+ b_data = (char *) __get_free_pages(GFP_KERNEL, order);
if (!b_data)
goto abort;
+ b_allocd = (1 << order) * PAGE_SIZE;
+
if (clear)
- memset(b_data, 0, PAGE_SIZE);
- if (bh->b_data == b_data + PAGE_SIZE) {
- bh->b_size += PAGE_SIZE;
- bh->b_data -= PAGE_SIZE;
+ memset(b_data, 0, b_allocd);
+
+ /* newly allocated page frames below buffer header or ...*/
+ if (bh->b_data == b_data + b_allocd) {
+ bh->b_size += b_allocd;
+ bh->b_data -= b_allocd;
if (full)
- atomic_add(PAGE_SIZE, &bh->b_count);
+ atomic_add(b_allocd, &bh->b_count);
continue;
}
+ /* they are above the header */
if (b_data == bh->b_data + bh->b_size) {
- bh->b_size += PAGE_SIZE;
+ bh->b_size += b_allocd;
if (full)
- atomic_add(PAGE_SIZE, &bh->b_count);
+ atomic_add(b_allocd, &bh->b_count);
continue;
}
prev_bh = bh;
bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
if (!bh) {
- free_page((unsigned long) b_data);
+ free_pages((unsigned long) b_data, order);
goto abort;
}
bh->b_reqnext = NULL;
bh->b_data = b_data;
- bh->b_size = PAGE_SIZE;
+ bh->b_size = b_allocd;
atomic_set(&bh->b_count, full ? bh->b_size : 0);
prev_bh->b_reqnext = bh;
+
+ pages &= (order-1);
}
+
bh->b_size -= tape->excess_bh_size;
if (full)
atomic_sub(tape->excess_bh_size, &bh->b_count);
- return stage;
+ return merge_bh;
abort:
- __idetape_kfree_stage(stage);
+ ide_tape_kfree_buffer(tape);
return NULL;
}
-static idetape_stage_t *idetape_kmalloc_stage(idetape_tape_t *tape)
-{
- idetape_stage_t *cache_stage = tape->cache_stage;
-
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
-
- if (tape->nr_stages >= tape->max_stages)
- return NULL;
- if (cache_stage != NULL) {
- tape->cache_stage = NULL;
- return cache_stage;
- }
- return __idetape_kmalloc_stage(tape, 0, 0);
-}
-
static int idetape_copy_stage_from_user(idetape_tape_t *tape,
- idetape_stage_t *stage, const char __user *buf, int n)
+ const char __user *buf, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
@@ -1740,7 +1403,7 @@ static int idetape_copy_stage_from_user(idetape_tape_t *tape,
}
static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
- idetape_stage_t *stage, int n)
+ int n)
{
struct idetape_bh *bh = tape->bh;
int count;
@@ -1771,11 +1434,11 @@ static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
return ret;
}
-static void idetape_init_merge_stage(idetape_tape_t *tape)
+static void idetape_init_merge_buffer(idetape_tape_t *tape)
{
- struct idetape_bh *bh = tape->merge_stage->bh;
+ struct idetape_bh *bh = tape->merge_bh;
+ tape->bh = tape->merge_bh;
- tape->bh = bh;
if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
atomic_set(&bh->b_count, 0);
else {
@@ -1784,61 +1447,6 @@ static void idetape_init_merge_stage(idetape_tape_t *tape)
}
}
-static void idetape_switch_buffers(idetape_tape_t *tape, idetape_stage_t *stage)
-{
- struct idetape_bh *tmp;
-
- tmp = stage->bh;
- stage->bh = tape->merge_stage->bh;
- tape->merge_stage->bh = tmp;
- idetape_init_merge_stage(tape);
-}
-
-/* Add a new stage at the end of the pipeline. */
-static void idetape_add_stage_tail(ide_drive_t *drive, idetape_stage_t *stage)
-{
- idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
-
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
-
- spin_lock_irqsave(&tape->lock, flags);
- stage->next = NULL;
- if (tape->last_stage != NULL)
- tape->last_stage->next = stage;
- else
- tape->first_stage = stage;
- tape->next_stage = stage;
- tape->last_stage = stage;
- if (tape->next_stage == NULL)
- tape->next_stage = tape->last_stage;
- tape->nr_stages++;
- tape->nr_pending_stages++;
- spin_unlock_irqrestore(&tape->lock, flags);
-}
-
-/* Install a completion in a pending request and sleep until it is serviced. The
- * caller should ensure that the request will not be serviced before we install
- * the completion (usually by disabling interrupts).
- */
-static void idetape_wait_for_request(ide_drive_t *drive, struct request *rq)
-{
- DECLARE_COMPLETION_ONSTACK(wait);
- idetape_tape_t *tape = drive->driver_data;
-
- if (rq == NULL || !blk_special_request(rq)) {
- printk(KERN_ERR "ide-tape: bug: Trying to sleep on non-valid"
- " request\n");
- return;
- }
- rq->end_io_data = &wait;
- rq->end_io = blk_end_sync_rq;
- spin_unlock_irq(&tape->lock);
- wait_for_completion(&wait);
- /* The stage and its struct request have been deallocated */
- spin_lock_irq(&tape->lock);
-}
-
static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -1907,7 +1515,7 @@ static void idetape_create_test_unit_ready_cmd(struct ide_atapi_pc *pc)
* to the request list without waiting for it to be serviced! In that case, we
* usually use idetape_queue_pc_head().
*/
-static int __idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
+static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
{
struct ide_tape_obj *tape = drive->driver_data;
struct request rq;
@@ -1939,7 +1547,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
timeout += jiffies;
while (time_before(jiffies, timeout)) {
idetape_create_test_unit_ready_cmd(&pc);
- if (!__idetape_queue_pc_tail(drive, &pc))
+ if (!idetape_queue_pc_tail(drive, &pc))
return 0;
if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
|| (tape->asc == 0x3A)) {
@@ -1948,7 +1556,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
return -ENOMEDIUM;
idetape_create_load_unload_cmd(drive, &pc,
IDETAPE_LU_LOAD_MASK);
- __idetape_queue_pc_tail(drive, &pc);
+ idetape_queue_pc_tail(drive, &pc);
load_attempted = 1;
/* not about to be ready */
} else if (!(tape->sense_key == 2 && tape->asc == 4 &&
@@ -1959,11 +1567,6 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
return -EIO;
}
-static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
- return __idetape_queue_pc_tail(drive, pc);
-}
-
static int idetape_flush_tape_buffers(ide_drive_t *drive)
{
struct ide_atapi_pc pc;
@@ -2029,50 +1632,21 @@ static int idetape_create_prevent_cmd(ide_drive_t *drive,
return 1;
}
-static int __idetape_discard_read_pipeline(ide_drive_t *drive)
+static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
- int cnt;
if (tape->chrdev_dir != IDETAPE_DIR_READ)
- return 0;
+ return;
- /* Remove merge stage. */
- cnt = tape->merge_stage_size / tape->blk_size;
- if (test_and_clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags))
- ++cnt; /* Filemarks count as 1 sector */
- tape->merge_stage_size = 0;
- if (tape->merge_stage != NULL) {
- __idetape_kfree_stage(tape->merge_stage);
- tape->merge_stage = NULL;
+ clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags);
+ tape->merge_bh_size = 0;
+ if (tape->merge_bh != NULL) {
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
}
- /* Clear pipeline flags. */
- clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags);
tape->chrdev_dir = IDETAPE_DIR_NONE;
-
- /* Remove pipeline stages. */
- if (tape->first_stage == NULL)
- return 0;
-
- spin_lock_irqsave(&tape->lock, flags);
- tape->next_stage = NULL;
- if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_rq);
- spin_unlock_irqrestore(&tape->lock, flags);
-
- while (tape->first_stage != NULL) {
- struct request *rq_ptr = &tape->first_stage->rq;
-
- cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
- if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
- ++cnt;
- idetape_remove_stage_head(drive);
- }
- tape->nr_pending_stages = 0;
- tape->max_stages = tape->min_pipeline;
- return cnt;
}
/*
@@ -2089,7 +1663,7 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
struct ide_atapi_pc pc;
if (tape->chrdev_dir == IDETAPE_DIR_READ)
- __idetape_discard_read_pipeline(drive);
+ __ide_tape_discard_merge_buffer(drive);
idetape_wait_ready(drive, 60 * 5 * HZ);
idetape_create_locate_cmd(drive, &pc, block, partition, skip);
retval = idetape_queue_pc_tail(drive, &pc);
@@ -2100,20 +1674,19 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
return (idetape_queue_pc_tail(drive, &pc));
}
-static void idetape_discard_read_pipeline(ide_drive_t *drive,
+static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
int restore_position)
{
idetape_tape_t *tape = drive->driver_data;
- int cnt;
int seek, position;
- cnt = __idetape_discard_read_pipeline(drive);
+ __ide_tape_discard_merge_buffer(drive);
if (restore_position) {
position = idetape_read_position(drive);
- seek = position > cnt ? position - cnt : 0;
+ seek = position > 0 ? position : 0;
if (idetape_position_tape(drive, seek, 0, 0)) {
printk(KERN_INFO "ide-tape: %s: position_tape failed in"
- " discard_pipeline()\n", tape->name);
+ " %s\n", tape->name, __func__);
return;
}
}
@@ -2131,12 +1704,6 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
- if (idetape_pipeline_active(tape)) {
- printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
- __func__);
- return (0);
- }
-
idetape_init_rq(&rq, cmd);
rq.rq_disk = tape->disk;
rq.special = (void *)bh;
@@ -2148,27 +1715,13 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
return 0;
- if (tape->merge_stage)
- idetape_init_merge_stage(tape);
+ if (tape->merge_bh)
+ idetape_init_merge_buffer(tape);
if (rq.errors == IDETAPE_ERROR_GENERAL)
return -EIO;
return (tape->blk_size * (blocks-rq.current_nr_sectors));
}
-/* start servicing the pipeline stages, starting from tape->next_stage. */
-static void idetape_plug_pipeline(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- if (tape->next_stage == NULL)
- return;
- if (!idetape_pipeline_active(tape)) {
- set_bit(IDETAPE_FLAG_PIPELINE_ACTIVE, &tape->flags);
- idetape_activate_next_stage(drive);
- (void) ide_do_drive_cmd(drive, tape->active_data_rq, ide_end);
- }
-}
-
static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
{
idetape_init_pc(pc);
@@ -2206,135 +1759,39 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
pc->idetape_callback = &idetape_pc_callback;
}
-static void idetape_wait_first_stage(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
-
- if (tape->first_stage == NULL)
- return;
- spin_lock_irqsave(&tape->lock, flags);
- if (tape->active_stage == tape->first_stage)
- idetape_wait_for_request(drive, tape->active_data_rq);
- spin_unlock_irqrestore(&tape->lock, flags);
-}
-
-/*
- * Try to add a character device originated write request to our pipeline. In
- * case we don't succeed, we revert to non-pipelined operation mode for this
- * request. In order to accomplish that, we
- *
- * 1. Try to allocate a new pipeline stage.
- * 2. If we can't, wait for more and more requests to be serviced and try again
- * each time.
- * 3. If we still can't allocate a stage, fallback to non-pipelined operation
- * mode for this request.
- */
+/* Queue up a character device originated write request. */
static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks)
{
idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *new_stage;
- unsigned long flags;
- struct request *rq;
debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
- /* Attempt to allocate a new stage. Beware possible race conditions. */
- while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) {
- spin_lock_irqsave(&tape->lock, flags);
- if (idetape_pipeline_active(tape)) {
- idetape_wait_for_request(drive, tape->active_data_rq);
- spin_unlock_irqrestore(&tape->lock, flags);
- } else {
- spin_unlock_irqrestore(&tape->lock, flags);
- idetape_plug_pipeline(drive);
- if (idetape_pipeline_active(tape))
- continue;
- /*
- * The machine is short on memory. Fallback to non-
- * pipelined operation mode for this request.
- */
- return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
- blocks, tape->merge_stage->bh);
- }
- }
- rq = &new_stage->rq;
- idetape_init_rq(rq, REQ_IDETAPE_WRITE);
- /* Doesn't actually matter - We always assume sequential access */
- rq->sector = tape->first_frame;
- rq->current_nr_sectors = blocks;
- rq->nr_sectors = blocks;
-
- idetape_switch_buffers(tape, new_stage);
- idetape_add_stage_tail(drive, new_stage);
- tape->pipeline_head++;
- idetape_calculate_speeds(drive);
-
- /*
- * Estimate whether the tape has stopped writing by checking if our
- * write pipeline is currently empty. If we are not writing anymore,
- * wait for the pipeline to be almost completely full (90%) before
- * starting to service requests, so that we will be able to keep up with
- * the higher speeds of the tape.
- */
- if (!idetape_pipeline_active(tape)) {
- if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
- tape->nr_stages >= tape->max_stages -
- tape->uncontrolled_pipeline_head_speed * 3 * 1024 /
- tape->blk_size) {
- tape->measure_insert_time = 1;
- tape->insert_time = jiffies;
- tape->insert_size = 0;
- tape->insert_speed = 0;
- idetape_plug_pipeline(drive);
- }
- }
- if (test_and_clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags))
- /* Return a deferred error */
- return -EIO;
- return blocks;
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
+ blocks, tape->merge_bh);
}
-/*
- * Wait until all pending pipeline requests are serviced. Typically called on
- * device close.
- */
-static void idetape_wait_for_pipeline(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
-
- while (tape->next_stage || idetape_pipeline_active(tape)) {
- idetape_plug_pipeline(drive);
- spin_lock_irqsave(&tape->lock, flags);
- if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_rq);
- spin_unlock_irqrestore(&tape->lock, flags);
- }
-}
-
-static void idetape_empty_write_pipeline(ide_drive_t *drive)
+static void ide_tape_flush_merge_buffer(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int blocks, min;
struct idetape_bh *bh;
if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
- printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline,"
+ printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer"
" but we are not writing.\n");
return;
}
- if (tape->merge_stage_size > tape->stage_size) {
+ if (tape->merge_bh_size > tape->buffer_size) {
printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
- tape->merge_stage_size = tape->stage_size;
+ tape->merge_bh_size = tape->buffer_size;
}
- if (tape->merge_stage_size) {
- blocks = tape->merge_stage_size / tape->blk_size;
- if (tape->merge_stage_size % tape->blk_size) {
+ if (tape->merge_bh_size) {
+ blocks = tape->merge_bh_size / tape->blk_size;
+ if (tape->merge_bh_size % tape->blk_size) {
unsigned int i;
blocks++;
- i = tape->blk_size - tape->merge_stage_size %
+ i = tape->blk_size - tape->merge_bh_size %
tape->blk_size;
bh = tape->bh->b_reqnext;
while (bh) {
@@ -2358,74 +1815,33 @@ static void idetape_empty_write_pipeline(ide_drive_t *drive)
}
}
(void) idetape_add_chrdev_write_request(drive, blocks);
- tape->merge_stage_size = 0;
+ tape->merge_bh_size = 0;
}
- idetape_wait_for_pipeline(drive);
- if (tape->merge_stage != NULL) {
- __idetape_kfree_stage(tape->merge_stage);
- tape->merge_stage = NULL;
+ if (tape->merge_bh != NULL) {
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
}
- clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags);
tape->chrdev_dir = IDETAPE_DIR_NONE;
-
- /*
- * On the next backup, perform the feedback loop again. (I don't want to
- * keep sense information between backups, as some systems are
- * constantly on, and the system load can be totally different on the
- * next backup).
- */
- tape->max_stages = tape->min_pipeline;
- if (tape->first_stage != NULL ||
- tape->next_stage != NULL ||
- tape->last_stage != NULL ||
- tape->nr_stages != 0) {
- printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
- "first_stage %p, next_stage %p, "
- "last_stage %p, nr_stages %d\n",
- tape->first_stage, tape->next_stage,
- tape->last_stage, tape->nr_stages);
- }
}
-static void idetape_restart_speed_control(ide_drive_t *drive)
+static int idetape_init_read(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-
- tape->restart_speed_control_req = 0;
- tape->pipeline_head = 0;
- tape->controlled_last_pipeline_head = 0;
- tape->controlled_previous_pipeline_head = 0;
- tape->uncontrolled_previous_pipeline_head = 0;
- tape->controlled_pipeline_head_speed = 5000;
- tape->pipeline_head_speed = 5000;
- tape->uncontrolled_pipeline_head_speed = 0;
- tape->controlled_pipeline_head_time =
- tape->uncontrolled_pipeline_head_time = jiffies;
- tape->controlled_previous_head_time =
- tape->uncontrolled_previous_head_time = jiffies;
-}
-
-static int idetape_init_read(ide_drive_t *drive, int max_stages)
-{
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *new_stage;
- struct request rq;
int bytes_read;
- u16 blocks = *(u16 *)&tape->caps[12];
/* Initialize read operation */
if (tape->chrdev_dir != IDETAPE_DIR_READ) {
if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
- idetape_empty_write_pipeline(drive);
+ ide_tape_flush_merge_buffer(drive);
idetape_flush_tape_buffers(drive);
}
- if (tape->merge_stage || tape->merge_stage_size) {
- printk(KERN_ERR "ide-tape: merge_stage_size should be"
+ if (tape->merge_bh || tape->merge_bh_size) {
+ printk(KERN_ERR "ide-tape: merge_bh_size should be"
" 0 now\n");
- tape->merge_stage_size = 0;
+ tape->merge_bh_size = 0;
}
- tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
- if (!tape->merge_stage)
+ tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0);
+ if (!tape->merge_bh)
return -ENOMEM;
tape->chrdev_dir = IDETAPE_DIR_READ;
@@ -2438,54 +1854,23 @@ static int idetape_init_read(ide_drive_t *drive, int max_stages)
if (drive->dsc_overlap) {
bytes_read = idetape_queue_rw_tail(drive,
REQ_IDETAPE_READ, 0,
- tape->merge_stage->bh);
+ tape->merge_bh);
if (bytes_read < 0) {
- __idetape_kfree_stage(tape->merge_stage);
- tape->merge_stage = NULL;
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
tape->chrdev_dir = IDETAPE_DIR_NONE;
return bytes_read;
}
}
}
- if (tape->restart_speed_control_req)
- idetape_restart_speed_control(drive);
- idetape_init_rq(&rq, REQ_IDETAPE_READ);
- rq.sector = tape->first_frame;
- rq.nr_sectors = blocks;
- rq.current_nr_sectors = blocks;
- if (!test_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags) &&
- tape->nr_stages < max_stages) {
- new_stage = idetape_kmalloc_stage(tape);
- while (new_stage != NULL) {
- new_stage->rq = rq;
- idetape_add_stage_tail(drive, new_stage);
- if (tape->nr_stages >= max_stages)
- break;
- new_stage = idetape_kmalloc_stage(tape);
- }
- }
- if (!idetape_pipeline_active(tape)) {
- if (tape->nr_pending_stages >= 3 * max_stages / 4) {
- tape->measure_insert_time = 1;
- tape->insert_time = jiffies;
- tape->insert_size = 0;
- tape->insert_speed = 0;
- idetape_plug_pipeline(drive);
- }
- }
+
return 0;
}
-/*
- * Called from idetape_chrdev_read() to service a character device read request
- * and add read-ahead requests to our pipeline.
- */
+/* called from idetape_chrdev_read() to service a chrdev read request. */
static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
{
idetape_tape_t *tape = drive->driver_data;
- unsigned long flags;
- struct request *rq_ptr;
- int bytes_read;
debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
@@ -2493,39 +1878,10 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
if (test_bit(IDETAPE_FLAG_FILEMARK, &tape->flags))
return 0;
- /* Wait for the next block to reach the head of the pipeline. */
- idetape_init_read(drive, tape->max_stages);
- if (tape->first_stage == NULL) {
- if (test_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags))
- return 0;
- return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
- tape->merge_stage->bh);
- }
- idetape_wait_first_stage(drive);
- rq_ptr = &tape->first_stage->rq;
- bytes_read = tape->blk_size * (rq_ptr->nr_sectors -
- rq_ptr->current_nr_sectors);
- rq_ptr->nr_sectors = 0;
- rq_ptr->current_nr_sectors = 0;
+ idetape_init_read(drive);
- if (rq_ptr->errors == IDETAPE_ERROR_EOD)
- return 0;
- else {
- idetape_switch_buffers(tape, tape->first_stage);
- if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
- set_bit(IDETAPE_FLAG_FILEMARK, &tape->flags);
- spin_lock_irqsave(&tape->lock, flags);
- idetape_remove_stage_head(drive);
- spin_unlock_irqrestore(&tape->lock, flags);
- tape->pipeline_head++;
- idetape_calculate_speeds(drive);
- }
- if (bytes_read > blocks * tape->blk_size) {
- printk(KERN_ERR "ide-tape: bug: trying to return more bytes"
- " than requested\n");
- bytes_read = blocks * tape->blk_size;
- }
- return (bytes_read);
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
+ tape->merge_bh);
}
static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
@@ -2537,8 +1893,8 @@ static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
while (bcount) {
unsigned int count;
- bh = tape->merge_stage->bh;
- count = min(tape->stage_size, bcount);
+ bh = tape->merge_bh;
+ count = min(tape->buffer_size, bcount);
bcount -= count;
blocks = count / tape->blk_size;
while (count) {
@@ -2549,31 +1905,10 @@ static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
bh = bh->b_reqnext;
}
idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks,
- tape->merge_stage->bh);
+ tape->merge_bh);
}
}
-static int idetape_pipeline_size(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- idetape_stage_t *stage;
- struct request *rq;
- int size = 0;
-
- idetape_wait_for_pipeline(drive);
- stage = tape->first_stage;
- while (stage != NULL) {
- rq = &stage->rq;
- size += tape->blk_size * (rq->nr_sectors -
- rq->current_nr_sectors);
- if (rq->errors == IDETAPE_ERROR_FILEMARK)
- size += tape->blk_size;
- stage = stage->next;
- }
- size += tape->merge_stage_size;
- return size;
-}
-
/*
* Rewinds the tape to the Beginning Of the current Partition (BOP). We
* currently support only one partition.
@@ -2619,11 +1954,10 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
if (copy_from_user(&config, argp, sizeof(config)))
return -EFAULT;
tape->best_dsc_rw_freq = config.dsc_rw_frequency;
- tape->max_stages = config.nr_stages;
break;
case 0x0350:
config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
- config.nr_stages = tape->max_stages;
+ config.nr_stages = 1;
if (copy_to_user(argp, &config, sizeof(config)))
return -EFAULT;
break;
@@ -2633,19 +1967,11 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
return 0;
}
-/*
- * The function below is now a bit more complicated than just passing the
- * command to the tape since we may have crossed some filemarks during our
- * pipelined read-ahead mode. As a minor side effect, the pipeline enables us to
- * support MTFSFM when the filemark is in our internal pipeline even if the tape
- * doesn't support spacing over filemarks in the reverse direction.
- */
static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
struct ide_atapi_pc pc;
- unsigned long flags;
int retval, count = 0;
int sprev = !!(tape->caps[4] & 0x20);
@@ -2658,48 +1984,12 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
}
if (tape->chrdev_dir == IDETAPE_DIR_READ) {
- /* its a read-ahead buffer, scan it for crossed filemarks. */
- tape->merge_stage_size = 0;
+ tape->merge_bh_size = 0;
if (test_and_clear_bit(IDETAPE_FLAG_FILEMARK, &tape->flags))
++count;
- while (tape->first_stage != NULL) {
- if (count == mt_count) {
- if (mt_op == MTFSFM)
- set_bit(IDETAPE_FLAG_FILEMARK,
- &tape->flags);
- return 0;
- }
- spin_lock_irqsave(&tape->lock, flags);
- if (tape->first_stage == tape->active_stage) {
- /*
- * We have reached the active stage in the read
- * pipeline. There is no point in allowing the
- * drive to continue reading any farther, so we
- * stop the pipeline.
- *
- * This section should be moved to a separate
- * subroutine because similar operations are
- * done in __idetape_discard_read_pipeline(),
- * for example.
- */
- tape->next_stage = NULL;
- spin_unlock_irqrestore(&tape->lock, flags);
- idetape_wait_first_stage(drive);
- tape->next_stage = tape->first_stage->next;
- } else
- spin_unlock_irqrestore(&tape->lock, flags);
- if (tape->first_stage->rq.errors ==
- IDETAPE_ERROR_FILEMARK)
- ++count;
- idetape_remove_stage_head(drive);
- }
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
}
- /*
- * The filemark was not found in our internal pipeline; now we can issue
- * the space command.
- */
switch (mt_op) {
case MTFSF:
case MTBSF:
@@ -2755,27 +2045,25 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
(count % tape->blk_size) == 0)
tape->user_bs_factor = count / tape->blk_size;
}
- rc = idetape_init_read(drive, tape->max_stages);
+ rc = idetape_init_read(drive);
if (rc < 0)
return rc;
if (count == 0)
return (0);
- if (tape->merge_stage_size) {
- actually_read = min((unsigned int)(tape->merge_stage_size),
+ if (tape->merge_bh_size) {
+ actually_read = min((unsigned int)(tape->merge_bh_size),
(unsigned int)count);
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
- actually_read))
+ if (idetape_copy_stage_to_user(tape, buf, actually_read))
ret = -EFAULT;
buf += actually_read;
- tape->merge_stage_size -= actually_read;
+ tape->merge_bh_size -= actually_read;
count -= actually_read;
}
- while (count >= tape->stage_size) {
+ while (count >= tape->buffer_size) {
bytes_read = idetape_add_chrdev_read_request(drive, ctl);
if (bytes_read <= 0)
goto finish;
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
- bytes_read))
+ if (idetape_copy_stage_to_user(tape, buf, bytes_read))
ret = -EFAULT;
buf += bytes_read;
count -= bytes_read;
@@ -2786,11 +2074,10 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
if (bytes_read <= 0)
goto finish;
temp = min((unsigned long)count, (unsigned long)bytes_read);
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
- temp))
+ if (idetape_copy_stage_to_user(tape, buf, temp))
ret = -EFAULT;
actually_read += temp;
- tape->merge_stage_size = bytes_read-temp;
+ tape->merge_bh_size = bytes_read-temp;
}
finish:
if (!actually_read && test_bit(IDETAPE_FLAG_FILEMARK, &tape->flags)) {
@@ -2821,17 +2108,17 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
/* Initialize write operation */
if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
if (tape->chrdev_dir == IDETAPE_DIR_READ)
- idetape_discard_read_pipeline(drive, 1);
- if (tape->merge_stage || tape->merge_stage_size) {
- printk(KERN_ERR "ide-tape: merge_stage_size "
+ ide_tape_discard_merge_buffer(drive, 1);
+ if (tape->merge_bh || tape->merge_bh_size) {
+ printk(KERN_ERR "ide-tape: merge_bh_size "
"should be 0 now\n");
- tape->merge_stage_size = 0;
+ tape->merge_bh_size = 0;
}
- tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
- if (!tape->merge_stage)
+ tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0);
+ if (!tape->merge_bh)
return -ENOMEM;
tape->chrdev_dir = IDETAPE_DIR_WRITE;
- idetape_init_merge_stage(tape);
+ idetape_init_merge_buffer(tape);
/*
* Issue a write 0 command to ensure that DSC handshake is
@@ -2842,10 +2129,10 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
if (drive->dsc_overlap) {
ssize_t retval = idetape_queue_rw_tail(drive,
REQ_IDETAPE_WRITE, 0,
- tape->merge_stage->bh);
+ tape->merge_bh);
if (retval < 0) {
- __idetape_kfree_stage(tape->merge_stage);
- tape->merge_stage = NULL;
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
tape->chrdev_dir = IDETAPE_DIR_NONE;
return retval;
}
@@ -2853,49 +2140,44 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
}
if (count == 0)
return (0);
- if (tape->restart_speed_control_req)
- idetape_restart_speed_control(drive);
- if (tape->merge_stage_size) {
- if (tape->merge_stage_size >= tape->stage_size) {
+ if (tape->merge_bh_size) {
+ if (tape->merge_bh_size >= tape->buffer_size) {
printk(KERN_ERR "ide-tape: bug: merge buf too big\n");
- tape->merge_stage_size = 0;
+ tape->merge_bh_size = 0;
}
actually_written = min((unsigned int)
- (tape->stage_size - tape->merge_stage_size),
+ (tape->buffer_size - tape->merge_bh_size),
(unsigned int)count);
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
- actually_written))
+ if (idetape_copy_stage_from_user(tape, buf, actually_written))
ret = -EFAULT;
buf += actually_written;
- tape->merge_stage_size += actually_written;
+ tape->merge_bh_size += actually_written;
count -= actually_written;
- if (tape->merge_stage_size == tape->stage_size) {
+ if (tape->merge_bh_size == tape->buffer_size) {
ssize_t retval;
- tape->merge_stage_size = 0;
+ tape->merge_bh_size = 0;
retval = idetape_add_chrdev_write_request(drive, ctl);
if (retval <= 0)
return (retval);
}
}
- while (count >= tape->stage_size) {
+ while (count >= tape->buffer_size) {
ssize_t retval;
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
- tape->stage_size))
+ if (idetape_copy_stage_from_user(tape, buf, tape->buffer_size))
ret = -EFAULT;
- buf += tape->stage_size;
- count -= tape->stage_size;
+ buf += tape->buffer_size;
+ count -= tape->buffer_size;
retval = idetape_add_chrdev_write_request(drive, ctl);
- actually_written += tape->stage_size;
+ actually_written += tape->buffer_size;
if (retval <= 0)
return (retval);
}
if (count) {
actually_written += count;
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
- count))
+ if (idetape_copy_stage_from_user(tape, buf, count))
ret = -EFAULT;
- tape->merge_stage_size += count;
+ tape->merge_bh_size += count;
}
return ret ? ret : actually_written;
}
@@ -2919,8 +2201,7 @@ static int idetape_write_filemark(ide_drive_t *drive)
*
* Note: MTBSF and MTBSFM are not supported when the tape doesn't support
* spacing over filemarks in the reverse direction. In this case, MTFSFM is also
- * usually not supported (it is supported in the rare case in which we crossed
- * the filemark during our read-ahead pipelined operation mode).
+ * usually not supported.
*
* The following commands are currently not supported:
*
@@ -2936,7 +2217,6 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",
mt_op, mt_count);
- /* Commands which need our pipelined read-ahead stages. */
switch (mt_op) {
case MTFSF:
case MTFSFM:
@@ -2953,7 +2233,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
case MTWEOF:
if (tape->write_prot)
return -EACCES;
- idetape_discard_read_pipeline(drive, 1);
+ ide_tape_discard_merge_buffer(drive, 1);
for (i = 0; i < mt_count; i++) {
retval = idetape_write_filemark(drive);
if (retval)
@@ -2961,12 +2241,12 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
}
return 0;
case MTREW:
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
if (idetape_rewind_tape(drive))
return -EIO;
return 0;
case MTLOAD:
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
idetape_create_load_unload_cmd(drive, &pc,
IDETAPE_LU_LOAD_MASK);
return idetape_queue_pc_tail(drive, &pc);
@@ -2981,7 +2261,7 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
if (!idetape_queue_pc_tail(drive, &pc))
tape->door_locked = DOOR_UNLOCKED;
}
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
idetape_create_load_unload_cmd(drive, &pc,
!IDETAPE_LU_LOAD_MASK);
retval = idetape_queue_pc_tail(drive, &pc);
@@ -2989,10 +2269,10 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
clear_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags);
return retval;
case MTNOP:
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
return idetape_flush_tape_buffers(drive);
case MTRETEN:
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
idetape_create_load_unload_cmd(drive, &pc,
IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
return idetape_queue_pc_tail(drive, &pc);
@@ -3014,11 +2294,11 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
set_bit(IDETAPE_FLAG_DETECT_BS, &tape->flags);
return 0;
case MTSEEK:
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
return idetape_position_tape(drive,
mt_count * tape->user_bs_factor, tape->partition, 0);
case MTSETPART:
- idetape_discard_read_pipeline(drive, 0);
+ ide_tape_discard_merge_buffer(drive, 0);
return idetape_position_tape(drive, 0, mt_count, 0);
case MTFSR:
case MTBSR:
@@ -3063,13 +2343,12 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd);
- tape->restart_speed_control_req = 1;
if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
- idetape_empty_write_pipeline(drive);
+ ide_tape_flush_merge_buffer(drive);
idetape_flush_tape_buffers(drive);
}
if (cmd == MTIOCGET || cmd == MTIOCPOS) {
- block_offset = idetape_pipeline_size(drive) /
+ block_offset = tape->merge_bh_size /
(tape->blk_size * tape->user_bs_factor);
position = idetape_read_position(drive);
if (position < 0)
@@ -3101,7 +2380,7 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
return 0;
default:
if (tape->chrdev_dir == IDETAPE_DIR_READ)
- idetape_discard_read_pipeline(drive, 1);
+ ide_tape_discard_merge_buffer(drive, 1);
return idetape_blkdev_ioctl(drive, cmd, arg);
}
}
@@ -3175,9 +2454,6 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
if (!test_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags))
(void)idetape_rewind_tape(drive);
- if (tape->chrdev_dir != IDETAPE_DIR_READ)
- clear_bit(IDETAPE_FLAG_PIPELINE_ERR, &tape->flags);
-
/* Read block size and write protect status from drive. */
ide_tape_get_bsize_from_bdesc(drive);
@@ -3206,8 +2482,6 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
}
}
}
- idetape_restart_speed_control(drive);
- tape->restart_speed_control_req = 0;
return 0;
out_put_tape:
@@ -3219,13 +2493,13 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
{
idetape_tape_t *tape = drive->driver_data;
- idetape_empty_write_pipeline(drive);
- tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
- if (tape->merge_stage != NULL) {
+ ide_tape_flush_merge_buffer(drive);
+ tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1, 0);
+ if (tape->merge_bh != NULL) {
idetape_pad_zeros(drive, tape->blk_size *
(tape->user_bs_factor - 1));
- __idetape_kfree_stage(tape->merge_stage);
- tape->merge_stage = NULL;
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
}
idetape_write_filemark(drive);
idetape_flush_tape_buffers(drive);
@@ -3248,14 +2522,9 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
idetape_write_release(drive, minor);
if (tape->chrdev_dir == IDETAPE_DIR_READ) {
if (minor < 128)
- idetape_discard_read_pipeline(drive, 1);
- else
- idetape_wait_for_pipeline(drive);
- }
- if (tape->cache_stage != NULL) {
- __idetape_kfree_stage(tape->cache_stage);
- tape->cache_stage = NULL;
+ ide_tape_discard_merge_buffer(drive, 1);
}
+
if (minor < 128 && test_bit(IDETAPE_FLAG_MEDIUM_PRESENT, &tape->flags))
(void) idetape_rewind_tape(drive);
if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
@@ -3392,33 +2661,15 @@ static void idetape_add_settings(ide_drive_t *drive)
ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
1, 2, (u16 *)&tape->caps[16], NULL);
- ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff,
- tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
- ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff,
- tape->stage_size / 1024, 1, &tape->max_stages, NULL);
- ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff,
- tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
- ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0,
- 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages,
- NULL);
- ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0,
- 0xffff, tape->stage_size / 1024, 1,
- &tape->nr_pending_stages, NULL);
ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
1, 1, (u16 *)&tape->caps[14], NULL);
- ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1,
- 1024, &tape->stage_size, NULL);
+ ide_add_setting(drive, "buffer_size", SETTING_READ, TYPE_INT, 0, 0xffff,
+ 1, 1024, &tape->buffer_size, NULL);
ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN,
IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq,
NULL);
ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
1, &drive->dsc_overlap, NULL);
- ide_add_setting(drive, "pipeline_head_speed_c", SETTING_READ, TYPE_INT,
- 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed,
- NULL);
- ide_add_setting(drive, "pipeline_head_speed_u", SETTING_READ, TYPE_INT,
- 0, 0xffff, 1, 1,
- &tape->uncontrolled_pipeline_head_speed, NULL);
ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
1, 1, &tape->avg_speed, NULL);
ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
@@ -3441,11 +2692,10 @@ static inline void idetape_add_settings(ide_drive_t *drive) { ; }
*/
static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
{
- unsigned long t1, tmid, tn, t;
+ unsigned long t;
int speed;
- int stage_size;
+ int buffer_size;
u8 gcw[2];
- struct sysinfo si;
u16 *ctl = (u16 *)&tape->caps[12];
spin_lock_init(&tape->lock);
@@ -3464,65 +2714,33 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->name[2] = '0' + minor;
tape->chrdev_dir = IDETAPE_DIR_NONE;
tape->pc = tape->pc_stack;
- tape->max_insert_speed = 10000;
- tape->speed_control = 1;
*((unsigned short *) &gcw) = drive->id->config;
/* Command packet DRQ type */
if (((gcw[0] & 0x60) >> 5) == 1)
set_bit(IDETAPE_FLAG_DRQ_INTERRUPT, &tape->flags);
- tape->min_pipeline = 10;
- tape->max_pipeline = 10;
- tape->max_stages = 10;
-
idetape_get_inquiry_results(drive);
idetape_get_mode_sense_results(drive);
ide_tape_get_bsize_from_bdesc(drive);
tape->user_bs_factor = 1;
- tape->stage_size = *ctl * tape->blk_size;
- while (tape->stage_size > 0xffff) {
+ tape->buffer_size = *ctl * tape->blk_size;
+ while (tape->buffer_size > 0xffff) {
printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
*ctl /= 2;
- tape->stage_size = *ctl * tape->blk_size;
+ tape->buffer_size = *ctl * tape->blk_size;
}
- stage_size = tape->stage_size;
- tape->pages_per_stage = stage_size / PAGE_SIZE;
- if (stage_size % PAGE_SIZE) {
- tape->pages_per_stage++;
- tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE;
+ buffer_size = tape->buffer_size;
+ tape->pages_per_buffer = buffer_size / PAGE_SIZE;
+ if (buffer_size % PAGE_SIZE) {
+ tape->pages_per_buffer++;
+ tape->excess_bh_size = PAGE_SIZE - buffer_size % PAGE_SIZE;
}
- /* Select the "best" DSC read/write polling freq and pipeline size. */
+ /* select the "best" DSC read/write polling freq */
speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
- tape->max_stages = speed * 1000 * 10 / tape->stage_size;
-
- /* Limit memory use for pipeline to 10% of physical memory */
- si_meminfo(&si);
- if (tape->max_stages * tape->stage_size >
- si.totalram * si.mem_unit / 10)
- tape->max_stages =
- si.totalram * si.mem_unit / (10 * tape->stage_size);
-
- tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
- tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
- tape->max_pipeline =
- min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
- if (tape->max_stages == 0) {
- tape->max_stages = 1;
- tape->min_pipeline = 1;
- tape->max_pipeline = 1;
- }
-
- t1 = (tape->stage_size * HZ) / (speed * 1000);
- tmid = (*(u16 *)&tape->caps[16] * 32 * HZ) / (speed * 125);
- tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000);
-
- if (tape->max_stages)
- t = tn;
- else
- t = t1;
+ t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000);
/*
* Ensure that the number we got makes sense; limit it within
@@ -3532,11 +2750,10 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
min_t(unsigned long, t, IDETAPE_DSC_RW_MAX),
IDETAPE_DSC_RW_MIN);
printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
- "%dkB pipeline, %lums tDSC%s\n",
+ "%lums tDSC%s\n",
drive->name, tape->name, *(u16 *)&tape->caps[14],
- (*(u16 *)&tape->caps[16] * 512) / tape->stage_size,
- tape->stage_size / 1024,
- tape->max_stages * tape->stage_size / 1024,
+ (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
+ tape->buffer_size / 1024,
tape->best_dsc_rw_freq * 1000 / HZ,
drive->using_dma ? ", DMA":"");
@@ -3560,7 +2777,7 @@ static void ide_tape_release(struct kref *kref)
ide_drive_t *drive = tape->drive;
struct gendisk *g = tape->disk;
- BUG_ON(tape->first_stage != NULL || tape->merge_stage_size);
+ BUG_ON(tape->merge_bh_size);
drive->dsc_overlap = 0;
drive->driver_data = NULL;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 155cc904f4eb..9a846a0cd5a4 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -33,60 +33,18 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+void ide_tf_dump(const char *s, struct ide_taskfile *tf)
{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_taskfile *tf = &task->tf;
- u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
-
- if (task->tf_flags & IDE_TFLAG_FLAGGED)
- HIHI = 0xFF;
-
#ifdef DEBUG
printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
- drive->name, tf->feature, tf->nsect, tf->lbal,
+ s, tf->feature, tf->nsect, tf->lbal,
tf->lbam, tf->lbah, tf->device, tf->command);
printk("%s: hob: nsect 0x%02x lbal 0x%02x "
"lbam 0x%02x lbah 0x%02x\n",
- drive->name, tf->hob_nsect, tf->hob_lbal,
+ s, tf->hob_nsect, tf->hob_lbal,
tf->hob_lbam, tf->hob_lbah);
#endif
-
- ide_set_irq(drive, 1);
-
- if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
- SELECT_MASK(drive, 0);
-
- if (task->tf_flags & IDE_TFLAG_OUT_DATA)
- hwif->OUTW((tf->hob_data << 8) | tf->data,
- hwif->io_ports[IDE_DATA_OFFSET]);
-
- if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
- hwif->OUTB(tf->hob_feature, hwif->io_ports[IDE_FEATURE_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
- hwif->OUTB(tf->hob_nsect, hwif->io_ports[IDE_NSECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
- hwif->OUTB(tf->hob_lbal, hwif->io_ports[IDE_SECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
- hwif->OUTB(tf->hob_lbam, hwif->io_ports[IDE_LCYL_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
- hwif->OUTB(tf->hob_lbah, hwif->io_ports[IDE_HCYL_OFFSET]);
-
- if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
- hwif->OUTB(tf->feature, hwif->io_ports[IDE_FEATURE_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
- hwif->OUTB(tf->nsect, hwif->io_ports[IDE_NSECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
- hwif->OUTB(tf->lbal, hwif->io_ports[IDE_SECTOR_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
- hwif->OUTB(tf->lbam, hwif->io_ports[IDE_LCYL_OFFSET]);
- if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
- hwif->OUTB(tf->lbah, hwif->io_ports[IDE_HCYL_OFFSET]);
-
- if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
- hwif->OUTB((tf->device & HIHI) | drive->select.all,
- hwif->io_ports[IDE_SELECT_OFFSET]);
}
int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
@@ -135,6 +93,7 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
ide_hwif_t *hwif = HWIF(drive);
struct ide_taskfile *tf = &task->tf;
ide_handler_t *handler = NULL;
+ const struct ide_dma_ops *dma_ops = hwif->dma_ops;
if (task->data_phase == TASKFILE_MULTI_IN ||
task->data_phase == TASKFILE_MULTI_OUT) {
@@ -148,14 +107,15 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
if (task->tf_flags & IDE_TFLAG_FLAGGED)
task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
- if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0)
- ide_tf_load(drive, task);
+ if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
+ ide_tf_dump(drive->name, tf);
+ hwif->tf_load(drive, task);
+ }
switch (task->data_phase) {
case TASKFILE_MULTI_OUT:
case TASKFILE_OUT:
- hwif->OUTBSYNC(drive, tf->command,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, tf->command, hwif->io_ports.command_addr);
ndelay(400); /* FIXME */
return pre_task_out_intr(drive, task->rq);
case TASKFILE_MULTI_IN:
@@ -178,10 +138,10 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
return ide_started;
default:
if (task_dma_ok(task) == 0 || drive->using_dma == 0 ||
- hwif->dma_setup(drive))
+ dma_ops->dma_setup(drive))
return ide_stopped;
- hwif->dma_exec_cmd(drive, tf->command);
- hwif->dma_start(drive);
+ dma_ops->dma_exec_cmd(drive, tf->command);
+ dma_ops->dma_start(drive);
return ide_started;
}
}
@@ -283,7 +243,8 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
return stat;
}
-static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
+static void ide_pio_sector(ide_drive_t *drive, struct request *rq,
+ unsigned int write)
{
ide_hwif_t *hwif = drive->hwif;
struct scatterlist *sg = hwif->sg_table;
@@ -323,9 +284,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
/* do the actual data transfer */
if (write)
- hwif->ata_output_data(drive, buf, SECTOR_WORDS);
+ hwif->output_data(drive, rq, buf, SECTOR_SIZE);
else
- hwif->ata_input_data(drive, buf, SECTOR_WORDS);
+ hwif->input_data(drive, rq, buf, SECTOR_SIZE);
kunmap_atomic(buf, KM_BIO_SRC_IRQ);
#ifdef CONFIG_HIGHMEM
@@ -333,13 +294,14 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
#endif
}
-static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
+static void ide_pio_multi(ide_drive_t *drive, struct request *rq,
+ unsigned int write)
{
unsigned int nsect;
nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
while (nsect--)
- ide_pio_sector(drive, write);
+ ide_pio_sector(drive, rq, write);
}
static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
@@ -362,10 +324,10 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
switch (drive->hwif->data_phase) {
case TASKFILE_MULTI_IN:
case TASKFILE_MULTI_OUT:
- ide_pio_multi(drive, write);
+ ide_pio_multi(drive, rq, write);
break;
default:
- ide_pio_sector(drive, write);
+ ide_pio_sector(drive, rq, write);
break;
}
@@ -455,7 +417,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive)
/* Error? */
if (stat & ERR_STAT)
- return task_error(drive, rq, __FUNCTION__, stat);
+ return task_error(drive, rq, __func__, stat);
/* Didn't want any data? Odd. */
if (!(stat & DRQ_STAT))
@@ -467,7 +429,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive)
if (!hwif->nleft) {
stat = wait_drive_not_busy(drive);
if (!OK_STAT(stat, 0, BAD_STAT))
- return task_error(drive, rq, __FUNCTION__, stat);
+ return task_error(drive, rq, __func__, stat);
task_end_request(drive, rq, stat);
return ide_stopped;
}
@@ -488,11 +450,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
u8 stat = ide_read_status(drive);
if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
- return task_error(drive, rq, __FUNCTION__, stat);
+ return task_error(drive, rq, __func__, stat);
/* Deal with unexpected ATA data phase. */
if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
- return task_error(drive, rq, __FUNCTION__, stat);
+ return task_error(drive, rq, __func__, stat);
if (!hwif->nleft) {
task_end_request(drive, rq, stat);
@@ -675,7 +637,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
/* (hs): give up if multcount is not set */
printk(KERN_ERR "%s: %s Multimode Write " \
"multcount is not set\n",
- drive->name, __FUNCTION__);
+ drive->name, __func__);
err = -EPERM;
goto abort;
}
@@ -692,7 +654,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
/* (hs): give up if multcount is not set */
printk(KERN_ERR "%s: %s Multimode Read failure " \
"multcount is not set\n",
- drive->name, __FUNCTION__);
+ drive->name, __func__);
err = -EPERM;
goto abort;
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 917c72dcd33d..999584c03d97 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -94,19 +94,8 @@ DEFINE_MUTEX(ide_cfg_mtx);
int noautodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEACPI
-int ide_noacpi = 0;
-int ide_noacpitfs = 1;
-int ide_noacpionboot = 1;
-#endif
-
-/*
- * This is declared extern in ide.h, for access by other IDE modules:
- */
ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
-EXPORT_SYMBOL(ide_hwifs);
-
static void ide_port_init_devices_data(ide_hwif_t *);
/*
@@ -232,117 +221,6 @@ static int ide_system_bus_speed(void)
return pci_dev_present(pci_default) ? 33 : 50;
}
-ide_hwif_t * ide_find_port(unsigned long base)
-{
- ide_hwif_t *hwif;
- int i;
-
- for (i = 0; i < MAX_HWIFS; i++) {
- hwif = &ide_hwifs[i];
- if (hwif->io_ports[IDE_DATA_OFFSET] == base)
- goto found;
- }
-
- for (i = 0; i < MAX_HWIFS; i++) {
- hwif = &ide_hwifs[i];
- if (hwif->chipset == ide_unknown)
- goto found;
- }
-
- hwif = NULL;
-found:
- return hwif;
-}
-
-EXPORT_SYMBOL_GPL(ide_find_port);
-
-static struct resource* hwif_request_region(ide_hwif_t *hwif,
- unsigned long addr, int num)
-{
- struct resource *res = request_region(addr, num, hwif->name);
-
- if (!res)
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
- hwif->name, addr, addr+num-1);
- return res;
-}
-
-/**
- * ide_hwif_request_regions - request resources for IDE
- * @hwif: interface to use
- *
- * Requests all the needed resources for an interface.
- * Right now core IDE code does this work which is deeply wrong.
- * MMIO leaves it to the controller driver,
- * PIO will migrate this way over time.
- */
-
-int ide_hwif_request_regions(ide_hwif_t *hwif)
-{
- unsigned long addr;
- unsigned int i;
-
- if (hwif->mmio)
- return 0;
- addr = hwif->io_ports[IDE_CONTROL_OFFSET];
- if (addr && !hwif_request_region(hwif, addr, 1))
- goto control_region_busy;
- hwif->straight8 = 0;
- addr = hwif->io_ports[IDE_DATA_OFFSET];
- if ((addr | 7) == hwif->io_ports[IDE_STATUS_OFFSET]) {
- if (!hwif_request_region(hwif, addr, 8))
- goto data_region_busy;
- hwif->straight8 = 1;
- return 0;
- }
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- addr = hwif->io_ports[i];
- if (!hwif_request_region(hwif, addr, 1)) {
- while (--i)
- release_region(addr, 1);
- goto data_region_busy;
- }
- }
- return 0;
-
-data_region_busy:
- addr = hwif->io_ports[IDE_CONTROL_OFFSET];
- if (addr)
- release_region(addr, 1);
-control_region_busy:
- /* If any errors are return, we drop the hwif interface. */
- return -EBUSY;
-}
-
-/**
- * ide_hwif_release_regions - free IDE resources
- *
- * Note that we only release the standard ports,
- * and do not even try to handle any extra ports
- * allocated for weird IDE interface chipsets.
- *
- * Note also that we don't yet handle mmio resources here. More
- * importantly our caller should be doing this so we need to
- * restructure this as a helper function for drivers.
- */
-
-void ide_hwif_release_regions(ide_hwif_t *hwif)
-{
- u32 i = 0;
-
- if (hwif->mmio)
- return;
- if (hwif->io_ports[IDE_CONTROL_OFFSET])
- release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
- if (hwif->straight8) {
- release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
- return;
- }
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- if (hwif->io_ports[i])
- release_region(hwif->io_ports[i], 1);
-}
-
void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
{
ide_hwgroup_t *hwgroup = hwif->hwgroup;
@@ -409,7 +287,7 @@ EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
/**
* ide_unregister - free an IDE interface
- * @index: index of interface (will change soon to a pointer)
+ * @hwif: IDE interface
*
* Perform the final unregister of an IDE interface. At the moment
* we don't refcount interfaces so this will also get split up.
@@ -429,19 +307,16 @@ EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
* This is raving bonkers.
*/
-void ide_unregister(unsigned int index)
+void ide_unregister(ide_hwif_t *hwif)
{
- ide_hwif_t *hwif, *g;
+ ide_hwif_t *g;
ide_hwgroup_t *hwgroup;
int irq_count = 0;
- BUG_ON(index >= MAX_HWIFS);
-
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
mutex_lock(&ide_cfg_mtx);
spin_lock_irq(&ide_lock);
- hwif = &ide_hwifs[index];
if (!hwif->present)
goto abort;
__ide_port_unregister_devices(hwif);
@@ -479,12 +354,10 @@ void ide_unregister(unsigned int index)
spin_lock_irq(&ide_lock);
if (hwif->dma_base)
- (void)ide_release_dma(hwif);
-
- ide_hwif_release_regions(hwif);
+ ide_release_dma_engine(hwif);
/* restore hwif data to pristine status */
- ide_init_port_data(hwif, index);
+ ide_init_port_data(hwif, hwif->index);
abort:
spin_unlock_irq(&ide_lock);
@@ -495,9 +368,8 @@ EXPORT_SYMBOL(ide_unregister);
void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
{
- memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
+ memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
hwif->irq = hw->irq;
- hwif->noprobe = 0;
hwif->chipset = hw->chipset;
hwif->gendev.parent = hw->dev;
hwif->ack_intr = hw->ack_intr;
@@ -588,7 +460,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
if (!drive->id || !(drive->id->capability & 1))
goto out;
- if (hwif->dma_host_set == NULL)
+ if (hwif->dma_ops == NULL)
goto out;
err = -EBUSY;
@@ -627,11 +499,14 @@ out:
int set_pio_mode(ide_drive_t *drive, int arg)
{
struct request rq;
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
if (arg < 0 || arg > 255)
return -EINVAL;
- if (drive->hwif->set_pio_mode == NULL)
+ if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
+ (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
return -ENOSYS;
if (drive->special.b.set_tune)
@@ -953,16 +828,6 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
return 0; /* zero = nothing matched */
}
-extern int probe_ali14xx;
-extern int probe_umc8672;
-extern int probe_dtc2278;
-extern int probe_ht6560b;
-extern int probe_qd65xx;
-extern int cmd640_vlb;
-extern int probe_4drives;
-
-static int __initdata is_chipset_set;
-
/*
* ide_setup() gets called VERY EARLY during initialization,
* to handle kernel "command line" strings beginning with "hdx=" or "ide".
@@ -971,14 +836,12 @@ static int __initdata is_chipset_set;
*/
static int __init ide_setup(char *s)
{
- int i, vals[3];
ide_hwif_t *hwif;
ide_drive_t *drive;
unsigned int hw, unit;
+ int vals[3];
const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
- const char max_hwif = '0' + (MAX_HWIFS - 1);
-
if (strncmp(s,"hd",2) == 0 && s[2] == '=') /* hd= is for hd.c */
return 0; /* driver and not us */
@@ -994,7 +857,7 @@ static int __init ide_setup(char *s)
printk(" : Enabled support for IDE doublers\n");
ide_doubler = 1;
- return 1;
+ goto obsolete_option;
}
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
@@ -1008,17 +871,17 @@ static int __init ide_setup(char *s)
if (!strcmp(s, "ide=noacpi")) {
//printk(" : Disable IDE ACPI support.\n");
ide_noacpi = 1;
- return 1;
+ goto obsolete_option;
}
if (!strcmp(s, "ide=acpigtf")) {
//printk(" : Enable IDE ACPI _GTF support.\n");
- ide_noacpitfs = 0;
- return 1;
+ ide_acpigtf = 1;
+ goto obsolete_option;
}
if (!strcmp(s, "ide=acpionboot")) {
//printk(" : Call IDE ACPI methods on boot.\n");
- ide_noacpionboot = 0;
- return 1;
+ ide_acpionboot = 1;
+ goto obsolete_option;
}
#endif /* CONFIG_BLK_DEV_IDEACPI */
@@ -1028,7 +891,7 @@ static int __init ide_setup(char *s)
if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {
"none", "noprobe", "nowerr", "cdrom", "nodma",
- "autotune", "noautotune", "-8", "-9", "-10",
+ "-6", "-7", "-8", "-9", "-10",
"noflush", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
@@ -1043,30 +906,22 @@ static int __init ide_setup(char *s)
case -1: /* "none" */
case -2: /* "noprobe" */
drive->noprobe = 1;
- goto done;
+ goto obsolete_option;
case -3: /* "nowerr" */
drive->bad_wstat = BAD_R_STAT;
- hwif->noprobe = 0;
- goto done;
+ goto obsolete_option;
case -4: /* "cdrom" */
drive->present = 1;
drive->media = ide_cdrom;
/* an ATAPI device ignores DRDY */
drive->ready_stat = 0;
- hwif->noprobe = 0;
- goto done;
+ goto obsolete_option;
case -5: /* nodma */
drive->nodma = 1;
- goto done;
- case -6: /* "autotune" */
- drive->autotune = IDE_TUNE_AUTO;
- goto obsolete_option;
- case -7: /* "noautotune" */
- drive->autotune = IDE_TUNE_NOAUTO;
goto obsolete_option;
case -11: /* noflush */
drive->noflush = 1;
- goto done;
+ goto obsolete_option;
case -12: /* "remap" */
drive->remap_0_to_1 = 1;
goto obsolete_option;
@@ -1084,8 +939,7 @@ static int __init ide_setup(char *s)
drive->sect = drive->bios_sect = vals[2];
drive->present = 1;
drive->forced_geom = 1;
- hwif->noprobe = 0;
- goto done;
+ goto obsolete_option;
default:
goto bad_option;
}
@@ -1103,126 +957,15 @@ static int __init ide_setup(char *s)
idebus_parameter = vals[0];
} else
printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
- goto done;
+ goto obsolete_option;
}
- /*
- * Look for interface options: "idex="
- */
- if (s[3] >= '0' && s[3] <= max_hwif) {
- /*
- * Be VERY CAREFUL changing this: note hardcoded indexes below
- * (-8, -9, -10) are reserved to ease the hardcoding.
- */
- static const char *ide_words[] = {
- "minus1", "serialize", "minus3", "minus4",
- "reset", "minus6", "ata66", "minus8", "minus9",
- "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
- "dtc2278", "umc8672", "ali14xx", NULL };
-
- hw = s[3] - '0';
- hwif = &ide_hwifs[hw];
- i = match_parm(&s[4], ide_words, vals, 3);
- /*
- * Cryptic check to ensure chipset not already set for hwif.
- * Note: we can't depend on hwif->chipset here.
- */
- if (i >= -18 && i <= -11) {
- /* chipset already specified */
- if (is_chipset_set)
- goto bad_option;
- /* these drivers are for "ide0=" only */
- if (hw != 0)
- goto bad_hwif;
- is_chipset_set = 1;
- printk("\n");
- }
-
- switch (i) {
-#ifdef CONFIG_BLK_DEV_ALI14XX
- case -17: /* "ali14xx" */
- probe_ali14xx = 1;
- goto obsolete_option;
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
- case -16: /* "umc8672" */
- probe_umc8672 = 1;
- goto obsolete_option;
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
- case -15: /* "dtc2278" */
- probe_dtc2278 = 1;
- goto obsolete_option;
-#endif
-#ifdef CONFIG_BLK_DEV_CMD640
- case -14: /* "cmd640_vlb" */
- cmd640_vlb = 1;
- goto obsolete_option;
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
- case -13: /* "ht6560b" */
- probe_ht6560b = 1;
- goto obsolete_option;
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
- case -12: /* "qd65xx" */
- probe_qd65xx = 1;
- goto obsolete_option;
-#endif
-#ifdef CONFIG_BLK_DEV_4DRIVES
- case -11: /* "four" drives on one set of ports */
- probe_4drives = 1;
- goto obsolete_option;
-#endif
- case -10: /* minus10 */
- case -9: /* minus9 */
- case -8: /* minus8 */
- case -6:
- case -4:
- case -3:
- goto bad_option;
- case -7: /* ata66 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
- /*
- * Use ATA_CBL_PATA40_SHORT so drive side
- * cable detection is also overriden.
- */
- hwif->cbl = ATA_CBL_PATA40_SHORT;
- goto obsolete_option;
-#else
- goto bad_hwif;
-#endif
- case -5: /* "reset" */
- hwif->reset = 1;
- goto obsolete_option;
- case -2: /* "serialize" */
- hwif->mate = &ide_hwifs[hw^1];
- hwif->mate->mate = hwif;
- hwif->serialized = hwif->mate->serialized = 1;
- goto obsolete_option;
-
- case -1:
- case 0:
- case 1:
- case 2:
- case 3:
- goto bad_option;
- default:
- printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
- return 1;
- }
- }
bad_option:
printk(" -- BAD OPTION\n");
return 1;
obsolete_option:
printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n");
return 1;
-bad_hwif:
- printk("-- NOT SUPPORTED ON ide%d", hw);
-done:
- printk("\n");
- return 1;
}
EXPORT_SYMBOL(ide_lock);
@@ -1358,6 +1101,185 @@ static void ide_port_class_release(struct device *portdev)
put_device(&hwif->gendev);
}
+int ide_vlb_clk;
+EXPORT_SYMBOL_GPL(ide_vlb_clk);
+
+module_param_named(vlb_clock, ide_vlb_clk, int, 0);
+MODULE_PARM_DESC(vlb_clock, "VLB clock frequency (in MHz)");
+
+int ide_pci_clk;
+EXPORT_SYMBOL_GPL(ide_pci_clk);
+
+module_param_named(pci_clock, ide_pci_clk, int, 0);
+MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
+
+static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
+{
+ int a, b, i, j = 1;
+ unsigned int *dev_param_mask = (unsigned int *)kp->arg;
+
+ if (sscanf(s, "%d.%d:%d", &a, &b, &j) != 3 &&
+ sscanf(s, "%d.%d", &a, &b) != 2)
+ return -EINVAL;
+
+ i = a * MAX_DRIVES + b;
+
+ if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1)
+ return -EINVAL;
+
+ if (j)
+ *dev_param_mask |= (1 << i);
+ else
+ *dev_param_mask &= (1 << i);
+
+ return 0;
+}
+
+static unsigned int ide_nodma;
+
+module_param_call(nodma, ide_set_dev_param_mask, NULL, &ide_nodma, 0);
+MODULE_PARM_DESC(nodma, "disallow DMA for a device");
+
+static unsigned int ide_noflush;
+
+module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0);
+MODULE_PARM_DESC(noflush, "disable flush requests for a device");
+
+static unsigned int ide_noprobe;
+
+module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0);
+MODULE_PARM_DESC(noprobe, "skip probing for a device");
+
+static unsigned int ide_nowerr;
+
+module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0);
+MODULE_PARM_DESC(nowerr, "ignore the WRERR_STAT bit for a device");
+
+static unsigned int ide_cdroms;
+
+module_param_call(cdrom, ide_set_dev_param_mask, NULL, &ide_cdroms, 0);
+MODULE_PARM_DESC(cdrom, "force device as a CD-ROM");
+
+struct chs_geom {
+ unsigned int cyl;
+ u8 head;
+ u8 sect;
+};
+
+static unsigned int ide_disks;
+static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES];
+
+static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
+{
+ int a, b, c = 0, h = 0, s = 0, i, j = 1;
+
+ if (sscanf(str, "%d.%d:%d,%d,%d", &a, &b, &c, &h, &s) != 5 &&
+ sscanf(str, "%d.%d:%d", &a, &b, &j) != 3)
+ return -EINVAL;
+
+ i = a * MAX_DRIVES + b;
+
+ if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1)
+ return -EINVAL;
+
+ if (c > INT_MAX || h > 255 || s > 255)
+ return -EINVAL;
+
+ if (j)
+ ide_disks |= (1 << i);
+ else
+ ide_disks &= (1 << i);
+
+ ide_disks_chs[i].cyl = c;
+ ide_disks_chs[i].head = h;
+ ide_disks_chs[i].sect = s;
+
+ return 0;
+}
+
+module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0);
+MODULE_PARM_DESC(chs, "force device as a disk (using CHS)");
+
+static void ide_dev_apply_params(ide_drive_t *drive)
+{
+ int i = drive->hwif->index * MAX_DRIVES + drive->select.b.unit;
+
+ if (ide_nodma & (1 << i)) {
+ printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name);
+ drive->nodma = 1;
+ }
+ if (ide_noflush & (1 << i)) {
+ printk(KERN_INFO "ide: disabling flush requests for %s\n",
+ drive->name);
+ drive->noflush = 1;
+ }
+ if (ide_noprobe & (1 << i)) {
+ printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
+ drive->noprobe = 1;
+ }
+ if (ide_nowerr & (1 << i)) {
+ printk(KERN_INFO "ide: ignoring the WRERR_STAT bit for %s\n",
+ drive->name);
+ drive->bad_wstat = BAD_R_STAT;
+ }
+ if (ide_cdroms & (1 << i)) {
+ printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name);
+ drive->present = 1;
+ drive->media = ide_cdrom;
+ /* an ATAPI device ignores DRDY */
+ drive->ready_stat = 0;
+ }
+ if (ide_disks & (1 << i)) {
+ drive->cyl = drive->bios_cyl = ide_disks_chs[i].cyl;
+ drive->head = drive->bios_head = ide_disks_chs[i].head;
+ drive->sect = drive->bios_sect = ide_disks_chs[i].sect;
+ drive->forced_geom = 1;
+ printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n",
+ drive->name,
+ drive->cyl, drive->head, drive->sect);
+ drive->present = 1;
+ drive->media = ide_disk;
+ drive->ready_stat = READY_STAT;
+ }
+}
+
+static unsigned int ide_ignore_cable;
+
+static int ide_set_ignore_cable(const char *s, struct kernel_param *kp)
+{
+ int i, j = 1;
+
+ if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1)
+ return -EINVAL;
+
+ if (i >= MAX_HWIFS || j < 0 || j > 1)
+ return -EINVAL;
+
+ if (j)
+ ide_ignore_cable |= (1 << i);
+ else
+ ide_ignore_cable &= (1 << i);
+
+ return 0;
+}
+
+module_param_call(ignore_cable, ide_set_ignore_cable, NULL, NULL, 0);
+MODULE_PARM_DESC(ignore_cable, "ignore cable detection");
+
+void ide_port_apply_params(ide_hwif_t *hwif)
+{
+ int i;
+
+ if (ide_ignore_cable & (1 << hwif->index)) {
+ printk(KERN_INFO "ide: ignoring cable detection for %s\n",
+ hwif->name);
+ hwif->cbl = ATA_CBL_PATA40_SHORT;
+ }
+
+ for (i = 0; i < MAX_DRIVES; i++)
+ ide_dev_apply_params(&hwif->drives[i]);
+}
+
/*
* This is gets invoked once during initialization, to set *everything* up
*/
@@ -1424,11 +1346,6 @@ int __init init_module (void)
void __exit cleanup_module (void)
{
- int index;
-
- for (index = 0; index < MAX_HWIFS; ++index)
- ide_unregister(index);
-
proc_ide_destroy();
class_destroy(ide_port_class);
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index bc8b1f8de614..90c65cf97448 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -49,6 +49,8 @@
#include <asm/io.h>
+#define DRV_NAME "ali14xx"
+
/* port addresses for auto-detection */
#define ALI_NUM_PORTS 4
static const int ports[ALI_NUM_PORTS] __initdata =
@@ -86,7 +88,7 @@ static u8 regOff; /* output to base port to close registers */
/*
* Read a controller register.
*/
-static inline u8 inReg (u8 reg)
+static inline u8 inReg(u8 reg)
{
outb_p(reg, regPort);
return inb(dataPort);
@@ -95,7 +97,7 @@ static inline u8 inReg (u8 reg)
/*
* Write a controller register.
*/
-static void outReg (u8 data, u8 reg)
+static void outReg(u8 data, u8 reg)
{
outb_p(reg, regPort);
outb_p(data, dataPort);
@@ -114,7 +116,7 @@ static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
int time1, time2;
u8 param1, param2, param3, param4;
unsigned long flags;
- int bus_speed = system_bus_clock();
+ int bus_speed = ide_vlb_clk ? ide_vlb_clk : system_bus_clock();
/* calculate timing, according to PIO mode */
time1 = ide_pio_cycle_time(drive, pio);
@@ -143,7 +145,7 @@ static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
/*
* Auto-detect the IDE controller port.
*/
-static int __init findPort (void)
+static int __init findPort(void)
{
int i;
u8 t;
@@ -175,7 +177,8 @@ static int __init findPort (void)
/*
* Initialize controller registers with default values.
*/
-static int __init initRegisters (void) {
+static int __init initRegisters(void)
+{
const RegInitializer *p;
u8 t;
unsigned long flags;
@@ -191,17 +194,20 @@ static int __init initRegisters (void) {
return t;
}
+static const struct ide_port_ops ali14xx_port_ops = {
+ .set_pio_mode = ali14xx_set_pio_mode,
+};
+
static const struct ide_port_info ali14xx_port_info = {
+ .name = DRV_NAME,
.chipset = ide_ali14xx,
- .host_flags = IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE,
+ .port_ops = &ali14xx_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
.pio_mask = ATA_PIO4,
};
static int __init ali14xx_probe(void)
{
- static u8 idx[4] = { 0, 1, 0xff, 0xff };
- hw_regs_t hw[2];
-
printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
basePort, regOn);
@@ -211,26 +217,10 @@ static int __init ali14xx_probe(void)
return 1;
}
- memset(&hw, 0, sizeof(hw));
-
- ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
- hw[0].irq = 14;
-
- ide_std_init_ports(&hw[1], 0x170, 0x376);
- hw[1].irq = 15;
-
- ide_init_port_hw(&ide_hwifs[0], &hw[0]);
- ide_init_port_hw(&ide_hwifs[1], &hw[1]);
-
- ide_hwifs[0].set_pio_mode = &ali14xx_set_pio_mode;
- ide_hwifs[1].set_pio_mode = &ali14xx_set_pio_mode;
-
- ide_device_add(idx, &ali14xx_port_info);
-
- return 0;
+ return ide_legacy_device_add(&ali14xx_port_info, 0);
}
-int probe_ali14xx = 0;
+static int probe_ali14xx;
module_param_named(probe, probe_ali14xx, bool, 0);
MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index fdd3791e465f..5c730e4dd735 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -102,7 +102,7 @@ static int buddha_ack_intr(ide_hwif_t *hwif)
{
unsigned char ch;
- ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+ ch = z_readb(hwif->io_ports.irq_addr);
if (!(ch & 0x80))
return 0;
return 1;
@@ -112,9 +112,9 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
{
unsigned char ch;
- ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+ ch = z_readb(hwif->io_ports.irq_addr);
/* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
- z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]);
+ z_writeb(0, hwif->io_ports.irq_addr);
if (!(ch & 0x80))
return 0;
return 1;
@@ -128,13 +128,13 @@ static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
memset(hw, 0, sizeof(*hw));
- hw->io_ports[IDE_DATA_OFFSET] = base;
+ hw->io_ports.data_addr = base;
for (i = 1; i < 8; i++)
- hw->io_ports[i] = base + 2 + i * 4;
+ hw->io_ports_array[i] = base + 2 + i * 4;
- hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
- hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+ hw->io_ports.ctl_addr = ctl;
+ hw->io_ports.irq_addr = irq_port;
hw->irq = IRQ_AMIGA_PORTS;
hw->ack_intr = ack_intr;
@@ -221,15 +221,13 @@ fail_base2:
buddha_setup_ports(&hw, base, ctl, irq_port, ack_intr);
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif) {
u8 index = hwif->index;
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
- hwif->mmio = 1;
-
idx[i] = index;
}
}
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 5f69cd2ea6f7..af791a02a120 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -16,6 +16,8 @@
#include <asm/io.h>
+#define DRV_NAME "dtc2278"
+
/*
* Changing this #undef to #define may solve start up problems in some systems.
*/
@@ -86,30 +88,26 @@ static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
}
}
+static const struct ide_port_ops dtc2278_port_ops = {
+ .set_pio_mode = dtc2278_set_pio_mode,
+};
+
static const struct ide_port_info dtc2278_port_info __initdata = {
+ .name = DRV_NAME,
.chipset = ide_dtc2278,
+ .port_ops = &dtc2278_port_ops,
.host_flags = IDE_HFLAG_SERIALIZE |
IDE_HFLAG_NO_UNMASK_IRQS |
IDE_HFLAG_IO_32BIT |
/* disallow ->io_32bit changes */
IDE_HFLAG_NO_IO_32BIT |
- IDE_HFLAG_NO_DMA |
- IDE_HFLAG_NO_AUTOTUNE,
+ IDE_HFLAG_NO_DMA,
.pio_mask = ATA_PIO4,
};
static int __init dtc2278_probe(void)
{
unsigned long flags;
- ide_hwif_t *hwif, *mate;
- static u8 idx[4] = { 0, 1, 0xff, 0xff };
- hw_regs_t hw[2];
-
- hwif = &ide_hwifs[0];
- mate = &ide_hwifs[1];
-
- if (hwif->chipset != ide_unknown || mate->chipset != ide_unknown)
- return 1;
local_irq_save(flags);
/*
@@ -129,25 +127,10 @@ static int __init dtc2278_probe(void)
#endif
local_irq_restore(flags);
- memset(&hw, 0, sizeof(hw));
-
- ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
- hw[0].irq = 14;
-
- ide_std_init_ports(&hw[1], 0x170, 0x376);
- hw[1].irq = 15;
-
- ide_init_port_hw(hwif, &hw[0]);
- ide_init_port_hw(mate, &hw[1]);
-
- hwif->set_pio_mode = &dtc2278_set_pio_mode;
-
- ide_device_add(idx, &dtc2278_port_info);
-
- return 0;
+ return ide_legacy_device_add(&dtc2278_port_info, 0);
}
-int probe_dtc2278 = 0;
+static int probe_dtc2278;
module_param_named(probe, probe_dtc2278, bool, 0);
MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index e950afa5939c..83555ca513b5 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -22,6 +22,7 @@
#include <asm/atariints.h>
#include <asm/atari_stdma.h>
+#define DRV_NAME "falconide"
/*
* Base of the IDE interface
@@ -43,18 +44,40 @@
int falconide_intr_lock;
EXPORT_SYMBOL(falconide_intr_lock);
+static void falconide_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return insw(data_addr, buf, (len + 1) / 2);
+
+ insw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
+static void falconide_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return outsw(data_adr, buf, (len + 1) / 2);
+
+ outsw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
static void __init falconide_setup_ports(hw_regs_t *hw)
{
int i;
memset(hw, 0, sizeof(*hw));
- hw->io_ports[IDE_DATA_OFFSET] = ATA_HD_BASE;
+ hw->io_ports.data_addr = ATA_HD_BASE;
for (i = 1; i < 8; i++)
- hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4;
+ hw->io_ports_array[i] = ATA_HD_BASE + 1 + i * 4;
- hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_BASE + ATA_HD_CONTROL;
+ hw->io_ports.ctl_addr = ATA_HD_BASE + ATA_HD_CONTROL;
hw->irq = IRQ_MFP_IDE;
hw->ack_intr = NULL;
@@ -74,9 +97,14 @@ static int __init falconide_init(void)
printk(KERN_INFO "ide: Falcon IDE controller\n");
+ if (!request_mem_region(ATA_HD_BASE, 0x40, DRV_NAME)) {
+ printk(KERN_ERR "%s: resources busy\n", DRV_NAME);
+ return -EBUSY;
+ }
+
falconide_setup_ports(&hw);
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif) {
u8 index = hwif->index;
u8 idx[4] = { index, 0xff, 0xff, 0xff };
@@ -84,6 +112,10 @@ static int __init falconide_init(void)
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
+ /* Atari has a byte-swapped IDE interface */
+ hwif->input_data = falconide_input_data;
+ hwif->output_data = falconide_output_data;
+
ide_get_lock(NULL, NULL);
ide_device_add(idx, NULL);
ide_release_lock();
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index e3b4638cc883..a9c2593a898c 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -63,6 +63,8 @@
#define GAYLE_HAS_CONTROL_REG (!ide_doubler)
#define GAYLE_IDEREG_SIZE (ide_doubler ? 0x1000 : 0x2000)
int ide_doubler = 0; /* support IDE doublers? */
+module_param_named(doubler, ide_doubler, bool, 0);
+MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
@@ -74,7 +76,7 @@ static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
{
unsigned char ch;
- ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+ ch = z_readb(hwif->io_ports.irq_addr);
if (!(ch & GAYLE_IRQ_IDE))
return 0;
return 1;
@@ -84,11 +86,11 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
{
unsigned char ch;
- ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+ ch = z_readb(hwif->io_ports.irq_addr);
if (!(ch & GAYLE_IRQ_IDE))
return 0;
- (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
- z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+ (void)z_readb(hwif->io_ports.status_addr);
+ z_writeb(0x7c, hwif->io_ports.irq_addr);
return 1;
}
@@ -100,13 +102,13 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
memset(hw, 0, sizeof(*hw));
- hw->io_ports[IDE_DATA_OFFSET] = base;
+ hw->io_ports.data_addr = base;
for (i = 1; i < 8; i++)
- hw->io_ports[i] = base + 2 + i * 4;
+ hw->io_ports_array[i] = base + 2 + i * 4;
- hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
- hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+ hw->io_ports.ctl_addr = ctl;
+ hw->io_ports.irq_addr = irq_port;
hw->irq = IRQ_AMIGA_PORTS;
hw->ack_intr = ack_intr;
@@ -175,15 +177,13 @@ found:
gayle_setup_ports(&hw, base, ctrlport, irqport, ack_intr);
- hwif = ide_find_port(base);
+ hwif = ide_find_port();
if (hwif) {
u8 index = hwif->index;
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
- hwif->mmio = 1;
-
idx[i] = index;
} else
release_mem_region(res_start, res_n);
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 0b0d86731927..abdedf56643e 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -122,12 +122,12 @@ static int hd_error;
* This struct defines the HD's and their types.
*/
struct hd_i_struct {
- unsigned int head,sect,cyl,wpcom,lzone,ctl;
+ unsigned int head, sect, cyl, wpcom, lzone, ctl;
int unit;
int recalibrate;
int special_op;
};
-
+
#ifdef HD_TYPE
static struct hd_i_struct hd_info[] = { HD_TYPE };
static int NR_HD = ARRAY_SIZE(hd_info);
@@ -168,7 +168,7 @@ unsigned long read_timer(void)
spin_lock_irqsave(&i8253_lock, flags);
t = jiffies * 11932;
- outb_p(0, 0x43);
+ outb_p(0, 0x43);
i = inb_p(0x40);
i |= inb(0x40) << 8;
spin_unlock_irqrestore(&i8253_lock, flags);
@@ -183,7 +183,7 @@ static void __init hd_setup(char *str, int *ints)
if (ints[0] != 3)
return;
if (hd_info[0].head != 0)
- hdind=1;
+ hdind = 1;
hd_info[hdind].head = ints[2];
hd_info[hdind].sect = ints[3];
hd_info[hdind].cyl = ints[1];
@@ -193,7 +193,7 @@ static void __init hd_setup(char *str, int *ints)
NR_HD = hdind+1;
}
-static void dump_status (const char *msg, unsigned int stat)
+static void dump_status(const char *msg, unsigned int stat)
{
char *name = "hd?";
if (CURRENT)
@@ -291,7 +291,6 @@ static int controller_ready(unsigned int drive, unsigned int head)
return 0;
}
-
static void hd_out(struct hd_i_struct *disk,
unsigned int nsect,
unsigned int sect,
@@ -313,15 +312,15 @@ static void hd_out(struct hd_i_struct *disk,
return;
}
SET_HANDLER(intr_addr);
- outb_p(disk->ctl,HD_CMD);
- port=HD_DATA;
- outb_p(disk->wpcom>>2,++port);
- outb_p(nsect,++port);
- outb_p(sect,++port);
- outb_p(cyl,++port);
- outb_p(cyl>>8,++port);
- outb_p(0xA0|(disk->unit<<4)|head,++port);
- outb_p(cmd,++port);
+ outb_p(disk->ctl, HD_CMD);
+ port = HD_DATA;
+ outb_p(disk->wpcom >> 2, ++port);
+ outb_p(nsect, ++port);
+ outb_p(sect, ++port);
+ outb_p(cyl, ++port);
+ outb_p(cyl >> 8, ++port);
+ outb_p(0xA0 | (disk->unit << 4) | head, ++port);
+ outb_p(cmd, ++port);
}
static void hd_request (void);
@@ -344,14 +343,14 @@ static void reset_controller(void)
{
int i;
- outb_p(4,HD_CMD);
- for(i = 0; i < 1000; i++) barrier();
- outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
- for(i = 0; i < 1000; i++) barrier();
+ outb_p(4, HD_CMD);
+ for (i = 0; i < 1000; i++) barrier();
+ outb_p(hd_info[0].ctl & 0x0f, HD_CMD);
+ for (i = 0; i < 1000; i++) barrier();
if (drive_busy())
printk("hd: controller still busy\n");
else if ((hd_error = inb(HD_ERROR)) != 1)
- printk("hd: controller reset failed: %02x\n",hd_error);
+ printk("hd: controller reset failed: %02x\n", hd_error);
}
static void reset_hd(void)
@@ -371,8 +370,8 @@ repeat:
if (++i < NR_HD) {
struct hd_i_struct *disk = &hd_info[i];
disk->special_op = disk->recalibrate = 1;
- hd_out(disk,disk->sect,disk->sect,disk->head-1,
- disk->cyl,WIN_SPECIFY,&reset_hd);
+ hd_out(disk, disk->sect, disk->sect, disk->head-1,
+ disk->cyl, WIN_SPECIFY, &reset_hd);
if (reset)
goto repeat;
} else
@@ -393,7 +392,7 @@ static void unexpected_hd_interrupt(void)
unsigned int stat = inb_p(HD_STATUS);
if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
- dump_status ("unexpected interrupt", stat);
+ dump_status("unexpected interrupt", stat);
SET_TIMER;
}
}
@@ -453,7 +452,7 @@ static void read_intr(void)
return;
ok_to_read:
req = CURRENT;
- insw(HD_DATA,req->buffer,256);
+ insw(HD_DATA, req->buffer, 256);
req->sector++;
req->buffer += 512;
req->errors = 0;
@@ -507,7 +506,7 @@ ok_to_write:
end_request(req, 1);
if (i > 0) {
SET_HANDLER(&write_intr);
- outsw(HD_DATA,req->buffer,256);
+ outsw(HD_DATA, req->buffer, 256);
local_irq_enable();
} else {
#if (HD_DELAY > 0)
@@ -560,11 +559,11 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req)
{
if (disk->recalibrate) {
disk->recalibrate = 0;
- hd_out(disk,disk->sect,0,0,0,WIN_RESTORE,&recal_intr);
+ hd_out(disk, disk->sect, 0, 0, 0, WIN_RESTORE, &recal_intr);
return reset;
}
if (disk->head > 16) {
- printk ("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
+ printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
end_request(req, 0);
}
disk->special_op = 0;
@@ -633,19 +632,21 @@ repeat:
if (blk_fs_request(req)) {
switch (rq_data_dir(req)) {
case READ:
- hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr);
+ hd_out(disk, nsect, sec, head, cyl, WIN_READ,
+ &read_intr);
if (reset)
goto repeat;
break;
case WRITE:
- hd_out(disk,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+ hd_out(disk, nsect, sec, head, cyl, WIN_WRITE,
+ &write_intr);
if (reset)
goto repeat;
if (wait_DRQ()) {
bad_rw_intr();
goto repeat;
}
- outsw(HD_DATA,req->buffer,256);
+ outsw(HD_DATA, req->buffer, 256);
break;
default:
printk("unknown hd-command\n");
@@ -655,7 +656,7 @@ repeat:
}
}
-static void do_hd_request (struct request_queue * q)
+static void do_hd_request(struct request_queue *q)
{
disable_irq(HD_IRQ);
hd_request();
@@ -708,12 +709,12 @@ static int __init hd_init(void)
{
int drive;
- if (register_blkdev(MAJOR_NR,"hd"))
+ if (register_blkdev(MAJOR_NR, "hd"))
return -1;
hd_queue = blk_init_queue(do_hd_request, &hd_lock);
if (!hd_queue) {
- unregister_blkdev(MAJOR_NR,"hd");
+ unregister_blkdev(MAJOR_NR, "hd");
return -ENOMEM;
}
@@ -742,7 +743,7 @@ static int __init hd_init(void)
goto out;
}
- for (drive=0 ; drive < NR_HD ; drive++) {
+ for (drive = 0 ; drive < NR_HD ; drive++) {
struct gendisk *disk = alloc_disk(64);
struct hd_i_struct *p = &hd_info[drive];
if (!disk)
@@ -756,7 +757,7 @@ static int __init hd_init(void)
disk->queue = hd_queue;
p->unit = drive;
hd_gendisk[drive] = disk;
- printk ("%s: %luMB, CHS=%d/%d/%d\n",
+ printk("%s: %luMB, CHS=%d/%d/%d\n",
disk->disk_name, (unsigned long)get_capacity(disk)/2048,
p->cyl, p->head, p->sect);
}
@@ -776,7 +777,7 @@ static int __init hd_init(void)
}
/* Let them fly */
- for(drive=0; drive < NR_HD; drive++)
+ for (drive = 0; drive < NR_HD; drive++)
add_disk(hd_gendisk[drive]);
return 0;
@@ -791,7 +792,7 @@ out1:
NR_HD = 0;
out:
del_timer(&device_timer);
- unregister_blkdev(MAJOR_NR,"hd");
+ unregister_blkdev(MAJOR_NR, "hd");
blk_cleanup_queue(hd_queue);
return -1;
Enomem:
@@ -800,7 +801,8 @@ Enomem:
goto out;
}
-static int __init parse_hd_setup (char *line) {
+static int __init parse_hd_setup(char *line)
+{
int ints[6];
(void) get_options(line, ARRAY_SIZE(ints), ints);
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index 88fe9070c9c3..4fe516df9f74 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -35,6 +35,7 @@
* Try: http://www.maf.iki.fi/~maf/ht6560b/
*/
+#define DRV_NAME "ht6560b"
#define HT6560B_VERSION "v0.08"
#include <linux/module.h>
@@ -156,8 +157,8 @@ static void ht6560b_selectproc (ide_drive_t *drive)
/*
* Set timing for this drive:
*/
- outb(timing, hwif->io_ports[IDE_SELECT_OFFSET]);
- (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]);
+ outb(timing, hwif->io_ports.device_addr);
+ (void)inb(hwif->io_ports.status_addr);
#ifdef DEBUG
printk("ht6560b: %s: select=%#x timing=%#x\n",
drive->name, select, timing);
@@ -211,8 +212,8 @@ static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
{
int active_time, recovery_time;
int active_cycles, recovery_cycles;
- int bus_speed = system_bus_clock();
-
+ int bus_speed = ide_vlb_clk ? ide_vlb_clk : system_bus_clock();
+
if (pio) {
unsigned int cycle_time;
@@ -322,66 +323,44 @@ static void __init ht6560b_port_init_devs(ide_hwif_t *hwif)
hwif->drives[1].drive_data = t;
}
-int probe_ht6560b = 0;
+static int probe_ht6560b;
module_param_named(probe, probe_ht6560b, bool, 0);
MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
+static const struct ide_port_ops ht6560b_port_ops = {
+ .port_init_devs = ht6560b_port_init_devs,
+ .set_pio_mode = ht6560b_set_pio_mode,
+ .selectproc = ht6560b_selectproc,
+};
+
static const struct ide_port_info ht6560b_port_info __initdata = {
+ .name = DRV_NAME,
.chipset = ide_ht6560b,
+ .port_ops = &ht6560b_port_ops,
.host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */
IDE_HFLAG_NO_DMA |
- IDE_HFLAG_NO_AUTOTUNE |
IDE_HFLAG_ABUSE_PREFETCH,
.pio_mask = ATA_PIO4,
};
static int __init ht6560b_init(void)
{
- ide_hwif_t *hwif, *mate;
- static u8 idx[4] = { 0, 1, 0xff, 0xff };
- hw_regs_t hw[2];
-
if (probe_ht6560b == 0)
return -ENODEV;
- hwif = &ide_hwifs[0];
- mate = &ide_hwifs[1];
-
- if (!request_region(HT_CONFIG_PORT, 1, hwif->name)) {
+ if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) {
printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
- __FUNCTION__);
+ __func__);
return -ENODEV;
}
if (!try_to_init_ht6560b()) {
- printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+ printk(KERN_NOTICE "%s: HBA not found\n", __func__);
goto release_region;
}
- memset(&hw, 0, sizeof(hw));
-
- ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
- hw[0].irq = 14;
-
- ide_std_init_ports(&hw[1], 0x170, 0x376);
- hw[1].irq = 15;
-
- ide_init_port_hw(hwif, &hw[0]);
- ide_init_port_hw(mate, &hw[1]);
-
- hwif->selectproc = &ht6560b_selectproc;
- hwif->set_pio_mode = &ht6560b_set_pio_mode;
-
- mate->selectproc = &ht6560b_selectproc;
- mate->set_pio_mode = &ht6560b_set_pio_mode;
-
- hwif->port_init_devs = ht6560b_port_init_devs;
- mate->port_init_devs = ht6560b_port_init_devs;
-
- ide_device_add(idx, &ht6560b_port_info);
-
- return 0;
+ return ide_legacy_device_add(&ht6560b_port_info, 0);
release_region:
release_region(HT_CONFIG_PORT, 1);
diff --git a/drivers/ide/legacy/ide-4drives.c b/drivers/ide/legacy/ide-4drives.c
index ecd7f3553554..ecae916a3385 100644
--- a/drivers/ide/legacy/ide-4drives.c
+++ b/drivers/ide/legacy/ide-4drives.c
@@ -4,7 +4,9 @@
#include <linux/module.h>
#include <linux/ide.h>
-int probe_4drives = 0;
+#define DRV_NAME "ide-4drives"
+
+static int probe_4drives;
module_param_named(probe, probe_4drives, bool, 0);
MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
@@ -12,31 +14,51 @@ MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
static int __init ide_4drives_init(void)
{
ide_hwif_t *hwif, *mate;
- u8 idx[4] = { 0, 1, 0xff, 0xff };
+ unsigned long base = 0x1f0, ctl = 0x3f6;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
hw_regs_t hw;
if (probe_4drives == 0)
return -ENODEV;
- hwif = &ide_hwifs[0];
- mate = &ide_hwifs[1];
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, 0x1f0, 0x3f6);
+ ide_std_init_ports(&hw, base, ctl);
hw.irq = 14;
hw.chipset = ide_4drives;
- ide_init_port_hw(hwif, &hw);
- ide_init_port_hw(mate, &hw);
-
- mate->drives[0].select.all ^= 0x20;
- mate->drives[1].select.all ^= 0x20;
-
- hwif->mate = mate;
- mate->mate = hwif;
-
- hwif->serialized = mate->serialized = 1;
+ hwif = ide_find_port();
+ if (hwif) {
+ ide_init_port_hw(hwif, &hw);
+ idx[0] = hwif->index;
+ }
+
+ mate = ide_find_port();
+ if (mate) {
+ ide_init_port_hw(mate, &hw);
+ mate->drives[0].select.all ^= 0x20;
+ mate->drives[1].select.all ^= 0x20;
+ idx[1] = mate->index;
+
+ if (hwif) {
+ hwif->mate = mate;
+ mate->mate = hwif;
+ hwif->serialized = mate->serialized = 1;
+ }
+ }
ide_device_add(idx, NULL);
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 9a23b94f2939..aa2ea3deac85 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -51,6 +51,8 @@
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
+#define DRV_NAME "ide-cs"
+
/*====================================================================*/
/* Module parameters */
@@ -72,16 +74,11 @@ static char *version =
/*====================================================================*/
-static const char ide_major[] = {
- IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
- IDE4_MAJOR, IDE5_MAJOR
-};
-
typedef struct ide_info_t {
struct pcmcia_device *p_dev;
+ ide_hwif_t *hwif;
int ndev;
dev_node_t node;
- int hd;
} ide_info_t;
static void ide_release(struct pcmcia_device *);
@@ -136,45 +133,71 @@ static int ide_probe(struct pcmcia_device *link)
static void ide_detach(struct pcmcia_device *link)
{
+ ide_info_t *info = link->priv;
+ ide_hwif_t *hwif = info->hwif;
+
DEBUG(0, "ide_detach(0x%p)\n", link);
ide_release(link);
- kfree(link->priv);
+ release_region(hwif->io_ports.ctl_addr, 1);
+ release_region(hwif->io_ports.data_addr, 8);
+
+ kfree(info);
} /* ide_detach */
-static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
+static const struct ide_port_ops idecs_port_ops = {
+ .quirkproc = ide_undecoded_slave,
+};
+
+static ide_hwif_t *idecs_register(unsigned long io, unsigned long ctl,
+ unsigned long irq, struct pcmcia_device *handle)
{
ide_hwif_t *hwif;
hw_regs_t hw;
int i;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ if (!request_region(io, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, io, io + 7);
+ return NULL;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(io, 8);
+ return NULL;
+ }
+
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, io, ctl);
hw.irq = irq;
hw.chipset = ide_pci;
hw.dev = &handle->dev;
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif == NULL)
- return -1;
+ goto out_release;
i = hwif->index;
- if (hwif->present)
- ide_unregister(i);
- else
- ide_init_port_data(hwif, i);
-
+ ide_init_port_data(hwif, i);
ide_init_port_hw(hwif, &hw);
- hwif->quirkproc = &ide_undecoded_slave;
+ hwif->port_ops = &idecs_port_ops;
idx[0] = i;
ide_device_add(idx, NULL);
- return hwif->present ? i : -1;
+ if (hwif->present)
+ return hwif;
+
+out_release:
+ release_region(ctl, 1);
+ release_region(io, 8);
+ return NULL;
}
/*======================================================================
@@ -199,8 +222,9 @@ static int ide_config(struct pcmcia_device *link)
cistpl_cftable_entry_t dflt;
} *stk = NULL;
cistpl_cftable_entry_t *cfg;
- int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0;
+ int i, pass, last_ret = 0, last_fn = 0, is_kme = 0;
unsigned long io_base, ctl_base;
+ ide_hwif_t *hwif;
DEBUG(0, "ide_config(0x%p)\n", link);
@@ -296,14 +320,15 @@ static int ide_config(struct pcmcia_device *link)
outb(0x81, ctl_base+1);
/* retry registration in case device is still spinning up */
- for (hd = -1, i = 0; i < 10; i++) {
- hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
- if (hd >= 0) break;
+ for (i = 0; i < 10; i++) {
+ hwif = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
+ if (hwif)
+ break;
if (link->io.NumPorts1 == 0x20) {
outb(0x02, ctl_base + 0x10);
- hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
- link->irq.AssignedIRQ, link);
- if (hd >= 0) {
+ hwif = idecs_register(io_base + 0x10, ctl_base + 0x10,
+ link->irq.AssignedIRQ, link);
+ if (hwif) {
io_base += 0x10;
ctl_base += 0x10;
break;
@@ -312,7 +337,7 @@ static int ide_config(struct pcmcia_device *link)
msleep(100);
}
- if (hd < 0) {
+ if (hwif == NULL) {
printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx"
", irq %u failed\n", io_base, ctl_base,
link->irq.AssignedIRQ);
@@ -320,10 +345,10 @@ static int ide_config(struct pcmcia_device *link)
}
info->ndev = 1;
- sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2));
- info->node.major = ide_major[hd];
+ sprintf(info->node.dev_name, "hd%c", 'a' + hwif->index * 2);
+ info->node.major = hwif->major;
info->node.minor = 0;
- info->hd = hd;
+ info->hwif = hwif;
link->dev_node = &info->node;
printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n",
info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10);
@@ -354,13 +379,14 @@ failed:
void ide_release(struct pcmcia_device *link)
{
ide_info_t *info = link->priv;
+ ide_hwif_t *hwif = info->hwif;
DEBUG(0, "ide_release(0x%p)\n", link);
if (info->ndev) {
/* FIXME: if this fails we need to queue the cleanup somehow
-- need to investigate the required PCMCIA magic */
- ide_unregister(info->hd);
+ ide_unregister(hwif);
}
info->ndev = 0;
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
index 249651e2da42..d3bc3f24e05d 100644
--- a/drivers/ide/legacy/ide_platform.c
+++ b/drivers/ide/legacy/ide_platform.c
@@ -30,14 +30,14 @@ static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
unsigned long port = (unsigned long)base;
int i;
- hw->io_ports[IDE_DATA_OFFSET] = port;
+ hw->io_ports.data_addr = port;
port += (1 << pdata->ioport_shift);
- for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
+ for (i = 1; i <= 7;
i++, port += (1 << pdata->ioport_shift))
- hw->io_ports[i] = port;
+ hw->io_ports_array[i] = port;
- hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+ hw->io_ports.ctl_addr = (unsigned long)ctrl;
hw->irq = irq;
@@ -89,7 +89,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
res_alt->start, res_alt->end - res_alt->start + 1);
}
- hwif = ide_find_port((unsigned long)base);
+ hwif = ide_find_port();
if (!hwif) {
ret = -ENODEV;
goto out;
@@ -102,7 +102,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
ide_init_port_hw(hwif, &hw);
if (mmio) {
- hwif->mmio = 1;
+ hwif->host_flags = IDE_HFLAG_MMIO;
default_hwif_mmiops(hwif);
}
@@ -122,7 +122,7 @@ static int __devexit plat_ide_remove(struct platform_device *pdev)
{
ide_hwif_t *hwif = pdev->dev.driver_data;
- ide_unregister(hwif->index);
+ ide_unregister(hwif);
return 0;
}
@@ -130,6 +130,7 @@ static int __devexit plat_ide_remove(struct platform_device *pdev)
static struct platform_driver platform_ide_driver = {
.driver = {
.name = "pata_platform",
+ .owner = THIS_MODULE,
},
.probe = plat_ide_probe,
.remove = __devexit_p(plat_ide_remove),
@@ -147,6 +148,7 @@ static void __exit platform_ide_exit(void)
MODULE_DESCRIPTION("Platform IDE driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pata_platform");
module_init(platform_ide_init);
module_exit(platform_ide_exit);
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index eaf5dbe58bc2..1f527bbf8d96 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -72,9 +72,9 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
memset(hw, 0, sizeof(*hw));
for (i = 0; i < 8; i++)
- hw->io_ports[i] = base + i * 4;
+ hw->io_ports_array[i] = base + i * 4;
- hw->io_ports[IDE_CONTROL_OFFSET] = base + IDE_CONTROL;
+ hw->io_ports.ctl_addr = base + IDE_CONTROL;
hw->irq = irq;
hw->ack_intr = ack_intr;
@@ -120,7 +120,7 @@ static int __init macide_init(void)
macide_setup_ports(&hw, base, irq, ack_intr);
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif) {
u8 index = hwif->index;
u8 idx[4] = { index, 0xff, 0xff, 0xff };
@@ -128,8 +128,6 @@ static int __init macide_init(void)
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
- hwif->mmio = 1;
-
ide_device_add(idx, NULL);
}
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 2da28759686e..6f535d00e638 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -36,23 +36,6 @@ static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
PCIDE_BASE6 */
};
-
- /*
- * Offsets from one of the above bases
- */
-
-/* used to do addr translation here but it is easier to do in setup ports */
-/*#define IDE_OFF_B(x) ((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/
-
-#define IDE_OFF_B(x) ((unsigned long)((IDE_##x##_OFFSET)))
-#define IDE_OFF_W(x) ((unsigned long)((IDE_##x##_OFFSET)))
-
-static const int pcide_offsets[IDE_NR_PORTS] = {
- IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR),
- IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS),
- 518/*IDE_OFF(CMD)*/
-};
-
static int q40ide_default_irq(unsigned long base)
{
switch (base) {
@@ -68,29 +51,48 @@ static int q40ide_default_irq(unsigned long base)
/*
* Addresses are pretranslated for Q40 ISA access.
*/
-void q40_ide_setup_ports ( hw_regs_t *hw,
- unsigned long base, int *offsets,
- unsigned long ctrl, unsigned long intr,
+static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
ide_ack_intr_t *ack_intr,
int irq)
{
- int i;
-
memset(hw, 0, sizeof(hw_regs_t));
- for (i = 0; i < IDE_NR_PORTS; i++) {
- /* BIG FAT WARNING:
- assumption: only DATA port is ever used in 16 bit mode */
- if ( i==0 )
- hw->io_ports[i] = Q40_ISA_IO_W(base + offsets[i]);
- else
- hw->io_ports[i] = Q40_ISA_IO_B(base + offsets[i]);
- }
+ /* BIG FAT WARNING:
+ assumption: only DATA port is ever used in 16 bit mode */
+ hw->io_ports.data_addr = Q40_ISA_IO_W(base);
+ hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
+ hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
+ hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
+ hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
+ hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
+ hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
+ hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
+ hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
hw->irq = irq;
hw->ack_intr = ack_intr;
}
+static void q40ide_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return insw(data_addr, buf, (len + 1) / 2);
+ insw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
+static void q40ide_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return outsw(data_addr, buf, (len + 1) / 2);
+
+ outsw_swapw(data_addr, buf, (len + 1) / 2);
+}
/*
* the static array is needed to have the name reported in /proc/ioports,
@@ -131,17 +133,19 @@ static int __init q40ide_init(void)
release_region(pcide_bases[i], 8);
continue;
}
- q40_ide_setup_ports(&hw,(unsigned long) pcide_bases[i], (int *)pcide_offsets,
- pcide_bases[i]+0x206,
- 0, NULL,
+ q40_ide_setup_ports(&hw, pcide_bases[i],
+ NULL,
// m68kide_iops,
q40ide_default_irq(pcide_bases[i]));
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif) {
ide_init_port_data(hwif, hwif->index);
ide_init_port_hw(hwif, &hw);
- hwif->mmio = 1;
+
+ /* Q40 has a byte-swapped IDE interface */
+ hwif->input_data = q40ide_input_data;
+ hwif->output_data = q40ide_output_data;
idx[i] = hwif->index;
}
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 7016bdf4fcc1..6424af154325 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -11,11 +11,7 @@
*
* QDI QD6500/QD6580 EIDE controller fast support
*
- * Please set local bus speed using kernel parameter idebus
- * for example, "idebus=33" stands for 33Mhz VLbus
* To activate controller support, use "ide0=qd65xx"
- * To enable tuning, use "hda=autotune hdb=autotune"
- * To enable 2nd channel tuning (qd6580 only), use "hdc=autotune hdd=autotune"
*/
/*
@@ -37,6 +33,8 @@
#include <asm/system.h>
#include <asm/io.h>
+#define DRV_NAME "qd65xx"
+
#include "qd65xx.h"
/*
@@ -88,12 +86,12 @@
static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
/*
- * qd_select:
+ * qd65xx_select:
*
- * This routine is invoked from ide.c to prepare for access to a given drive.
+ * This routine is invoked to prepare for access to a given drive.
*/
-static void qd_select (ide_drive_t *drive)
+static void qd65xx_select(ide_drive_t *drive)
{
u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
(QD_TIMREG(drive) & 0x02);
@@ -112,17 +110,18 @@ static void qd_select (ide_drive_t *drive)
static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
{
- u8 active_cycle,recovery_cycle;
+ int clk = ide_vlb_clk ? ide_vlb_clk : system_bus_clock();
+ u8 act_cyc, rec_cyc;
- if (system_bus_clock()<=33) {
- active_cycle = 9 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 9);
- recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+ if (clk <= 33) {
+ act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9);
+ rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
} else {
- active_cycle = 8 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 1, 8);
- recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+ act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8);
+ rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
}
- return((recovery_cycle<<4) | 0x08 | active_cycle);
+ return (rec_cyc << 4) | 0x08 | act_cyc;
}
/*
@@ -133,10 +132,13 @@ static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery
static u8 qd6580_compute_timing (int active_time, int recovery_time)
{
- u8 active_cycle = 17 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 17);
- u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+ int clk = ide_vlb_clk ? ide_vlb_clk : system_bus_clock();
+ u8 act_cyc, rec_cyc;
+
+ act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17);
+ rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
- return((recovery_cycle<<4) | active_cycle);
+ return (rec_cyc << 4) | act_cyc;
}
/*
@@ -168,36 +170,15 @@ static int qd_find_disk_type (ide_drive_t *drive,
}
/*
- * qd_timing_ok:
- *
- * check whether timings don't conflict
- */
-
-static int qd_timing_ok (ide_drive_t drives[])
-{
- return (IDE_IMPLY(drives[0].present && drives[1].present,
- IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
- QD_TIMING(drives) == QD_TIMING(drives+1))));
- /* if same timing register, must be same timing */
-}
-
-/*
* qd_set_timing:
*
- * records the timing, and enables selectproc as needed
+ * records the timing
*/
static void qd_set_timing (ide_drive_t *drive, u8 timing)
{
- ide_hwif_t *hwif = HWIF(drive);
-
drive->drive_data &= 0xff00;
drive->drive_data |= timing;
- if (qd_timing_ok(hwif->drives)) {
- qd_select(drive); /* selects once */
- hwif->selectproc = NULL;
- } else
- hwif->selectproc = &qd_select;
printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
}
@@ -225,10 +206,11 @@ static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- int base = HWIF(drive)->select_data;
+ ide_hwif_t *hwif = drive->hwif;
unsigned int cycle_time;
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
+ u8 base = (hwif->config_data & 0xff00) >> 8;
if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
cycle_time = ide_pio_cycle_time(drive, pio);
@@ -299,21 +281,10 @@ static int __init qd_testreg(int port)
return (readreg != QD_TESTVAL);
}
-/*
- * qd_setup:
- *
- * called to setup an ata channel : adjusts attributes & links for tuning
- */
-
-static void __init qd_setup(ide_hwif_t *hwif, int base, int config)
-{
- hwif->select_data = base;
- hwif->config_data = config;
-}
-
static void __init qd6500_port_init_devs(ide_hwif_t *hwif)
{
- u8 base = hwif->select_data, config = QD_CONFIG(hwif);
+ u8 base = (hwif->config_data & 0xff00) >> 8;
+ u8 config = QD_CONFIG(hwif);
hwif->drives[0].drive_data = QD6500_DEF_DATA;
hwif->drives[1].drive_data = QD6500_DEF_DATA;
@@ -322,9 +293,10 @@ static void __init qd6500_port_init_devs(ide_hwif_t *hwif)
static void __init qd6580_port_init_devs(ide_hwif_t *hwif)
{
u16 t1, t2;
- u8 base = hwif->select_data, config = QD_CONFIG(hwif);
+ u8 base = (hwif->config_data & 0xff00) >> 8;
+ u8 config = QD_CONFIG(hwif);
- if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+ if (hwif->host_flags & IDE_HFLAG_SINGLE) {
t1 = QD6580_DEF_DATA;
t2 = QD6580_DEF_DATA2;
} else
@@ -334,11 +306,23 @@ static void __init qd6580_port_init_devs(ide_hwif_t *hwif)
hwif->drives[1].drive_data = t2;
}
+static const struct ide_port_ops qd6500_port_ops = {
+ .port_init_devs = qd6500_port_init_devs,
+ .set_pio_mode = qd6500_set_pio_mode,
+ .selectproc = qd65xx_select,
+};
+
+static const struct ide_port_ops qd6580_port_ops = {
+ .port_init_devs = qd6580_port_init_devs,
+ .set_pio_mode = qd6580_set_pio_mode,
+ .selectproc = qd65xx_select,
+};
+
static const struct ide_port_info qd65xx_port_info __initdata = {
+ .name = DRV_NAME,
.chipset = ide_qd65xx,
.host_flags = IDE_HFLAG_IO_32BIT |
- IDE_HFLAG_NO_DMA |
- IDE_HFLAG_NO_AUTOTUNE,
+ IDE_HFLAG_NO_DMA,
.pio_mask = ATA_PIO4,
};
@@ -351,65 +335,41 @@ static const struct ide_port_info qd65xx_port_info __initdata = {
static int __init qd_probe(int base)
{
- ide_hwif_t *hwif;
- u8 config, unit;
- u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
- hw_regs_t hw[2];
+ int rc;
+ u8 config, unit, control;
+ struct ide_port_info d = qd65xx_port_info;
config = inb(QD_CONFIG_PORT);
if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
- return 1;
+ return -ENODEV;
unit = ! (config & QD_CONFIG_IDE_BASEPORT);
- memset(&hw, 0, sizeof(hw));
+ if (unit)
+ d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
- ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
- hw[0].irq = 14;
+ switch (config & 0xf0) {
+ case QD_CONFIG_QD6500:
+ if (qd_testreg(base))
+ return -ENODEV; /* bad register */
- ide_std_init_ports(&hw[1], 0x170, 0x376);
- hw[1].irq = 15;
-
- if ((config & 0xf0) == QD_CONFIG_QD6500) {
-
- if (qd_testreg(base)) return 1; /* bad register */
-
- /* qd6500 found */
-
- hwif = &ide_hwifs[unit];
- printk(KERN_NOTICE "%s: qd6500 at %#x\n", hwif->name, base);
- printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
- config, QD_ID3);
-
if (config & QD_CONFIG_DISABLED) {
printk(KERN_WARNING "qd6500 is disabled !\n");
- return 1;
+ return -ENODEV;
}
- ide_init_port_hw(hwif, &hw[unit]);
-
- qd_setup(hwif, base, config);
-
- hwif->port_init_devs = qd6500_port_init_devs;
- hwif->set_pio_mode = &qd6500_set_pio_mode;
-
- idx[unit] = unit;
-
- ide_device_add(idx, &qd65xx_port_info);
-
- return 1;
- }
-
- if (((config & 0xf0) == QD_CONFIG_QD6580_A) ||
- ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-
- u8 control;
-
- if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
- /* bad registers */
+ printk(KERN_NOTICE "qd6500 at %#x\n", base);
+ printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+ config, QD_ID3);
- /* qd6580 found */
+ d.port_ops = &qd6500_port_ops;
+ d.host_flags |= IDE_HFLAG_SINGLE;
+ break;
+ case QD_CONFIG_QD6580_A:
+ case QD_CONFIG_QD6580_B:
+ if (qd_testreg(base) || qd_testreg(base + 0x02))
+ return -ENODEV; /* bad registers */
control = inb(QD_CONTROL_PORT);
@@ -419,74 +379,44 @@ static int __init qd_probe(int base)
outb(QD_DEF_CONTR, QD_CONTROL_PORT);
- if (control & QD_CONTR_SEC_DISABLED) {
- /* secondary disabled */
-
- hwif = &ide_hwifs[unit];
- printk(KERN_INFO "%s: qd6580: single IDE board\n",
- hwif->name);
-
- ide_init_port_hw(hwif, &hw[unit]);
-
- qd_setup(hwif, base, config | (control << 8));
-
- hwif->port_init_devs = qd6580_port_init_devs;
- hwif->set_pio_mode = &qd6580_set_pio_mode;
-
- idx[unit] = unit;
+ d.port_ops = &qd6580_port_ops;
+ if (control & QD_CONTR_SEC_DISABLED)
+ d.host_flags |= IDE_HFLAG_SINGLE;
- ide_device_add(idx, &qd65xx_port_info);
-
- return 1;
- } else {
- ide_hwif_t *mate;
-
- hwif = &ide_hwifs[0];
- mate = &ide_hwifs[1];
- /* secondary enabled */
- printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
- hwif->name, mate->name);
-
- ide_init_port_hw(hwif, &hw[0]);
- ide_init_port_hw(mate, &hw[1]);
-
- qd_setup(hwif, base, config | (control << 8));
-
- hwif->port_init_devs = qd6580_port_init_devs;
- hwif->set_pio_mode = &qd6580_set_pio_mode;
-
- qd_setup(mate, base, config | (control << 8));
-
- mate->port_init_devs = qd6580_port_init_devs;
- mate->set_pio_mode = &qd6580_set_pio_mode;
+ printk(KERN_INFO "qd6580: %s IDE board\n",
+ (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
+ break;
+ default:
+ return -ENODEV;
+ }
- idx[0] = 0;
- idx[1] = 1;
+ rc = ide_legacy_device_add(&d, (base << 8) | config);
- ide_device_add(idx, &qd65xx_port_info);
+ if (d.host_flags & IDE_HFLAG_SINGLE)
+ return (rc == 0) ? 1 : rc;
- return 0; /* no other qd65xx possible */
- }
- }
- /* no qd65xx found */
- return 1;
+ return rc;
}
-int probe_qd65xx = 0;
+static int probe_qd65xx;
module_param_named(probe, probe_qd65xx, bool, 0);
MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
static int __init qd65xx_init(void)
{
+ int rc1, rc2 = -ENODEV;
+
if (probe_qd65xx == 0)
return -ENODEV;
- if (qd_probe(0x30))
- qd_probe(0xb0);
- if (ide_hwifs[0].chipset != ide_qd65xx &&
- ide_hwifs[1].chipset != ide_qd65xx)
+ rc1 = qd_probe(0x30);
+ if (rc1)
+ rc2 = qd_probe(0xb0);
+
+ if (rc1 < 0 && rc2 < 0)
return -ENODEV;
+
return 0;
}
diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h
index 28dd50a15d55..c83dea85e621 100644
--- a/drivers/ide/legacy/qd65xx.h
+++ b/drivers/ide/legacy/qd65xx.h
@@ -30,7 +30,6 @@
#define QD_ID3 ((config & QD_CONFIG_ID3)!=0)
#define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff)
-#define QD_CONTROL(hwif) (((hwif)->config_data & 0xff00) >> 8)
#define QD_TIMING(drive) (byte)(((drive)->drive_data) & 0x00ff)
#define QD_TIMREG(drive) (byte)((((drive)->drive_data) & 0xff00) >> 8)
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index bc1944811b99..b54a14a57755 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -19,7 +19,7 @@
*/
/*
- * VLB Controller Support from
+ * VLB Controller Support from
* Wolfram Podien
* Rohoefe 3
* D28832 Achim
@@ -32,7 +32,7 @@
* #define UMC_DRIVE0 11
* in the beginning of the driver, which sets the speed of drive 0 to 11 (there
* are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the
+ * the results from the DOS speed test program supplied from UMC. 11 is the
* highest speed (about PIO mode 3)
*/
#define REALLY_SLOW_IO /* some systems can safely undef this */
@@ -51,6 +51,8 @@
#include <asm/io.h>
+#define DRV_NAME "umc8672"
+
/*
* Default speeds. These can be changed with "auto-tune" and/or hdparm.
*/
@@ -60,115 +62,103 @@
#define UMC_DRIVE3 1 /* In case of crash reduce speed */
static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const u8 pio_to_umc [5] = {0,3,7,10,11}; /* rough guesses */
+static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11}; /* rough guesses */
/* 0 1 2 3 4 5 6 7 8 9 10 11 */
static const u8 speedtab [3][12] = {
- {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
- {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
- {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+ {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
+ {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
+ {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0}
+};
-static void out_umc (char port,char wert)
+static void out_umc(char port, char wert)
{
- outb_p(port,0x108);
- outb_p(wert,0x109);
+ outb_p(port, 0x108);
+ outb_p(wert, 0x109);
}
-static inline u8 in_umc (char port)
+static inline u8 in_umc(char port)
{
- outb_p(port,0x108);
+ outb_p(port, 0x108);
return inb_p(0x109);
}
-static void umc_set_speeds (u8 speeds[])
+static void umc_set_speeds(u8 speeds[])
{
int i, tmp;
- outb_p(0x5A,0x108); /* enable umc */
+ outb_p(0x5A, 0x108); /* enable umc */
- out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
- out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+ out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+ out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
tmp = 0;
- for (i = 3; i >= 0; i--) {
+ for (i = 3; i >= 0; i--)
tmp = (tmp << 2) | speedtab[1][speeds[i]];
+ out_umc(0xdc, tmp);
+ for (i = 0; i < 4; i++) {
+ out_umc(0xd0 + i, speedtab[2][speeds[i]]);
+ out_umc(0xd8 + i, speedtab[2][speeds[i]]);
}
- out_umc (0xdc,tmp);
- for (i = 0;i < 4; i++) {
- out_umc (0xd0+i,speedtab[2][speeds[i]]);
- out_umc (0xd8+i,speedtab[2][speeds[i]]);
- }
- outb_p(0xa5,0x108); /* disable umc */
+ outb_p(0xa5, 0x108); /* disable umc */
- printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+ printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
speeds[0], speeds[1], speeds[2], speeds[3]);
}
static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
+ ide_hwif_t *hwif = drive->hwif;
unsigned long flags;
- ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
drive->name, pio, pio_to_umc[pio]);
spin_lock_irqsave(&ide_lock, flags);
- if (hwgroup && hwgroup->handler != NULL) {
+ if (hwif->mate && hwif->mate->hwgroup->handler) {
printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
} else {
current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
- umc_set_speeds (current_speeds);
+ umc_set_speeds(current_speeds);
}
spin_unlock_irqrestore(&ide_lock, flags);
}
+static const struct ide_port_ops umc8672_port_ops = {
+ .set_pio_mode = umc_set_pio_mode,
+};
+
static const struct ide_port_info umc8672_port_info __initdata = {
+ .name = DRV_NAME,
.chipset = ide_umc8672,
- .host_flags = IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE,
+ .port_ops = &umc8672_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
.pio_mask = ATA_PIO4,
};
static int __init umc8672_probe(void)
{
unsigned long flags;
- static u8 idx[4] = { 0, 1, 0xff, 0xff };
- hw_regs_t hw[2];
if (!request_region(0x108, 2, "umc8672")) {
printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
return 1;
}
local_irq_save(flags);
- outb_p(0x5A,0x108); /* enable umc */
+ outb_p(0x5A, 0x108); /* enable umc */
if (in_umc (0xd5) != 0xa0) {
local_irq_restore(flags);
printk(KERN_ERR "umc8672: not found\n");
release_region(0x108, 2);
- return 1;
+ return 1;
}
- outb_p(0xa5,0x108); /* disable umc */
+ outb_p(0xa5, 0x108); /* disable umc */
- umc_set_speeds (current_speeds);
+ umc_set_speeds(current_speeds);
local_irq_restore(flags);
- memset(&hw, 0, sizeof(hw));
-
- ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
- hw[0].irq = 14;
-
- ide_std_init_ports(&hw[1], 0x170, 0x376);
- hw[1].irq = 15;
-
- ide_init_port_hw(&ide_hwifs[0], &hw[0]);
- ide_init_port_hw(&ide_hwifs[1], &hw[1]);
-
- ide_hwifs[0].set_pio_mode = &umc_set_pio_mode;
- ide_hwifs[1].set_pio_mode = &umc_set_pio_mode;
-
- ide_device_add(idx, &umc8672_port_info);
-
- return 0;
+ return ide_legacy_device_add(&umc8672_port_info, 0);
}
-int probe_umc8672 = 0;
+static int probe_umc8672;
module_param_named(probe, probe_umc8672, bool, 0);
MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 9b628248f2f4..1a6c27b32498 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -47,9 +47,6 @@
#define IDE_AU1XXX_BURSTMODE 1
static _auide_hwif auide_hwif;
-static int dbdma_init_done;
-
-static int auide_ddma_init(_auide_hwif *auide);
#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
@@ -61,7 +58,7 @@ void auide_insw(unsigned long port, void *addr, u32 count)
if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
DDMA_FLAGS_NOIE)) {
- printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
+ printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
return;
}
ctp = *((chan_tab_t **)ahwif->rx_chan);
@@ -79,7 +76,7 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
if(!put_source_flags(ahwif->tx_chan, (void*)addr,
count << 1, DDMA_FLAGS_NOIE)) {
- printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
+ printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
return;
}
ctp = *((chan_tab_t **)ahwif->tx_chan);
@@ -89,6 +86,17 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
}
+static void au1xxx_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void au1xxx_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
#endif
static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
@@ -250,7 +258,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
(void*) sg_virt(sg),
tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
- __FUNCTION__, __LINE__);
+ __func__, __LINE__);
}
} else
{
@@ -258,7 +266,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
(void*) sg_virt(sg),
tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
- __FUNCTION__, __LINE__);
+ __func__, __LINE__);
}
}
@@ -315,35 +323,6 @@ static int auide_dma_setup(ide_drive_t *drive)
return 0;
}
-static u8 auide_mdma_filter(ide_drive_t *drive)
-{
- /*
- * FIXME: ->white_list and ->black_list are based on completely bogus
- * ->ide_dma_check implementation which didn't set neither the host
- * controller timings nor the device for the desired transfer mode.
- *
- * They should be either removed or 0x00 MWDMA mask should be
- * returned for devices on the ->black_list.
- */
-
- if (dbdma_init_done == 0) {
- auide_hwif.white_list = ide_in_drive_list(drive->id,
- dma_white_list);
- auide_hwif.black_list = ide_in_drive_list(drive->id,
- dma_black_list);
- auide_hwif.drive = drive;
- auide_ddma_init(&auide_hwif);
- dbdma_init_done = 1;
- }
-
- /* Is the drive in our DMA black list? */
- if (auide_hwif.black_list)
- printk(KERN_WARNING "%s: Disabling DMA for %s (blacklisted)\n",
- drive->name, drive->id->model);
-
- return drive->hwif->mwdma_mask;
-}
-
static int auide_dma_test_irq(ide_drive_t *drive)
{
if (drive->waiting_for_dma == 0)
@@ -389,48 +368,48 @@ static void auide_ddma_rx_callback(int irq, void *param)
static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags)
{
dev->dev_id = dev_id;
- dev->dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR;
+ dev->dev_physaddr = (u32)IDE_PHYS_ADDR;
dev->dev_intlevel = 0;
dev->dev_intpolarity = 0;
dev->dev_tsize = tsize;
dev->dev_devwidth = devwidth;
dev->dev_flags = flags;
}
-
-#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
static void auide_dma_timeout(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
- if (hwif->ide_dma_test_irq(drive))
+ if (auide_dma_test_irq(drive))
return;
- hwif->ide_dma_end(drive);
+ auide_dma_end(drive);
}
-
-static int auide_ddma_init(_auide_hwif *auide) {
-
+static const struct ide_dma_ops au1xxx_dma_ops = {
+ .dma_host_set = auide_dma_host_set,
+ .dma_setup = auide_dma_setup,
+ .dma_exec_cmd = auide_dma_exec_cmd,
+ .dma_start = auide_dma_start,
+ .dma_end = auide_dma_end,
+ .dma_test_irq = auide_dma_test_irq,
+ .dma_lost_irq = auide_dma_lost_irq,
+ .dma_timeout = auide_dma_timeout,
+};
+
+static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ _auide_hwif *auide = (_auide_hwif *)hwif->hwif_data;
dbdev_tab_t source_dev_tab, target_dev_tab;
u32 dev_id, tsize, devwidth, flags;
- ide_hwif_t *hwif = auide->hwif;
- dev_id = AU1XXX_ATA_DDMA_REQ;
+ dev_id = IDE_DDMA_REQ;
- if (auide->white_list || auide->black_list) {
- tsize = 8;
- devwidth = 32;
- }
- else {
- tsize = 1;
- devwidth = 16;
-
- printk(KERN_ERR "au1xxx-ide: %s is not on ide driver whitelist.\n",auide_hwif.drive->id->model);
- printk(KERN_ERR " please read 'Documentation/mips/AU1xxx_IDE.README'");
- }
+ tsize = 8; /* 1 */
+ devwidth = 32; /* 16 */
#ifdef IDE_AU1XXX_BURSTMODE
flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
@@ -482,9 +461,9 @@ static int auide_ddma_init(_auide_hwif *auide) {
return 0;
}
#else
-
-static int auide_ddma_init( _auide_hwif *auide )
+static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
{
+ _auide_hwif *auide = (_auide_hwif *)hwif->hwif_data;
dbdev_tab_t source_dev_tab;
int flags;
@@ -532,20 +511,28 @@ static int auide_ddma_init( _auide_hwif *auide )
static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif)
{
int i;
- unsigned long *ata_regs = hw->io_ports;
+ unsigned long *ata_regs = hw->io_ports_array;
/* FIXME? */
- for (i = 0; i < IDE_CONTROL_OFFSET; i++) {
- *ata_regs++ = ahwif->regbase + (i << AU1XXX_ATA_REG_OFFSET);
- }
+ for (i = 0; i < 8; i++)
+ *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT);
/* set the Alternative Status register */
- *ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET);
+ *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT);
}
+static const struct ide_port_ops au1xxx_port_ops = {
+ .set_pio_mode = au1xxx_set_pio_mode,
+ .set_dma_mode = auide_set_dma_mode,
+};
+
static const struct ide_port_info au1xxx_port_info = {
+ .init_dma = auide_ddma_init,
+ .port_ops = &au1xxx_port_ops,
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+ .dma_ops = &au1xxx_dma_ops,
+#endif
.host_flags = IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
IDE_HFLAG_NO_IO_32BIT |
IDE_HFLAG_UNMASK_IRQS,
.pio_mask = ATA_PIO4,
@@ -599,9 +586,11 @@ static int au_ide_probe(struct device *dev)
goto out;
}
- /* FIXME: This might possibly break PCMCIA IDE devices */
-
- hwif = &ide_hwifs[pdev->id];
+ hwif = ide_find_port();
+ if (hwif == NULL) {
+ ret = -ENOENT;
+ goto out;
+ }
memset(&hw, 0, sizeof(hw));
auide_setup_ports(&hw, ahwif);
@@ -613,32 +602,13 @@ static int au_ide_probe(struct device *dev)
hwif->dev = dev;
- hwif->mmio = 1;
-
/* If the user has selected DDMA assisted copies,
then set up a few local I/O function entry points
*/
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
- hwif->INSW = auide_insw;
- hwif->OUTSW = auide_outsw;
-#endif
-
- hwif->set_pio_mode = &au1xxx_set_pio_mode;
- hwif->set_dma_mode = &auide_set_dma_mode;
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
- hwif->dma_timeout = &auide_dma_timeout;
-
- hwif->mdma_filter = &auide_mdma_filter;
-
- hwif->dma_host_set = &auide_dma_host_set;
- hwif->dma_exec_cmd = &auide_dma_exec_cmd;
- hwif->dma_start = &auide_dma_start;
- hwif->ide_dma_end = &auide_dma_end;
- hwif->dma_setup = &auide_dma_setup;
- hwif->ide_dma_test_irq = &auide_dma_test_irq;
- hwif->dma_lost_irq = &auide_dma_lost_irq;
+ hwif->input_data = au1xxx_input_data;
+ hwif->output_data = au1xxx_output_data;
#endif
hwif->select_data = 0; /* no chipset-specific code */
hwif->config_data = 0; /* no chipset-specific code */
@@ -646,11 +616,6 @@ static int au_ide_probe(struct device *dev)
auide_hwif.hwif = hwif;
hwif->hwif_data = &auide_hwif;
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
- auide_ddma_init(&auide_hwif);
- dbdma_init_done = 1;
-#endif
-
idx[0] = hwif->index;
ide_device_add(idx, &au1xxx_port_info);
@@ -670,7 +635,7 @@ static int au_ide_remove(struct device *dev)
ide_hwif_t *hwif = dev_get_drvdata(dev);
_auide_hwif *ahwif = &auide_hwif;
- ide_unregister(hwif->index);
+ ide_unregister(hwif);
iounmap((void *)ahwif->regbase);
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 956259fc09ba..712d17bdd470 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -76,17 +76,12 @@ static int __devinit swarm_ide_probe(struct device *dev)
if (!SIBYTE_HAVE_IDE)
return -ENODEV;
- /* Find an empty slot. */
- for (i = 0; i < MAX_HWIFS; i++)
- if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET])
- break;
- if (i >= MAX_HWIFS) {
+ hwif = ide_find_port();
+ if (hwif == NULL) {
printk(KERN_ERR DRV_NAME ": no free slot for interface\n");
return -ENOMEM;
}
- hwif = ide_hwifs + i;
-
base = ioremap(A_IO_EXT_BASE, 0x800);
offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS));
size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS));
@@ -114,16 +109,15 @@ static int __devinit swarm_ide_probe(struct device *dev)
base = ioremap(offset, size);
/* Setup MMIO ops. */
+ hwif->host_flags = IDE_HFLAG_MMIO;
default_hwif_mmiops(hwif);
- /* Prevent resource map manipulation. */
- hwif->mmio = 1;
+
hwif->chipset = ide_generic;
- hwif->noprobe = 0;
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- hwif->io_ports[i] =
+ for (i = 0; i <= 7; i++)
+ hwif->io_ports_array[i] =
(unsigned long)(base + ((0x1f0 + i) << 5));
- hwif->io_ports[IDE_CONTROL_OFFSET] =
+ hwif->io_ports.ctl_addr =
(unsigned long)(base + (0x3f6 << 5));
hwif->irq = K_INT_GB_IDE;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index cfb3265bc1a8..7f46c224b7c4 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -135,12 +135,12 @@ static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- drive->hwif->set_dma_mode(drive, pio + XFER_PIO_0);
+ drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
}
static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const char *name)
{
- int bus_speed = system_bus_clock();
+ int bus_speed = ide_pci_clk ? ide_pci_clk : system_bus_clock();
if (bus_speed <= 33)
pci_set_drvdata(dev, (void *) aec6xxx_33_base);
@@ -175,27 +175,23 @@ static u8 __devinit atp86x_cable_detect(ide_hwif_t *hwif)
return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
}
-static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- hwif->set_pio_mode = &aec_set_pio_mode;
-
- if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
- hwif->set_dma_mode = &aec6210_set_mode;
- else {
- hwif->set_dma_mode = &aec6260_set_mode;
+static const struct ide_port_ops atp850_port_ops = {
+ .set_pio_mode = aec_set_pio_mode,
+ .set_dma_mode = aec6210_set_mode,
+};
- hwif->cable_detect = atp86x_cable_detect;
- }
-}
+static const struct ide_port_ops atp86x_port_ops = {
+ .set_pio_mode = aec_set_pio_mode,
+ .set_dma_mode = aec6260_set_mode,
+ .cable_detect = atp86x_cable_detect,
+};
static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
{ /* 0 */
.name = "AEC6210",
.init_chipset = init_chipset_aec62xx,
- .init_hwif = init_hwif_aec62xx,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .port_ops = &atp850_port_ops,
.host_flags = IDE_HFLAG_SERIALIZE |
IDE_HFLAG_NO_ATAPI_DMA |
IDE_HFLAG_NO_DSC |
@@ -207,7 +203,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
},{ /* 1 */
.name = "AEC6260",
.init_chipset = init_chipset_aec62xx,
- .init_hwif = init_hwif_aec62xx,
+ .port_ops = &atp86x_port_ops,
.host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
IDE_HFLAG_ABUSE_SET_DMA_MODE |
IDE_HFLAG_OFF_BOARD,
@@ -217,17 +213,18 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
},{ /* 2 */
.name = "AEC6260R",
.init_chipset = init_chipset_aec62xx,
- .init_hwif = init_hwif_aec62xx,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .port_ops = &atp86x_port_ops,
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_ABUSE_SET_DMA_MODE,
+ IDE_HFLAG_ABUSE_SET_DMA_MODE |
+ IDE_HFLAG_NON_BOOTABLE,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
},{ /* 3 */
.name = "AEC6280",
.init_chipset = init_chipset_aec62xx,
- .init_hwif = init_hwif_aec62xx,
+ .port_ops = &atp86x_port_ops,
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
IDE_HFLAG_ABUSE_SET_DMA_MODE |
IDE_HFLAG_OFF_BOARD,
@@ -237,8 +234,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
},{ /* 4 */
.name = "AEC6280R",
.init_chipset = init_chipset_aec62xx,
- .init_hwif = init_hwif_aec62xx,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .port_ops = &atp86x_port_ops,
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
IDE_HFLAG_ABUSE_SET_DMA_MODE |
IDE_HFLAG_OFF_BOARD,
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index b3b6f514ce2d..b36a22b8c213 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -38,8 +38,6 @@
#include <asm/io.h>
-#define DISPLAY_ALI_TIMINGS
-
/*
* ALi devices are not plug in. Otherwise these static values would
* need to go. They ought to go away anyway
@@ -49,236 +47,6 @@ static u8 m5229_revision;
static u8 chip_is_1543c_e;
static struct pci_dev *isa_dev;
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static u8 ali_proc = 0;
-
-static struct pci_dev *bmide_dev;
-
-static char *fifo[4] = {
- "FIFO Off",
- "FIFO On ",
- "DMA mode",
- "PIO mode" };
-
-static char *udmaT[8] = {
- "1.5T",
- " 2T",
- "2.5T",
- " 3T",
- "3.5T",
- " 4T",
- " 6T",
- " 8T"
-};
-
-static char *channel_status[8] = {
- "OK ",
- "busy ",
- "DRQ ",
- "DRQ busy ",
- "error ",
- "error busy ",
- "error DRQ ",
- "error DRQ busy"
-};
-
-/**
- * ali_get_info - generate proc file for ALi IDE
- * @buffer: buffer to fill
- * @addr: address of user start in buffer
- * @offset: offset into 'file'
- * @count: buffer count
- *
- * Walks the Ali devices and outputs summary data on the tuning and
- * anything else that will help with debugging
- */
-
-static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
-{
- unsigned long bibma;
- u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
- char *q, *p = buffer;
-
- /* fetch rev. */
- pci_read_config_byte(bmide_dev, 0x08, &rev);
- if (rev >= 0xc1) /* M1543C or newer */
- udmaT[7] = " ???";
- else
- fifo[3] = " ??? ";
-
- /* first fetch bibma: */
-
- bibma = pci_resource_start(bmide_dev, 4);
-
- /*
- * at that point bibma+0x2 et bibma+0xa are byte
- * registers to investigate:
- */
- c0 = inb(bibma + 0x02);
- c1 = inb(bibma + 0x0a);
-
- p += sprintf(p,
- "\n Ali M15x3 Chipset.\n");
- p += sprintf(p,
- " ------------------\n");
- pci_read_config_byte(bmide_dev, 0x78, &reg53h);
- p += sprintf(p, "PCI Clock: %d.\n", reg53h);
-
- pci_read_config_byte(bmide_dev, 0x53, &reg53h);
- p += sprintf(p,
- "CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
- (reg53h & 0x02) ? "Yes" : "No ",
- (reg53h & 0x01) ? "Yes" : "No " );
- pci_read_config_byte(bmide_dev, 0x74, &reg53h);
- p += sprintf(p,
- "FIFO Status: contains %d Words, runs%s%s\n\n",
- (reg53h & 0x3f),
- (reg53h & 0x40) ? " OVERWR" : "",
- (reg53h & 0x80) ? " OVERRD." : "." );
-
- p += sprintf(p,
- "-------------------primary channel"
- "-------------------secondary channel"
- "---------\n\n");
-
- pci_read_config_byte(bmide_dev, 0x09, &reg53h);
- p += sprintf(p,
- "channel status: %s"
- " %s\n",
- (reg53h & 0x20) ? "On " : "Off",
- (reg53h & 0x10) ? "On " : "Off" );
-
- p += sprintf(p,
- "both channels togth: %s"
- " %s\n",
- (c0&0x80) ? "No " : "Yes",
- (c1&0x80) ? "No " : "Yes" );
-
- pci_read_config_byte(bmide_dev, 0x76, &reg53h);
- p += sprintf(p,
- "Channel state: %s %s\n",
- channel_status[reg53h & 0x07],
- channel_status[(reg53h & 0x70) >> 4] );
-
- pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
- pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
- p += sprintf(p,
- "Add. Setup Timing: %dT"
- " %dT\n",
- (reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
- (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
-
- pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
- pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
- p += sprintf(p,
- "Command Act. Count: %dT"
- " %dT\n"
- "Command Rec. Count: %dT"
- " %dT\n\n",
- (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
- (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
- (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
- (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
-
- p += sprintf(p,
- "----------------drive0-----------drive1"
- "------------drive0-----------drive1------\n\n");
- p += sprintf(p,
- "DMA enabled: %s %s"
- " %s %s\n",
- (c0&0x20) ? "Yes" : "No ",
- (c0&0x40) ? "Yes" : "No ",
- (c1&0x20) ? "Yes" : "No ",
- (c1&0x40) ? "Yes" : "No " );
-
- pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
- pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
- q = "FIFO threshold: %2d Words %2d Words"
- " %2d Words %2d Words\n";
- if (rev < 0xc1) {
- if ((rev == 0x20) &&
- (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
- p += sprintf(p, q, 8, 8, 8, 8);
- } else {
- p += sprintf(p, q,
- (reg5xh & 0x03) + 12,
- ((reg5xh & 0x30)>>4) + 12,
- (reg5yh & 0x03) + 12,
- ((reg5yh & 0x30)>>4) + 12 );
- }
- } else {
- int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
- int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
- int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
- int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
- p += sprintf(p, q, t1, t2, t3, t4);
- }
-
-#if 0
- p += sprintf(p,
- "FIFO threshold: %2d Words %2d Words"
- " %2d Words %2d Words\n",
- (reg5xh & 0x03) + 12,
- ((reg5xh & 0x30)>>4) + 12,
- (reg5yh & 0x03) + 12,
- ((reg5yh & 0x30)>>4) + 12 );
-#endif
-
- p += sprintf(p,
- "FIFO mode: %s %s %s %s\n",
- fifo[((reg5xh & 0x0c) >> 2)],
- fifo[((reg5xh & 0xc0) >> 6)],
- fifo[((reg5yh & 0x0c) >> 2)],
- fifo[((reg5yh & 0xc0) >> 6)] );
-
- pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
- pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
- pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
- pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
-
- p += sprintf(p,/*
- "------------------drive0-----------drive1"
- "------------drive0-----------drive1------\n")*/
- "Dt RW act. Cnt %2dT %2dT"
- " %2dT %2dT\n"
- "Dt RW rec. Cnt %2dT %2dT"
- " %2dT %2dT\n\n",
- (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
- (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
- (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
- (reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
- (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
- (reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
- (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
- (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
-
- p += sprintf(p,
- "-----------------------------------UDMA Timings"
- "--------------------------------\n\n");
-
- pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
- pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
- p += sprintf(p,
- "UDMA: %s %s"
- " %s %s\n"
- "UDMA timings: %s %s"
- " %s %s\n\n",
- (reg5xh & 0x08) ? "OK" : "No",
- (reg5xh & 0x80) ? "OK" : "No",
- (reg5yh & 0x08) ? "OK" : "No",
- (reg5yh & 0x80) ? "OK" : "No",
- udmaT[(reg5xh & 0x07)],
- udmaT[(reg5xh & 0x70) >> 4],
- udmaT[reg5yh & 0x07],
- udmaT[(reg5yh & 0x70) >> 4] );
-
- return p-buffer; /* => must be less than 4k! */
-}
-#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
-
/**
* ali_set_pio_mode - set host controller for PIO mode
* @drive: drive
@@ -294,7 +62,7 @@ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
int s_time, a_time, c_time;
u8 s_clc, a_clc, r_clc;
unsigned long flags;
- int bus_speed = system_bus_clock();
+ int bus_speed = ide_pci_clk ? ide_pci_clk : system_bus_clock();
int port = hwif->channel ? 0x5c : 0x58;
int portFIFO = hwif->channel ? 0x55 : 0x54;
u8 cd_dma_fifo = 0;
@@ -465,14 +233,6 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
- if (!ali_proc) {
- ali_proc = 1;
- bmide_dev = dev;
- ide_pci_create_host_proc("ali", ali_get_info);
- }
-#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
-
local_irq_save(flags);
if (m5229_revision < 0xC2) {
@@ -610,7 +370,7 @@ static int ali_cable_override(struct pci_dev *pdev)
}
/**
- * ata66_ali15x3 - check for UDMA 66 support
+ * ali_cable_detect - cable detection
* @hwif: IDE interface
*
* This checks if the controller and the cable are capable
@@ -620,7 +380,7 @@ static int ali_cable_override(struct pci_dev *pdev)
* FIXME: frobs bits that are not defined on newer ALi devicea
*/
-static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
+static u8 __devinit ali_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long flags;
@@ -652,27 +412,7 @@ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
return cbl;
}
-/**
- * init_hwif_common_ali15x3 - Set up ALI IDE hardware
- * @hwif: IDE interface
- *
- * Initialize the IDE structure side of the ALi 15x3 driver.
- */
-
-static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &ali_set_pio_mode;
- hwif->set_dma_mode = &ali_set_dma_mode;
- hwif->udma_filter = &ali_udma_filter;
-
- hwif->cable_detect = ata66_ali15x3;
-
- if (hwif->dma_base == 0)
- return;
-
- hwif->dma_setup = &ali15x3_dma_setup;
-}
-
+#ifndef CONFIG_SPARC64
/**
* init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff
* @hwif: interface to configure
@@ -722,35 +462,66 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
if(irq >= 0)
hwif->irq = irq;
}
-
- init_hwif_common_ali15x3(hwif);
}
+#endif
/**
* init_dma_ali15x3 - set up DMA on ALi15x3
* @hwif: IDE interface
- * @dmabase: DMA interface base PCI address
+ * @d: IDE port info
*
- * Set up the DMA functionality on the ALi 15x3. For the ALi
- * controllers this is generic so we can let the generic code do
- * the actual work.
+ * Set up the DMA functionality on the ALi 15x3.
*/
-static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+static int __devinit init_dma_ali15x3(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
{
- if (m5229_revision < 0x20)
- return;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long base = ide_pci_dma_base(hwif, d);
+
+ if (base == 0 || ide_pci_set_master(dev, d->name) < 0)
+ return -1;
+
if (!hwif->channel)
- outb(inb(dmabase + 2) & 0x60, dmabase + 2);
- ide_setup_dma(hwif, dmabase);
+ outb(inb(base + 2) & 0x60, base + 2);
+
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, base, base + 7);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ ide_setup_dma(hwif, base);
+
+ return 0;
}
+static const struct ide_port_ops ali_port_ops = {
+ .set_pio_mode = ali_set_pio_mode,
+ .set_dma_mode = ali_set_dma_mode,
+ .udma_filter = ali_udma_filter,
+ .cable_detect = ali_cable_detect,
+};
+
+static const struct ide_dma_ops ali_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ali15x3_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
static const struct ide_port_info ali15x3_chipset __devinitdata = {
.name = "ALI15X3",
.init_chipset = init_chipset_ali15x3,
+#ifndef CONFIG_SPARC64
.init_hwif = init_hwif_ali15x3,
+#endif
.init_dma = init_dma_ali15x3,
- .host_flags = IDE_HFLAG_BOOTABLE,
+ .port_ops = &ali_port_ops,
.pio_mask = ATA_PIO5,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
@@ -793,14 +564,17 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
d.udma_mask = ATA_UDMA5;
else
d.udma_mask = ATA_UDMA6;
+
+ d.dma_ops = &ali_dma_ops;
+ } else {
+ d.host_flags |= IDE_HFLAG_NO_DMA;
+
+ d.mwdma_mask = d.swdma_mask = 0;
}
if (idx == 0)
d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
-#if defined(CONFIG_SPARC64)
- d.init_hwif = init_hwif_common_ali15x3;
-#endif /* CONFIG_SPARC64 */
return ide_setup_pci_device(dev, &d);
}
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 2ef890ce8097..efcf54338be7 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -179,7 +179,7 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev,
* Determine the system bus clock.
*/
- amd_clock = system_bus_clock() * 1000;
+ amd_clock = (ide_pci_clk ? ide_pci_clk : system_bus_clock()) * 1000;
switch (amd_clock) {
case 33000: amd_clock = 33333; break;
@@ -210,21 +210,20 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
if (hwif->irq == 0) /* 0 is bogus but will do for now */
hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
-
- hwif->set_pio_mode = &amd_set_pio_mode;
- hwif->set_dma_mode = &amd_set_drive;
-
- hwif->cable_detect = amd_cable_detect;
}
+static const struct ide_port_ops amd_port_ops = {
+ .set_pio_mode = amd_set_pio_mode,
+ .set_dma_mode = amd_set_drive,
+ .cable_detect = amd_cable_detect,
+};
+
#define IDE_HFLAGS_AMD \
(IDE_HFLAG_PIO_NO_BLACKLIST | \
- IDE_HFLAG_PIO_NO_DOWNGRADE | \
IDE_HFLAG_ABUSE_SET_DMA_MODE | \
IDE_HFLAG_POST_SET_MODE | \
IDE_HFLAG_IO_32BIT | \
- IDE_HFLAG_UNMASK_IRQS | \
- IDE_HFLAG_BOOTABLE)
+ IDE_HFLAG_UNMASK_IRQS)
#define DECLARE_AMD_DEV(name_str, swdma, udma) \
{ \
@@ -232,6 +231,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
+ .port_ops = &amd_port_ops, \
.host_flags = IDE_HFLAGS_AMD, \
.pio_mask = ATA_PIO5, \
.swdma_mask = swdma, \
@@ -245,6 +245,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
+ .port_ops = &amd_port_ops, \
.host_flags = IDE_HFLAGS_AMD, \
.pio_mask = ATA_PIO5, \
.swdma_mask = ATA_SWDMA2, \
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 7e037c880cb0..8b637181681a 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -130,37 +130,26 @@ static u8 __devinit atiixp_cable_detect(ide_hwif_t *hwif)
return ATA_CBL_PATA40;
}
-/**
- * init_hwif_atiixp - fill in the hwif for the ATIIXP
- * @hwif: IDE interface
- *
- * Set up the ide_hwif_t for the ATIIXP interface according to the
- * capabilities of the hardware.
- */
-
-static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &atiixp_set_pio_mode;
- hwif->set_dma_mode = &atiixp_set_dma_mode;
-
- hwif->cable_detect = atiixp_cable_detect;
-}
+static const struct ide_port_ops atiixp_port_ops = {
+ .set_pio_mode = atiixp_set_pio_mode,
+ .set_dma_mode = atiixp_set_dma_mode,
+ .cable_detect = atiixp_cable_detect,
+};
static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.name = "ATIIXP",
- .init_hwif = init_hwif_atiixp,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
- .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+ .port_ops = &atiixp_port_ops,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
},{ /* 1 */
.name = "SB600_PATA",
- .init_hwif = init_hwif_atiixp,
.enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
- .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_LEGACY_IRQS |
- IDE_HFLAG_BOOTABLE,
+ .port_ops = &atiixp_port_ops,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_LEGACY_IRQS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index a1cfe033a55f..aaf38109eaec 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -4,7 +4,7 @@
/*
* Original authors: abramov@cecmow.enet.dec.com (Igor Abramov)
- * mlord@pobox.com (Mark Lord)
+ * mlord@pobox.com (Mark Lord)
*
* See linux/MAINTAINERS for address of current maintainer.
*
@@ -98,7 +98,7 @@
#define CMD640_PREFETCH_MASKS 1
-//#define CMD640_DUMP_REGS
+/*#define CMD640_DUMP_REGS */
#include <linux/types.h>
#include <linux/kernel.h>
@@ -109,10 +109,9 @@
#include <asm/io.h>
-/*
- * This flag is set in ide.c by the parameter: ide0=cmd640_vlb
- */
-int cmd640_vlb = 0;
+#define DRV_NAME "cmd640"
+
+static int cmd640_vlb;
/*
* CMD640 specific registers definition.
@@ -185,7 +184,6 @@ static DEFINE_SPINLOCK(cmd640_lock);
* These are initialized to point at the devices we control
*/
static ide_hwif_t *cmd_hwif0, *cmd_hwif1;
-static ide_drive_t *cmd_drives[4];
/*
* Interface to access cmd640x registers
@@ -207,13 +205,13 @@ static unsigned int cmd640_chip_version;
/* PCI method 1 access */
-static void put_cmd640_reg_pci1 (u16 reg, u8 val)
+static void put_cmd640_reg_pci1(u16 reg, u8 val)
{
outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
outb_p(val, (reg & 3) | 0xcfc);
}
-static u8 get_cmd640_reg_pci1 (u16 reg)
+static u8 get_cmd640_reg_pci1(u16 reg)
{
outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
return inb_p((reg & 3) | 0xcfc);
@@ -221,14 +219,14 @@ static u8 get_cmd640_reg_pci1 (u16 reg)
/* PCI method 2 access (from CMD datasheet) */
-static void put_cmd640_reg_pci2 (u16 reg, u8 val)
+static void put_cmd640_reg_pci2(u16 reg, u8 val)
{
outb_p(0x10, 0xcf8);
outb_p(val, cmd640_key + reg);
outb_p(0, 0xcf8);
}
-static u8 get_cmd640_reg_pci2 (u16 reg)
+static u8 get_cmd640_reg_pci2(u16 reg)
{
u8 b;
@@ -240,13 +238,13 @@ static u8 get_cmd640_reg_pci2 (u16 reg)
/* VLB access */
-static void put_cmd640_reg_vlb (u16 reg, u8 val)
+static void put_cmd640_reg_vlb(u16 reg, u8 val)
{
outb_p(reg, cmd640_key);
outb_p(val, cmd640_key + 4);
}
-static u8 get_cmd640_reg_vlb (u16 reg)
+static u8 get_cmd640_reg_vlb(u16 reg)
{
outb_p(reg, cmd640_key);
return inb_p(cmd640_key + 4);
@@ -268,11 +266,11 @@ static void put_cmd640_reg(u16 reg, u8 val)
unsigned long flags;
spin_lock_irqsave(&cmd640_lock, flags);
- __put_cmd640_reg(reg,val);
+ __put_cmd640_reg(reg, val);
spin_unlock_irqrestore(&cmd640_lock, flags);
}
-static int __init match_pci_cmd640_device (void)
+static int __init match_pci_cmd640_device(void)
{
const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
unsigned int i;
@@ -292,7 +290,7 @@ static int __init match_pci_cmd640_device (void)
/*
* Probe for CMD640x -- pci method 1
*/
-static int __init probe_for_cmd640_pci1 (void)
+static int __init probe_for_cmd640_pci1(void)
{
__get_cmd640_reg = get_cmd640_reg_pci1;
__put_cmd640_reg = put_cmd640_reg_pci1;
@@ -308,7 +306,7 @@ static int __init probe_for_cmd640_pci1 (void)
/*
* Probe for CMD640x -- pci method 2
*/
-static int __init probe_for_cmd640_pci2 (void)
+static int __init probe_for_cmd640_pci2(void)
{
__get_cmd640_reg = get_cmd640_reg_pci2;
__put_cmd640_reg = put_cmd640_reg_pci2;
@@ -322,7 +320,7 @@ static int __init probe_for_cmd640_pci2 (void)
/*
* Probe for CMD640x -- vlb
*/
-static int __init probe_for_cmd640_vlb (void)
+static int __init probe_for_cmd640_vlb(void)
{
u8 b;
@@ -343,18 +341,18 @@ static int __init probe_for_cmd640_vlb (void)
* Returns 1 if an IDE interface/drive exists at 0x170,
* Returns 0 otherwise.
*/
-static int __init secondary_port_responding (void)
+static int __init secondary_port_responding(void)
{
unsigned long flags;
spin_lock_irqsave(&cmd640_lock, flags);
- outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */
+ outb_p(0x0a, 0x176); /* select drive0 */
udelay(100);
- if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
- outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+ if ((inb_p(0x176) & 0x1f) != 0x0a) {
+ outb_p(0x1a, 0x176); /* select drive1 */
udelay(100);
- if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+ if ((inb_p(0x176) & 0x1f) != 0x1a) {
spin_unlock_irqrestore(&cmd640_lock, flags);
return 0; /* nothing responded */
}
@@ -367,7 +365,7 @@ static int __init secondary_port_responding (void)
/*
* Dump out all cmd640 registers. May be called from ide.c
*/
-static void cmd640_dump_regs (void)
+static void cmd640_dump_regs(void)
{
unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
@@ -382,13 +380,13 @@ static void cmd640_dump_regs (void)
}
#endif
+#ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
/*
* Check whether prefetch is on for a drive,
* and initialize the unmask flags for safe operation.
*/
-static void __init check_prefetch (unsigned int index)
+static void __init check_prefetch(ide_drive_t *drive, unsigned int index)
{
- ide_drive_t *drive = cmd_drives[index];
u8 b = get_cmd640_reg(prefetch_regs[index]);
if (b & prefetch_masks[index]) { /* is prefetch off? */
@@ -403,29 +401,12 @@ static void __init check_prefetch (unsigned int index)
drive->no_io_32bit = 0;
}
}
-
-/*
- * Figure out which devices we control
- */
-static void __init setup_device_ptrs (void)
-{
- cmd_hwif0 = &ide_hwifs[0];
- cmd_hwif1 = &ide_hwifs[1];
-
- cmd_drives[0] = &cmd_hwif0->drives[0];
- cmd_drives[1] = &cmd_hwif0->drives[1];
- cmd_drives[2] = &cmd_hwif1->drives[0];
- cmd_drives[3] = &cmd_hwif1->drives[1];
-}
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
+#else
/*
* Sets prefetch mode for a drive.
*/
-static void set_prefetch_mode (unsigned int index, int mode)
+static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode)
{
- ide_drive_t *drive = cmd_drives[index];
unsigned long flags;
int reg = prefetch_regs[index];
u8 b;
@@ -452,7 +433,7 @@ static void set_prefetch_mode (unsigned int index, int mode)
/*
* Dump out current drive clocks settings
*/
-static void display_clocks (unsigned int index)
+static void display_clocks(unsigned int index)
{
u8 active_count, recovery_count;
@@ -471,44 +452,16 @@ static void display_clocks (unsigned int index)
* Pack active and recovery counts into single byte representation
* used by controller
*/
-static inline u8 pack_nibbles (u8 upper, u8 lower)
+static inline u8 pack_nibbles(u8 upper, u8 lower)
{
return ((upper & 0x0f) << 4) | (lower & 0x0f);
}
/*
- * This routine retrieves the initial drive timings from the chipset.
- */
-static void __init retrieve_drive_counts (unsigned int index)
-{
- u8 b;
-
- /*
- * Get the internal setup timing, and convert to clock count
- */
- b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
- switch (b) {
- case 0x00: b = 4; break;
- case 0x80: b = 3; break;
- case 0x40: b = 2; break;
- default: b = 5; break;
- }
- setup_counts[index] = b;
-
- /*
- * Get the active/recovery counts
- */
- b = get_cmd640_reg(drwtim_regs[index]);
- active_counts[index] = (b >> 4) ? (b >> 4) : 0x10;
- recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
-}
-
-
-/*
* This routine writes the prepared setup/active/recovery counts
* for a drive into the cmd640 chipset registers to active them.
*/
-static void program_drive_counts (unsigned int index)
+static void program_drive_counts(ide_drive_t *drive, unsigned int index)
{
unsigned long flags;
u8 setup_count = setup_counts[index];
@@ -522,8 +475,11 @@ static void program_drive_counts (unsigned int index)
* so we merge the timings, using the slowest value for each timing.
*/
if (index > 1) {
- unsigned int mate;
- if (cmd_drives[mate = index ^ 1]->present) {
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *peer = &hwif->drives[!drive->select.b.unit];
+ unsigned int mate = index ^ 1;
+
+ if (peer->present) {
if (setup_count < setup_counts[mate])
setup_count = setup_counts[mate];
if (active_count < active_counts[mate])
@@ -537,11 +493,11 @@ static void program_drive_counts (unsigned int index)
* Convert setup_count to internal chipset representation
*/
switch (setup_count) {
- case 4: setup_count = 0x00; break;
- case 3: setup_count = 0x80; break;
- case 1:
- case 2: setup_count = 0x40; break;
- default: setup_count = 0xc0; /* case 5 */
+ case 4: setup_count = 0x00; break;
+ case 3: setup_count = 0x80; break;
+ case 1:
+ case 2: setup_count = 0x40; break;
+ default: setup_count = 0xc0; /* case 5 */
}
/*
@@ -562,11 +518,19 @@ static void program_drive_counts (unsigned int index)
/*
* Set a specific pio_mode for a drive
*/
-static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time)
+static void cmd640_set_mode(ide_drive_t *drive, unsigned int index,
+ u8 pio_mode, unsigned int cycle_time)
{
int setup_time, active_time, recovery_time, clock_time;
u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
- int bus_speed = system_bus_clock();
+ int bus_speed;
+
+ if (cmd640_vlb && ide_vlb_clk)
+ bus_speed = ide_vlb_clk;
+ else if (!cmd640_vlb && ide_pci_clk)
+ bus_speed = ide_pci_clk;
+ else
+ bus_speed = system_bus_clock();
if (pio_mode > 5)
pio_mode = 5;
@@ -574,15 +538,15 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
active_time = ide_pio_timings[pio_mode].active_time;
recovery_time = cycle_time - (setup_time + active_time);
clock_time = 1000 / bus_speed;
- cycle_count = (cycle_time + clock_time - 1) / clock_time;
+ cycle_count = DIV_ROUND_UP(cycle_time, clock_time);
- setup_count = (setup_time + clock_time - 1) / clock_time;
+ setup_count = DIV_ROUND_UP(setup_time, clock_time);
- active_count = (active_time + clock_time - 1) / clock_time;
+ active_count = DIV_ROUND_UP(active_time, clock_time);
if (active_count < 2)
active_count = 2; /* minimum allowed by cmd640 */
- recovery_count = (recovery_time + clock_time - 1) / clock_time;
+ recovery_count = DIV_ROUND_UP(recovery_time, clock_time);
recovery_count2 = cycle_count - (setup_count + active_count);
if (recovery_count2 > recovery_count)
recovery_count = recovery_count2;
@@ -611,7 +575,7 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
* 1) this is the wrong place to do it (proper is do_special() in ide.c)
* 2) in practice this is rarely, if ever, necessary
*/
- program_drive_counts (index);
+ program_drive_counts(drive, index);
}
static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
@@ -619,32 +583,26 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
unsigned int index = 0, cycle_time;
u8 b;
- while (drive != cmd_drives[index]) {
- if (++index > 3) {
- printk(KERN_ERR "%s: bad news in %s\n",
- drive->name, __FUNCTION__);
- return;
- }
- }
switch (pio) {
- case 6: /* set fast-devsel off */
- case 7: /* set fast-devsel on */
- b = get_cmd640_reg(CNTRL) & ~0x27;
- if (pio & 1)
- b |= 0x27;
- put_cmd640_reg(CNTRL, b);
- printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, (pio & 1) ? "en" : "dis");
- return;
-
- case 8: /* set prefetch off */
- case 9: /* set prefetch on */
- set_prefetch_mode(index, pio & 1);
- printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis");
- return;
+ case 6: /* set fast-devsel off */
+ case 7: /* set fast-devsel on */
+ b = get_cmd640_reg(CNTRL) & ~0x27;
+ if (pio & 1)
+ b |= 0x27;
+ put_cmd640_reg(CNTRL, b);
+ printk("%s: %sabled cmd640 fast host timing (devsel)\n",
+ drive->name, (pio & 1) ? "en" : "dis");
+ return;
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ set_prefetch_mode(drive, index, pio & 1);
+ printk("%s: %sabled cmd640 prefetch\n",
+ drive->name, (pio & 1) ? "en" : "dis");
+ return;
}
cycle_time = ide_pio_cycle_time(drive, pio);
- cmd640_set_mode(index, pio, cycle_time);
+ cmd640_set_mode(drive, index, pio, cycle_time);
printk("%s: selected cmd640 PIO mode%d (%dns)",
drive->name, pio, cycle_time);
@@ -652,6 +610,9 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
display_clocks(index);
}
+static const struct ide_port_ops cmd640_port_ops = {
+ .set_pio_mode = cmd640_set_pio_mode,
+};
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
static int pci_conf1(void)
@@ -693,14 +654,32 @@ static const struct ide_port_info cmd640_port_info __initdata = {
.chipset = ide_cmd640,
.host_flags = IDE_HFLAG_SERIALIZE |
IDE_HFLAG_NO_DMA |
- IDE_HFLAG_NO_AUTOTUNE |
IDE_HFLAG_ABUSE_PREFETCH |
IDE_HFLAG_ABUSE_FAST_DEVSEL,
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ .port_ops = &cmd640_port_ops,
.pio_mask = ATA_PIO5,
#endif
};
+static int cmd640x_init_one(unsigned long base, unsigned long ctl)
+{
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
/*
* Probe for a cmd640 chipset, and initialize it if found.
*/
@@ -709,7 +688,7 @@ static int __init cmd640x_init(void)
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
int second_port_toggled = 0;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
- int second_port_cmd640 = 0;
+ int second_port_cmd640 = 0, rc;
const char *bus_type, *port2;
unsigned int index;
u8 b, cfr;
@@ -749,10 +728,21 @@ static int __init cmd640x_init(void)
cfr = get_cmd640_reg(CFR);
cmd640_chip_version = cfr & CFR_DEVREV;
if (cmd640_chip_version == 0) {
- printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+ printk("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
return 0;
}
+ rc = cmd640x_init_one(0x1f0, 0x3f6);
+ if (rc)
+ return rc;
+
+ rc = cmd640x_init_one(0x170, 0x376);
+ if (rc) {
+ release_region(0x3f6, 1);
+ release_region(0x1f0, 8);
+ return rc;
+ }
+
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
@@ -764,17 +754,15 @@ static int __init cmd640x_init(void)
printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
"\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
+ cmd_hwif0 = ide_find_port();
+
/*
* Initialize data for primary port
*/
- setup_device_ptrs ();
-
- ide_init_port_hw(cmd_hwif0, &hw[0]);
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
- idx[0] = cmd_hwif0->index;
+ if (cmd_hwif0) {
+ ide_init_port_hw(cmd_hwif0, &hw[0]);
+ idx[0] = cmd_hwif0->index;
+ }
/*
* Ensure compatibility by always using the slowest timings
@@ -786,10 +774,13 @@ static int __init cmd640x_init(void)
put_cmd640_reg(CMDTIM, 0);
put_cmd640_reg(BRST, 0x40);
+ cmd_hwif1 = ide_find_port();
+
/*
* Try to enable the secondary interface, if not already enabled
*/
- if (cmd_hwif1->drives[0].noprobe && cmd_hwif1->drives[1].noprobe) {
+ if (cmd_hwif1 &&
+ cmd_hwif1->drives[0].noprobe && cmd_hwif1->drives[1].noprobe) {
port2 = "not probed";
} else {
b = get_cmd640_reg(CNTRL);
@@ -820,15 +811,11 @@ static int __init cmd640x_init(void)
/*
* Initialize data for secondary cmd640 port, if enabled
*/
- if (second_port_cmd640) {
+ if (second_port_cmd640 && cmd_hwif1) {
ide_init_port_hw(cmd_hwif1, &hw[1]);
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
idx[1] = cmd_hwif1->index;
}
- printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+ printk(KERN_INFO "cmd640: %sserialized, secondary interface %s\n",
second_port_cmd640 ? "" : "not ", port2);
/*
@@ -836,35 +823,34 @@ static int __init cmd640x_init(void)
* Do not unnecessarily disturb any prior BIOS setup of these.
*/
for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
- ide_drive_t *drive = cmd_drives[index];
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- if (drive->autotune || ((index > 1) && second_port_toggled)) {
- /*
- * Reset timing to the slowest speed and turn off prefetch.
- * This way, the drive identify code has a better chance.
- */
- setup_counts [index] = 4; /* max possible */
- active_counts [index] = 16; /* max possible */
- recovery_counts [index] = 16; /* max possible */
- program_drive_counts (index);
- set_prefetch_mode (index, 0);
- printk("cmd640: drive%d timings/prefetch cleared\n", index);
- } else {
- /*
- * Record timings/prefetch without changing them.
- * This preserves any prior BIOS setup.
- */
- retrieve_drive_counts (index);
- check_prefetch (index);
- printk("cmd640: drive%d timings/prefetch(%s) preserved",
- index, drive->no_io_32bit ? "off" : "on");
- display_clocks(index);
+ ide_drive_t *drive;
+
+ if (index > 1) {
+ if (cmd_hwif1 == NULL)
+ continue;
+ drive = &cmd_hwif1->drives[index & 1];
+ } else {
+ if (cmd_hwif0 == NULL)
+ continue;
+ drive = &cmd_hwif0->drives[index & 1];
}
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ /*
+ * Reset timing to the slowest speed and turn off prefetch.
+ * This way, the drive identify code has a better chance.
+ */
+ setup_counts [index] = 4; /* max possible */
+ active_counts [index] = 16; /* max possible */
+ recovery_counts [index] = 16; /* max possible */
+ program_drive_counts(drive, index);
+ set_prefetch_mode(drive, index, 0);
+ printk("cmd640: drive%d timings/prefetch cleared\n", index);
#else
/*
* Set the drive unmask flags to match the prefetch setting
*/
- check_prefetch (index);
+ check_prefetch(drive, index);
printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
index, drive->no_io_32bit ? "off" : "on");
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index edabe6299efd..08674711d089 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -68,8 +68,8 @@ static u8 quantize_timing(int timing, int quant)
*/
static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- int clock_time = 1000 / system_bus_clock();
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ int clock_time = 1000 / (ide_pci_clk ? ide_pci_clk : system_bus_clock());
u8 cycle_count, active_count, recovery_count, drwtim;
static const u8 recovery_values[] =
{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
@@ -128,7 +128,7 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
ide_pio_timings[pio].active_time);
setup_count = quantize_timing(ide_pio_timings[pio].setup_time,
- 1000 / system_bus_clock());
+ 1000 / (ide_pci_clk ? ide_pci_clk : system_bus_clock()));
/*
* The primary channel has individual address setup timing registers
@@ -223,7 +223,7 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
(void) pci_write_config_byte(dev, pciU, regU);
}
-static int cmd648_ide_dma_end (ide_drive_t *drive)
+static int cmd648_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long base = hwif->dma_base - (hwif->channel * 8);
@@ -239,7 +239,7 @@ static int cmd648_ide_dma_end (ide_drive_t *drive)
return err;
}
-static int cmd64x_ide_dma_end (ide_drive_t *drive)
+static int cmd64x_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -256,7 +256,7 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
return err;
}
-static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
+static int cmd648_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long base = hwif->dma_base - (hwif->channel * 8);
@@ -279,7 +279,7 @@ static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
return 0;
}
-static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+static int cmd64x_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -310,7 +310,7 @@ static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
* event order for DMA transfers.
*/
-static int cmd646_1_ide_dma_end (ide_drive_t *drive)
+static int cmd646_1_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u8 dma_stat = 0, dma_cmd = 0;
@@ -370,7 +370,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
return 0;
}
-static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
+static u8 __devinit cmd64x_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01;
@@ -385,91 +385,85 @@ static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
}
}
-static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- hwif->set_pio_mode = &cmd64x_set_pio_mode;
- hwif->set_dma_mode = &cmd64x_set_dma_mode;
-
- hwif->cable_detect = ata66_cmd64x;
+static const struct ide_port_ops cmd64x_port_ops = {
+ .set_pio_mode = cmd64x_set_pio_mode,
+ .set_dma_mode = cmd64x_set_dma_mode,
+ .cable_detect = cmd64x_cable_detect,
+};
- if (!hwif->dma_base)
- return;
+static const struct ide_dma_ops cmd64x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = cmd64x_dma_end,
+ .dma_test_irq = cmd64x_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
- /*
- * UltraDMA only supported on PCI646U and PCI646U2, which
- * correspond to revisions 0x03, 0x05 and 0x07 respectively.
- * Actually, although the CMD tech support people won't
- * tell me the details, the 0x03 revision cannot support
- * UDMA correctly without hardware modifications, and even
- * then it only works with Quantum disks due to some
- * hold time assumptions in the 646U part which are fixed
- * in the 646U2.
- *
- * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
- */
- if (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 5)
- hwif->ultra_mask = 0x00;
+static const struct ide_dma_ops cmd646_rev1_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = cmd646_1_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
- switch (dev->device) {
- case PCI_DEVICE_ID_CMD_648:
- case PCI_DEVICE_ID_CMD_649:
- alt_irq_bits:
- hwif->ide_dma_end = &cmd648_ide_dma_end;
- hwif->ide_dma_test_irq = &cmd648_ide_dma_test_irq;
- break;
- case PCI_DEVICE_ID_CMD_646:
- if (dev->revision == 0x01) {
- hwif->ide_dma_end = &cmd646_1_ide_dma_end;
- break;
- } else if (dev->revision >= 0x03)
- goto alt_irq_bits;
- /* fall thru */
- default:
- hwif->ide_dma_end = &cmd64x_ide_dma_end;
- hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
- break;
- }
-}
+static const struct ide_dma_ops cmd648_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = cmd648_dma_end,
+ .dma_test_irq = cmd648_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
{ /* 0 */
.name = "CMD643",
.init_chipset = init_chipset_cmd64x,
- .init_hwif = init_hwif_cmd64x,
.enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd64x_dma_ops,
.host_flags = IDE_HFLAG_CLEAR_SIMPLEX |
- IDE_HFLAG_ABUSE_PREFETCH |
- IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_ABUSE_PREFETCH,
.pio_mask = ATA_PIO5,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = 0x00, /* no udma */
},{ /* 1 */
.name = "CMD646",
.init_chipset = init_chipset_cmd64x,
- .init_hwif = init_hwif_cmd64x,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.chipset = ide_cmd646,
- .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd648_dma_ops,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
.pio_mask = ATA_PIO5,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
},{ /* 2 */
.name = "CMD648",
.init_chipset = init_chipset_cmd64x,
- .init_hwif = init_hwif_cmd64x,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd648_dma_ops,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
.pio_mask = ATA_PIO5,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
},{ /* 3 */
.name = "CMD649",
.init_chipset = init_chipset_cmd64x,
- .init_hwif = init_hwif_cmd64x,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd648_dma_ops,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
.pio_mask = ATA_PIO5,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
@@ -483,12 +477,35 @@ static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_devic
d = cmd64x_chipsets[idx];
- /*
- * The original PCI0646 didn't have the primary channel enable bit,
- * it appeared starting with PCI0646U (i.e. revision ID 3).
- */
- if (idx == 1 && dev->revision < 3)
- d.enablebits[0].reg = 0;
+ if (idx == 1) {
+ /*
+ * UltraDMA only supported on PCI646U and PCI646U2, which
+ * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+ * Actually, although the CMD tech support people won't
+ * tell me the details, the 0x03 revision cannot support
+ * UDMA correctly without hardware modifications, and even
+ * then it only works with Quantum disks due to some
+ * hold time assumptions in the 646U part which are fixed
+ * in the 646U2.
+ *
+ * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+ */
+ if (dev->revision < 5) {
+ d.udma_mask = 0x00;
+ /*
+ * The original PCI0646 didn't have the primary
+ * channel enable bit, it appeared starting with
+ * PCI0646U (i.e. revision ID 3).
+ */
+ if (dev->revision < 3) {
+ d.enablebits[0].reg = 0;
+ if (dev->revision == 1)
+ d.dma_ops = &cmd646_rev1_dma_ops;
+ else
+ d.dma_ops = &cmd64x_dma_ops;
+ }
+ }
+ }
return ide_setup_pci_device(dev, &d);
}
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 1c163e4ef03f..17669a434438 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -103,27 +103,32 @@ static void cs5520_dma_host_set(ide_drive_t *drive, int on)
ide_dma_host_set(drive, on);
}
-static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &cs5520_set_pio_mode;
- hwif->set_dma_mode = &cs5520_set_dma_mode;
-
- if (hwif->dma_base == 0)
- return;
+static const struct ide_port_ops cs5520_port_ops = {
+ .set_pio_mode = cs5520_set_pio_mode,
+ .set_dma_mode = cs5520_set_dma_mode,
+};
- hwif->dma_host_set = &cs5520_dma_host_set;
-}
+static const struct ide_dma_ops cs5520_dma_ops = {
+ .dma_host_set = cs5520_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
#define DECLARE_CS_DEV(name_str) \
{ \
.name = name_str, \
- .init_hwif = init_hwif_cs5520, \
+ .port_ops = &cs5520_port_ops, \
+ .dma_ops = &cs5520_dma_ops, \
.host_flags = IDE_HFLAG_ISA_PORTS | \
IDE_HFLAG_CS5520 | \
IDE_HFLAG_VDMA | \
IDE_HFLAG_NO_ATAPI_DMA | \
- IDE_HFLAG_ABUSE_SET_DMA_MODE |\
- IDE_HFLAG_BOOTABLE, \
+ IDE_HFLAG_ABUSE_SET_DMA_MODE, \
.pio_mask = ATA_PIO4, \
}
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 941a1344820b..f5534c1ff349 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -228,29 +228,27 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
unsigned long basereg;
u32 d0_timings;
- hwif->set_pio_mode = &cs5530_set_pio_mode;
- hwif->set_dma_mode = &cs5530_set_dma_mode;
-
basereg = CS5530_BASEREG(hwif);
d0_timings = inl(basereg + 0);
if (CS5530_BAD_PIO(d0_timings))
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
if (CS5530_BAD_PIO(inl(basereg + 8)))
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
-
- if (hwif->dma_base == 0)
- return;
-
- hwif->udma_filter = cs5530_udma_filter;
}
+static const struct ide_port_ops cs5530_port_ops = {
+ .set_pio_mode = cs5530_set_pio_mode,
+ .set_dma_mode = cs5530_set_dma_mode,
+ .udma_filter = cs5530_udma_filter,
+};
+
static const struct ide_port_info cs5530_chipset __devinitdata = {
.name = "CS5530",
.init_chipset = init_chipset_cs5530,
.init_hwif = init_hwif_cs5530,
+ .port_ops = &cs5530_port_ops,
.host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_POST_SET_MODE,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index d7b5ea992e94..99fe91a191b8 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -166,27 +166,17 @@ static u8 __devinit cs5535_cable_detect(ide_hwif_t *hwif)
return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
}
-/****
- * init_hwif_cs5535 - Initialize one ide cannel
- * @hwif: Channel descriptor
- *
- * This gets invoked by the IDE driver once for each channel. It
- * performs channel-specific pre-initialization before drive probing.
- *
- */
-static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &cs5535_set_pio_mode;
- hwif->set_dma_mode = &cs5535_set_dma_mode;
-
- hwif->cable_detect = cs5535_cable_detect;
-}
+static const struct ide_port_ops cs5535_port_ops = {
+ .set_pio_mode = cs5535_set_pio_mode,
+ .set_dma_mode = cs5535_set_dma_mode,
+ .cable_detect = cs5535_cable_detect,
+};
static const struct ide_port_info cs5535_chipset __devinitdata = {
.name = "CS5535",
- .init_hwif = init_hwif_cs5535,
+ .port_ops = &cs5535_port_ops,
.host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_ABUSE_SET_DMA_MODE,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 724cbacf4e5b..77cc22c2ad45 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -6,7 +6,7 @@
*
* The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
* Writing the driver was quite simple, since most of the job is
- * done by the generic pci-ide support.
+ * done by the generic pci-ide support.
* The hard part was finding the CY82C693's datasheet on Cypress's
* web page :-(. But Altavista solved this problem :-).
*
@@ -15,12 +15,10 @@
* - I recently got a 16.8G IBM DTTA, so I was able to test it with
* a large and fast disk - the results look great, so I'd say the
* driver is working fine :-)
- * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA
- * - this is my first linux driver, so there's probably a lot of room
+ * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA
+ * - this is my first linux driver, so there's probably a lot of room
* for optimizations and bug fixing, so feel free to do it.
- * - use idebus=xx parameter to set PCI bus speed - needed to calc
- * timings for PIO modes (default will be 40)
- * - if using PIO mode it's a good idea to set the PIO mode and
+ * - if using PIO mode it's a good idea to set the PIO mode and
* 32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
* - I had some problems with my IBM DHEA with PIO modes < 2
* (lost interrupts) ?????
@@ -110,11 +108,11 @@ typedef struct pio_clocks_s {
* calc clocks using bus_speed
* returns (rounded up) time in bus clocks for time in ns
*/
-static int calc_clk (int time, int bus_speed)
+static int calc_clk(int time, int bus_speed)
{
int clocks;
- clocks = (time*bus_speed+999)/1000 -1;
+ clocks = (time*bus_speed+999)/1000 - 1;
if (clocks < 0)
clocks = 0;
@@ -132,11 +130,11 @@ static int calc_clk (int time, int bus_speed)
* NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
* for mode 3 and 4 drives 8 and 16-bit timings are the same
*
- */
-static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+ */
+static void compute_clocks(u8 pio, pio_clocks_t *p_pclk)
{
int clk1, clk2;
- int bus_speed = system_bus_clock(); /* get speed of PCI bus */
+ int bus_speed = ide_pci_clk ? ide_pci_clk : system_bus_clock();
/* we don't check against CY82C693's min and max speed,
* so you can play with the idebus=xx parameter
@@ -158,7 +156,7 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
clk1 = (clk1<<4)|clk2; /* combine active and recovery clocks */
/* note: we use the same values for 16bit IOR and IOW
- * those are all the same, since I don't have other
+ * those are all the same, since I don't have other
* timings than those from ide-lib.c
*/
@@ -186,7 +184,7 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
outb(index, CY82_INDEX_PORT);
data = inb(CY82_DATA_PORT);
- printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+ printk(KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
drive->name, HWIF(drive)->channel, drive->select.b.unit,
(data&0x3), ((data>>2)&1));
#endif /* CY82C693_DEBUG_LOGS */
@@ -202,7 +200,7 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
mode & 3, single);
#endif /* CY82C693_DEBUG_INFO */
- /*
+ /*
* note: below we set the value for Bus Master IDE TimeOut Register
* I'm not absolutly sure what this does, but it solved my problem
* with IDE DMA and sound, so I now can play sound and work with
@@ -216,8 +214,8 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
outb(data, CY82_DATA_PORT);
-#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+#if CY82C693_DEBUG_INFO
+ printk(KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
drive->name, data);
#endif /* CY82C693_DEBUG_INFO */
}
@@ -242,14 +240,14 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
#if CY82C693_DEBUG_LOGS
/* for debug let's show the register values */
-
- if (drive->select.b.unit == 0) {
+
+ if (drive->select.b.unit == 0) {
/*
- * get master drive registers
+ * get master drive registers
* address setup control register
* is 32 bit !!!
- */
- pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+ */
+ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
addrCtrl &= 0x0F;
/* now let's get the remaining registers */
@@ -261,7 +259,7 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
* set slave drive registers
* address setup control register
* is 32 bit !!!
- */
+ */
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
addrCtrl &= 0xF0;
@@ -288,9 +286,9 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
* set master drive
* address setup control register
* is 32 bit !!!
- */
+ */
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
+
addrCtrl &= (~0xF);
addrCtrl |= (unsigned int)pclk.address_time;
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
@@ -299,14 +297,14 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
-
+
addrCtrl &= 0xF;
} else {
/*
* set slave drive
* address setup control register
* is 32 bit !!!
- */
+ */
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
addrCtrl &= (~0xF0);
@@ -320,7 +318,7 @@ static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
addrCtrl >>= 4;
addrCtrl &= 0xF;
- }
+ }
#if CY82C693_DEBUG_INFO
printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
@@ -340,41 +338,41 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
#ifdef CY82C693_SETDMA_CLOCK
u8 data = 0;
-#endif /* CY82C693_SETDMA_CLOCK */
+#endif /* CY82C693_SETDMA_CLOCK */
/* write info about this verion of the driver */
printk(KERN_INFO CY82_VERSION "\n");
#ifdef CY82C693_SETDMA_CLOCK
/* okay let's set the DMA clock speed */
-
- outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
- data = inb(CY82_DATA_PORT);
+
+ outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+ data = inb(CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
name, data);
#endif /* CY82C693_DEBUG_INFO */
- /*
+ /*
* for some reason sometimes the DMA controller
* speed is set to ATCLK/2 ???? - we fix this here
- *
+ *
* note: i don't know what causes this strange behaviour,
* but even changing the dma speed doesn't solve it :-(
- * the ide performance is still only half the normal speed
- *
+ * the ide performance is still only half the normal speed
+ *
* if anybody knows what goes wrong with my machine, please
* let me know - ASK
- */
+ */
data |= 0x03;
- outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
- outb(data, CY82_DATA_PORT);
+ outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+ outb(data, CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+ printk(KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
name, data);
#endif /* CY82C693_DEBUG_INFO */
@@ -382,15 +380,6 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
return 0;
}
-/*
- * the init function - called for each ide channel once
- */
-static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &cy82c693_set_pio_mode;
- hwif->set_dma_mode = &cy82c693_set_dma_mode;
-}
-
static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
{
static ide_hwif_t *primary;
@@ -404,14 +393,18 @@ static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
}
}
+static const struct ide_port_ops cy82c693_port_ops = {
+ .set_pio_mode = cy82c693_set_pio_mode,
+ .set_dma_mode = cy82c693_set_dma_mode,
+};
+
static const struct ide_port_info cy82c693_chipset __devinitdata = {
.name = "CY82C693",
.init_chipset = init_chipset_cy82c693,
.init_iops = init_iops_cy82c693,
- .init_hwif = init_hwif_cy82c693,
+ .port_ops = &cy82c693_port_ops,
.chipset = ide_cy82c693,
- .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 |
- IDE_HFLAG_BOOTABLE,
+ .host_flags = IDE_HFLAG_SINGLE,
.pio_mask = ATA_PIO4,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
@@ -424,7 +417,7 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev
/* CY82C693 is more than only a IDE controller.
Function 1 is primary IDE channel, function 2 - secondary. */
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
PCI_FUNC(dev->devfn) == 1) {
dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
ret = ide_setup_pci_devices(dev, dev2, &cy82c693_chipset);
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index 961698d655eb..b9e457996d0e 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -43,6 +43,10 @@ static const u8 setup[] = {
0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
};
+static const struct ide_port_ops delkin_cb_port_ops = {
+ .quirkproc = ide_undecoded_slave,
+};
+
static int __devinit
delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
@@ -71,26 +75,21 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
if (setup[i])
outb(setup[i], base + i);
}
- pci_release_regions(dev); /* IDE layer handles regions itself */
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
hw.irq = dev->irq;
hw.chipset = ide_pci; /* this enables IRQ sharing */
- hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ hwif = ide_find_port();
if (hwif == NULL)
goto out_disable;
i = hwif->index;
- if (hwif->present)
- ide_unregister(i);
- else
- ide_init_port_data(hwif, i);
-
+ ide_init_port_data(hwif, i);
ide_init_port_hw(hwif, &hw);
- hwif->quirkproc = &ide_undecoded_slave;
+ hwif->port_ops = &delkin_cb_port_ops;
idx[0] = i;
@@ -110,6 +109,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
out_disable:
printk(KERN_ERR "delkin_cb: no IDE devices found\n");
+ pci_release_regions(dev);
pci_disable_device(dev);
return -ENODEV;
}
@@ -119,9 +119,9 @@ delkin_cb_remove (struct pci_dev *dev)
{
ide_hwif_t *hwif = pci_get_drvdata(dev);
- if (hwif)
- ide_unregister(hwif->index);
+ ide_unregister(hwif);
+ pci_release_regions(dev);
pci_disable_device(dev);
}
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 7fd83a9d4dee..041720e22762 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -38,8 +38,7 @@ MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE st
{ \
.name = name_str, \
.host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \
- extra_flags | \
- IDE_HFLAG_BOOTABLE, \
+ extra_flags, \
.swdma_mask = ATA_SWDMA2, \
.mwdma_mask = ATA_MWDMA2, \
.udma_mask = ATA_UDMA6, \
@@ -50,9 +49,8 @@ static const struct ide_port_info generic_chipsets[] __devinitdata = {
{ /* 1 */
.name = "NS87410",
- .enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_BOOTABLE,
+ .enablebits = { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} },
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
@@ -99,7 +97,7 @@ static const struct ide_port_info generic_chipsets[] __devinitdata = {
* Called when the PCI registration layer (or the IDE initialization)
* finds a device matching our IDE device tables.
*/
-
+
static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
const struct ide_port_info *d = &generic_chipsets[id->driver_data];
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 9f01da46b016..84c36c117194 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -115,11 +115,10 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
return dev->irq;
}
-static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &hpt34x_set_pio_mode;
- hwif->set_dma_mode = &hpt34x_set_mode;
-}
+static const struct ide_port_ops hpt34x_port_ops = {
+ .set_pio_mode = hpt34x_set_pio_mode,
+ .set_dma_mode = hpt34x_set_mode,
+};
#define IDE_HFLAGS_HPT34X \
(IDE_HFLAG_NO_ATAPI_DMA | \
@@ -131,16 +130,14 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
{ /* 0 */
.name = "HPT343",
.init_chipset = init_chipset_hpt34x,
- .init_hwif = init_hwif_hpt34x,
- .extra = 16,
- .host_flags = IDE_HFLAGS_HPT34X,
+ .port_ops = &hpt34x_port_ops,
+ .host_flags = IDE_HFLAGS_HPT34X | IDE_HFLAG_NON_BOOTABLE,
.pio_mask = ATA_PIO5,
},
{ /* 1 */
.name = "HPT345",
.init_chipset = init_chipset_hpt34x,
- .init_hwif = init_hwif_hpt34x,
- .extra = 16,
+ .port_ops = &hpt34x_port_ops,
.host_flags = IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO5,
#ifdef CONFIG_HPT34X_AUTODMA
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 82d0e318a1fe..c929dadaaaff 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -760,7 +760,7 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
}
} else
outb(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
- hwif->io_ports[IDE_CONTROL_OFFSET]);
+ hwif->io_ports.ctl_addr);
}
/*
@@ -776,7 +776,7 @@ static void hpt366_dma_lost_irq(ide_drive_t *drive)
pci_read_config_byte(dev, 0x52, &mcr3);
pci_read_config_byte(dev, 0x5a, &scr1);
printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
- drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+ drive->name, __func__, mcr1, mcr3, scr1);
if (scr1 & 0x10)
pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
ide_dma_lost_irq(drive);
@@ -808,7 +808,7 @@ static void hpt370_irq_timeout(ide_drive_t *drive)
hpt370_clear_engine(drive);
}
-static void hpt370_ide_dma_start(ide_drive_t *drive)
+static void hpt370_dma_start(ide_drive_t *drive)
{
#ifdef HPT_RESET_STATE_ENGINE
hpt370_clear_engine(drive);
@@ -816,7 +816,7 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
ide_dma_start(drive);
}
-static int hpt370_ide_dma_end(ide_drive_t *drive)
+static int hpt370_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u8 dma_stat = inb(hwif->dma_status);
@@ -838,7 +838,7 @@ static void hpt370_dma_timeout(ide_drive_t *drive)
}
/* returns 1 if DMA IRQ issued, 0 otherwise */
-static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
+static int hpt374_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -858,11 +858,11 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
if (!drive->waiting_for_dma)
printk(KERN_WARNING "%s: (%s) called while not waiting\n",
- drive->name, __FUNCTION__);
+ drive->name, __func__);
return 0;
}
-static int hpt374_ide_dma_end(ide_drive_t *drive)
+static int hpt374_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -1271,17 +1271,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
/* Cache the channel's MISC. control registers' offset */
hwif->select_data = hwif->channel ? 0x54 : 0x50;
- hwif->set_pio_mode = &hpt3xx_set_pio_mode;
- hwif->set_dma_mode = &hpt3xx_set_mode;
-
- hwif->quirkproc = &hpt3xx_quirkproc;
- hwif->maskproc = &hpt3xx_maskproc;
-
- hwif->udma_filter = &hpt3xx_udma_filter;
- hwif->mdma_filter = &hpt3xx_mdma_filter;
-
- hwif->cable_detect = hpt3xx_cable_detect;
-
/*
* HPT3xxN chips have some complications:
*
@@ -1323,29 +1312,19 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
if (new_mcr != old_mcr)
pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
-
- if (hwif->dma_base == 0)
- return;
-
- if (chip_type >= HPT374) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (chip_type >= HPT370) {
- hwif->dma_start = &hpt370_ide_dma_start;
- hwif->ide_dma_end = &hpt370_ide_dma_end;
- hwif->dma_timeout = &hpt370_dma_timeout;
- } else
- hwif->dma_lost_irq = &hpt366_dma_lost_irq;
}
-static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
+static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 masterdma = 0, slavedma = 0;
- u8 dma_new = 0, dma_old = 0;
- unsigned long flags;
+ unsigned long flags, base = ide_pci_dma_base(hwif, d);
+ u8 dma_old, dma_new, masterdma = 0, slavedma = 0;
- dma_old = inb(dmabase + 2);
+ if (base == 0 || ide_pci_set_master(dev, d->name) < 0)
+ return -1;
+
+ dma_old = inb(base + 2);
local_irq_save(flags);
@@ -1356,11 +1335,21 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
if (masterdma & 0x30) dma_new |= 0x20;
if ( slavedma & 0x30) dma_new |= 0x40;
if (dma_new != dma_old)
- outb(dma_new, dmabase + 2);
+ outb(dma_new, base + 2);
local_irq_restore(flags);
- ide_setup_dma(hwif, dmabase);
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, base, base + 7);
+
+ hwif->extra_base = base + (hwif->channel ? 8 : 16);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ ide_setup_dma(hwif, base);
+
+ return 0;
}
static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
@@ -1416,6 +1405,49 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
IDE_HFLAG_ABUSE_SET_DMA_MODE | \
IDE_HFLAG_OFF_BOARD)
+static const struct ide_port_ops hpt3xx_port_ops = {
+ .set_pio_mode = hpt3xx_set_pio_mode,
+ .set_dma_mode = hpt3xx_set_mode,
+ .quirkproc = hpt3xx_quirkproc,
+ .maskproc = hpt3xx_maskproc,
+ .mdma_filter = hpt3xx_mdma_filter,
+ .udma_filter = hpt3xx_udma_filter,
+ .cable_detect = hpt3xx_cable_detect,
+};
+
+static const struct ide_dma_ops hpt37x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = hpt374_dma_end,
+ .dma_test_irq = hpt374_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_dma_ops hpt370_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = hpt370_dma_start,
+ .dma_end = hpt370_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = hpt370_dma_timeout,
+};
+
+static const struct ide_dma_ops hpt36x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = hpt366_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
{ /* 0 */
.name = "HPT36x",
@@ -1429,7 +1461,8 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
* Bit 4 is for the primary channel, bit 5 for the secondary.
*/
.enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
- .extra = 240,
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt36x_dma_ops,
.host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -1439,7 +1472,8 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .extra = 240,
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt37x_dma_ops,
.host_flags = IDE_HFLAGS_HPT3XX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -1449,7 +1483,8 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .extra = 240,
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt37x_dma_ops,
.host_flags = IDE_HFLAGS_HPT3XX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -1459,7 +1494,8 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .extra = 240,
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt37x_dma_ops,
.host_flags = IDE_HFLAGS_HPT3XX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -1470,7 +1506,8 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
.init_dma = init_dma_hpt366,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = ATA_UDMA5,
- .extra = 240,
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt37x_dma_ops,
.host_flags = IDE_HFLAGS_HPT3XX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -1480,7 +1517,8 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .extra = 240,
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt37x_dma_ops,
.host_flags = IDE_HFLAGS_HPT3XX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -1543,6 +1581,10 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
d.name = info->chip_name;
d.udma_mask = info->udma_mask;
+ /* fixup ->dma_ops for HPT370/HPT370A */
+ if (info == &hpt370 || info == &hpt370a)
+ d.dma_ops = &hpt370_dma_ops;
+
pci_set_drvdata(dev, (void *)info);
if (info == &hpt36x || info == &hpt374)
@@ -1557,7 +1599,7 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
hpt374_init(dev, dev2);
else {
if (hpt36x_init(dev, dev2))
- d.host_flags |= IDE_HFLAG_BOOTABLE;
+ d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE;
}
ret = ide_setup_pci_devices(dev, dev2, &d);
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index e3427eaab430..9053c8771e6e 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -35,7 +35,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
static DEFINE_SPINLOCK(tune_lock);
int control = 0;
- static const u8 timings[][2]= {
+ static const u8 timings[][2] = {
{ 0, 0 },
{ 0, 0 },
{ 1, 0 },
@@ -105,11 +105,10 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
if (!(reg48 & u_flag))
pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- if (speed >= XFER_UDMA_5) {
+ if (speed >= XFER_UDMA_5)
pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
- } else {
+ else
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
- }
if ((reg4a & a_speed) != u_speed)
pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
@@ -150,29 +149,18 @@ static u8 __devinit it8213_cable_detect(ide_hwif_t *hwif)
return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
}
-/**
- * init_hwif_it8213 - set up hwif structs
- * @hwif: interface to set up
- *
- * We do the basic set up of the interface structure.
- */
-
-static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
-{
- hwif->set_dma_mode = &it8213_set_dma_mode;
- hwif->set_pio_mode = &it8213_set_pio_mode;
-
- hwif->cable_detect = it8213_cable_detect;
-}
-
+static const struct ide_port_ops it8213_port_ops = {
+ .set_pio_mode = it8213_set_pio_mode,
+ .set_dma_mode = it8213_set_dma_mode,
+ .cable_detect = it8213_cable_detect,
+};
#define DECLARE_ITE_DEV(name_str) \
{ \
.name = name_str, \
- .init_hwif = init_hwif_it8213, \
- .enablebits = {{0x41,0x80,0x80}}, \
- .host_flags = IDE_HFLAG_SINGLE | \
- IDE_HFLAG_BOOTABLE, \
+ .enablebits = { {0x41, 0x80, 0x80} }, \
+ .port_ops = &it8213_port_ops, \
+ .host_flags = IDE_HFLAG_SINGLE, \
.pio_mask = ATA_PIO4, \
.swdma_mask = ATA_SWDMA2_ONLY, \
.mwdma_mask = ATA_MWDMA12_ONLY, \
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index d8a167451fd6..6ab04115286b 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -418,7 +418,7 @@ static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
}
/**
- * ata66_it821x - check for 80 pin cable
+ * it821x_cable_detect - cable detection
* @hwif: interface to check
*
* Check for the presence of an ATA66 capable cable on the
@@ -426,7 +426,7 @@ static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
* the needed logic onboard.
*/
-static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
+static u8 __devinit it821x_cable_detect(ide_hwif_t *hwif)
{
/* The reference driver also only does disk side */
return ATA_CBL_PATA80;
@@ -511,6 +511,11 @@ static void __devinit it821x_quirkproc(ide_drive_t *drive)
}
+static struct ide_dma_ops it821x_pass_through_dma_ops = {
+ .dma_start = it821x_dma_start,
+ .dma_end = it821x_dma_end,
+};
+
/**
* init_hwif_it821x - set up hwif structs
* @hwif: interface to set up
@@ -523,16 +528,10 @@ static void __devinit it821x_quirkproc(ide_drive_t *drive)
static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+ struct it821x_dev **itdevs = (struct it821x_dev **)pci_get_drvdata(dev);
+ struct it821x_dev *idev = itdevs[hwif->channel];
u8 conf;
- hwif->quirkproc = &it821x_quirkproc;
-
- if (idev == NULL) {
- printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
- return;
- }
-
ide_set_hwifdata(hwif, idev);
pci_read_config_byte(dev, 0x50, &conf);
@@ -567,17 +566,11 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
}
if (idev->smart == 0) {
- hwif->set_pio_mode = &it821x_set_pio_mode;
- hwif->set_dma_mode = &it821x_set_dma_mode;
-
/* MWDMA/PIO clock switching for pass through mode */
- hwif->dma_start = &it821x_dma_start;
- hwif->ide_dma_end = &it821x_dma_end;
+ hwif->dma_ops = &it821x_pass_through_dma_ops;
} else
hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
- hwif->cable_detect = ata66_it821x;
-
if (hwif->dma_base == 0)
return;
@@ -617,13 +610,20 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
return 0;
}
+static const struct ide_port_ops it821x_port_ops = {
+ /* it821x_set_{pio,dma}_mode() are only used in pass-through mode */
+ .set_pio_mode = it821x_set_pio_mode,
+ .set_dma_mode = it821x_set_dma_mode,
+ .quirkproc = it821x_quirkproc,
+ .cable_detect = it821x_cable_detect,
+};
#define DECLARE_ITE_DEV(name_str) \
{ \
.name = name_str, \
.init_chipset = init_chipset_it821x, \
.init_hwif = init_hwif_it821x, \
- .host_flags = IDE_HFLAG_BOOTABLE, \
+ .port_ops = &it821x_port_ops, \
.pio_mask = ATA_PIO4, \
}
@@ -642,6 +642,22 @@ static const struct ide_port_info it821x_chipsets[] __devinitdata = {
static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
+ struct it821x_dev *itdevs[2] = { NULL, NULL} , *itdev;
+ unsigned int i;
+
+ for (i = 0; i < 2; i++) {
+ itdev = kzalloc(sizeof(*itdev), GFP_KERNEL);
+ if (itdev == NULL) {
+ kfree(itdevs[0]);
+ printk(KERN_ERR "it821x: out of memory\n");
+ return -ENOMEM;
+ }
+
+ itdevs[i] = itdev;
+ }
+
+ pci_set_drvdata(dev, itdevs);
+
return ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
}
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index a56bcb4f22f4..96ef7394f283 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -19,13 +19,13 @@ typedef enum {
} port_type;
/**
- * ata66_jmicron - Cable check
+ * jmicron_cable_detect - cable detection
* @hwif: IDE port
*
* Returns the cable type.
*/
-static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
+static u8 __devinit jmicron_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *pdev = to_pci_dev(hwif->dev);
@@ -63,8 +63,7 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
* actually do our cable checking etc. Thankfully we don't need
* to do the plumbing for other cases.
*/
- switch (port_map[port])
- {
+ switch (port_map[port]) {
case PORT_PATA0:
if (control & (1 << 3)) /* 40/80 pin primary */
return ATA_CBL_PATA40;
@@ -96,26 +95,16 @@ static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
}
-/**
- * init_hwif_jmicron - set up hwif structs
- * @hwif: interface to set up
- *
- * Minimal set up is required for the Jmicron hardware.
- */
-
-static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &jmicron_set_pio_mode;
- hwif->set_dma_mode = &jmicron_set_dma_mode;
-
- hwif->cable_detect = ata66_jmicron;
-}
+static const struct ide_port_ops jmicron_port_ops = {
+ .set_pio_mode = jmicron_set_pio_mode,
+ .set_dma_mode = jmicron_set_dma_mode,
+ .cable_detect = jmicron_cable_detect,
+};
static const struct ide_port_info jmicron_chipset __devinitdata = {
.name = "JMB",
- .init_hwif = init_hwif_jmicron,
- .host_flags = IDE_HFLAG_BOOTABLE,
.enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
+ .port_ops = &jmicron_port_ops,
.pio_mask = ATA_PIO5,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index 75513320aad9..fec4955f449b 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -63,6 +63,48 @@ static u8 superio_ide_inb (unsigned long port)
return inb(port);
}
+static void superio_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ struct ide_io_ports *io_ports = &drive->hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data = inw(io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ outb(drive->ctl & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = superio_ide_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ outb(drive->ctl | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = inb(io_ports->lbah_addr);
+ }
+}
+
static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
{
struct pci_dev *pdev = to_pci_dev(hwif->dev);
@@ -72,14 +114,16 @@ static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
base = pci_resource_start(pdev, port * 2) & ~3;
dmabase = pci_resource_start(pdev, 4) & ~3;
- superio_ide_status[port] = base + IDE_STATUS_OFFSET;
- superio_ide_select[port] = base + IDE_SELECT_OFFSET;
+ superio_ide_status[port] = base + 7;
+ superio_ide_select[port] = base + 6;
superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa);
/* Clear error/interrupt, enable dma */
tmp = superio_ide_inb(superio_ide_dma_status[port]);
outb(tmp | 0x66, superio_ide_dma_status[port]);
+ hwif->tf_read = superio_tf_read;
+
/* We need to override inb to workaround a SuperIO errata */
hwif->INB = superio_ide_inb;
}
@@ -150,7 +194,7 @@ static void ns87415_selectproc (ide_drive_t *drive)
ns87415_prepare_drive (drive, drive->using_dma);
}
-static int ns87415_ide_dma_end (ide_drive_t *drive)
+static int ns87415_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u8 dma_stat = 0, dma_cmd = 0;
@@ -170,7 +214,7 @@ static int ns87415_ide_dma_end (ide_drive_t *drive)
return (dma_stat & 7) != 4;
}
-static int ns87415_ide_dma_setup(ide_drive_t *drive)
+static int ns87415_dma_setup(ide_drive_t *drive)
{
/* select DMA xfer */
ns87415_prepare_drive(drive, 1);
@@ -195,8 +239,6 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
u8 stat;
#endif
- hwif->selectproc = &ns87415_selectproc;
-
/*
* We cannot probe for IRQ: both ports share common IRQ on INTA.
* Also, leave IRQ masked during drive probing, to prevent infinite
@@ -233,12 +275,12 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
* SELECT_DRIVE() properly during first ide_probe_port().
*/
timeout = 10000;
- outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ outb(12, hwif->io_ports.ctl_addr);
udelay(10);
- outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ outb(8, hwif->io_ports.ctl_addr);
do {
udelay(50);
- stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ stat = hwif->INB(hwif->io_ports.status_addr);
if (stat == 0xff)
break;
} while ((stat & BUSY_STAT) && --timeout);
@@ -246,7 +288,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
}
if (!using_inta)
- hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
+ hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* share IRQ with mate */
@@ -254,19 +296,33 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
return;
outb(0x60, hwif->dma_status);
- hwif->dma_setup = &ns87415_ide_dma_setup;
- hwif->ide_dma_end = &ns87415_ide_dma_end;
}
+static const struct ide_port_ops ns87415_port_ops = {
+ .selectproc = ns87415_selectproc,
+};
+
+static const struct ide_dma_ops ns87415_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ns87415_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ns87415_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
static const struct ide_port_info ns87415_chipset __devinitdata = {
.name = "NS87415",
#ifdef CONFIG_SUPERIO
.init_iops = init_iops_ns87415,
#endif
.init_hwif = init_hwif_ns87415,
+ .port_ops = &ns87415_port_ops,
+ .dma_ops = &ns87415_dma_ops,
.host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_NO_ATAPI_DMA,
};
static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 46e8748f507e..6e99080497bf 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -53,13 +53,12 @@
* If you then set the second drive to another PIO, the old value
* (automatically selected) will be overrided by yours.
* There is a 25/33MHz switch in configuration
- * register, but driver is written for use at any frequency which get
- * (use idebus=xx to select PCI bus speed).
+ * register, but driver is written for use at any frequency.
*
* Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8.
+ * by Jaromir Koutek, for 2.1.8.
* Initial version of driver.
- *
+ *
* Version 0.2
* Number 0.2 skipped.
*
@@ -75,7 +74,7 @@
* by Jaromir Koutek
* Updates for use with (again) new IDE block driver.
* Update of documentation.
- *
+ *
* Version 0.6, Jan 2, 1999
* by Jaromir Koutek
* Reversed to version 0.3 of the driver, because
@@ -208,29 +207,34 @@ typedef struct pio_clocks_s {
static void compute_clocks(int pio, pio_clocks_t *clks)
{
- if (pio != PIO_NOT_EXIST) {
- int adr_setup, data_pls;
- int bus_speed = system_bus_clock();
-
- adr_setup = ide_pio_timings[pio].setup_time;
- data_pls = ide_pio_timings[pio].active_time;
- clks->address_time = cmpt_clk(adr_setup, bus_speed);
- clks->data_time = cmpt_clk(data_pls, bus_speed);
- clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
- - adr_setup-data_pls, bus_speed);
- if (clks->address_time<1) clks->address_time = 1;
- if (clks->address_time>4) clks->address_time = 4;
- if (clks->data_time<1) clks->data_time = 1;
- if (clks->data_time>16) clks->data_time = 16;
- if (clks->recovery_time<2) clks->recovery_time = 2;
- if (clks->recovery_time>17) clks->recovery_time = 17;
+ if (pio != PIO_NOT_EXIST) {
+ int adr_setup, data_pls;
+ int bus_speed = ide_pci_clk ? ide_pci_clk : system_bus_clock();
+
+ adr_setup = ide_pio_timings[pio].setup_time;
+ data_pls = ide_pio_timings[pio].active_time;
+ clks->address_time = cmpt_clk(adr_setup, bus_speed);
+ clks->data_time = cmpt_clk(data_pls, bus_speed);
+ clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+ - adr_setup-data_pls, bus_speed);
+ if (clks->address_time < 1)
+ clks->address_time = 1;
+ if (clks->address_time > 4)
+ clks->address_time = 4;
+ if (clks->data_time < 1)
+ clks->data_time = 1;
+ if (clks->data_time > 16)
+ clks->data_time = 16;
+ if (clks->recovery_time < 2)
+ clks->recovery_time = 2;
+ if (clks->recovery_time > 17)
+ clks->recovery_time = 17;
} else {
clks->address_time = 1;
clks->data_time = 1;
clks->recovery_time = 2;
/* minimal values */
}
-
}
static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
@@ -247,8 +251,8 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
/* sets drive->drive_data for both drives */
compute_pios(drive, pio);
- pio1 = hwif->drives[0].drive_data;
- pio2 = hwif->drives[1].drive_data;
+ pio1 = hwif->drives[0].drive_data;
+ pio2 = hwif->drives[1].drive_data;
compute_clocks(pio1, &first);
compute_clocks(pio2, &second);
@@ -275,7 +279,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
spin_lock_irqsave(&opti621_lock, flags);
- reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+ reg_base = hwif->io_ports.data_addr;
/* allow Register-B */
outb(0xc0, reg_base + CNTRL_REG);
@@ -321,31 +325,25 @@ static void __devinit opti621_port_init_devs(ide_hwif_t *hwif)
hwif->drives[1].drive_data = PIO_DONT_KNOW;
}
-/*
- * init_hwif_opti621() is called once for each hwif found at boot.
- */
-static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
-{
- hwif->port_init_devs = opti621_port_init_devs;
- hwif->set_pio_mode = &opti621_set_pio_mode;
-}
+static const struct ide_port_ops opti621_port_ops = {
+ .port_init_devs = opti621_port_init_devs,
+ .set_pio_mode = opti621_set_pio_mode,
+};
static const struct ide_port_info opti621_chipsets[] __devinitdata = {
{ /* 0 */
.name = "OPTI621",
- .init_hwif = init_hwif_opti621,
- .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_BOOTABLE,
+ .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
+ .port_ops = &opti621_port_ops,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
.pio_mask = ATA_PIO3,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
- },{ /* 1 */
+ }, { /* 1 */
.name = "OPTI621X",
- .init_hwif = init_hwif_opti621,
- .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_BOOTABLE,
+ .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
+ .port_ops = &opti621_port_ops,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
.pio_mask = ATA_PIO3,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 1c8cb7797a4a..070df8ab3b21 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -34,7 +34,7 @@
#undef DEBUG
#ifdef DEBUG
-#define DBG(fmt, args...) printk("%s: " fmt, __FUNCTION__, ## args)
+#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args)
#else
#define DBG(fmt, args...)
#endif
@@ -83,8 +83,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
{
u8 value;
- outb(index, hwif->dma_vendor1);
- value = inb(hwif->dma_vendor3);
+ outb(index, hwif->dma_base + 1);
+ value = inb(hwif->dma_base + 3);
DBG("index[%02X] value[%02X]\n", index, value);
return value;
@@ -97,8 +97,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
*/
static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
{
- outb(index, hwif->dma_vendor1);
- outb(value, hwif->dma_vendor3);
+ outb(index, hwif->dma_base + 1);
+ outb(value, hwif->dma_base + 3);
DBG("index[%02X] value[%02X]\n", index, value);
}
@@ -442,17 +442,6 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
return dev->irq;
}
-static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &pdcnew_set_pio_mode;
- hwif->set_dma_mode = &pdcnew_set_dma_mode;
-
- hwif->quirkproc = &pdcnew_quirkproc;
- hwif->resetproc = &pdcnew_reset;
-
- hwif->cable_detect = pdcnew_cable_detect;
-}
-
static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
{
struct pci_dev *dev2;
@@ -476,11 +465,19 @@ static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
return NULL;
}
+static const struct ide_port_ops pdcnew_port_ops = {
+ .set_pio_mode = pdcnew_set_pio_mode,
+ .set_dma_mode = pdcnew_set_dma_mode,
+ .quirkproc = pdcnew_quirkproc,
+ .resetproc = pdcnew_reset,
+ .cable_detect = pdcnew_cable_detect,
+};
+
#define DECLARE_PDCNEW_DEV(name_str, udma) \
{ \
.name = name_str, \
.init_chipset = init_chipset_pdcnew, \
- .init_hwif = init_hwif_pdc202new, \
+ .port_ops = &pdcnew_port_ops, \
.host_flags = IDE_HFLAG_POST_SET_MODE | \
IDE_HFLAG_ERROR_STOPS_FIFO | \
IDE_HFLAG_OFF_BOARD, \
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 150422ec3cfa..fca89eda5c02 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -115,7 +115,7 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
}
-static u8 __devinit pdc2026x_old_cable_detect(ide_hwif_t *hwif)
+static u8 __devinit pdc2026x_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
@@ -163,7 +163,7 @@ static void pdc202xx_quirkproc(ide_drive_t *drive)
drive->quirk_list = 0;
}
-static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
+static void pdc202xx_dma_start(ide_drive_t *drive)
{
if (drive->current_speed > XFER_UDMA_2)
pdc_old_enable_66MHz_clock(drive->hwif);
@@ -185,7 +185,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
ide_dma_start(drive);
}
-static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+static int pdc202xx_dma_end(ide_drive_t *drive)
{
if (drive->media != ide_disk || drive->addressing == 1) {
ide_hwif_t *hwif = HWIF(drive);
@@ -202,7 +202,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
return __ide_dma_end(drive);
}
-static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+static int pdc202xx_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long high_16 = hwif->extra_base - 16;
@@ -226,26 +226,6 @@ somebody_else:
return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
}
-static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
-
- if (hwif->resetproc != NULL)
- hwif->resetproc(drive);
-
- ide_dma_lost_irq(drive);
-}
-
-static void pdc202xx_dma_timeout(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
-
- if (hwif->resetproc != NULL)
- hwif->resetproc(drive);
-
- ide_dma_timeout(drive);
-}
-
static void pdc202xx_reset_host (ide_hwif_t *hwif)
{
unsigned long high_16 = hwif->extra_base - 16;
@@ -271,68 +251,46 @@ static void pdc202xx_reset (ide_drive_t *drive)
ide_set_max_pio(drive);
}
-static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
- const char *name)
+static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
{
- return dev->irq;
+ pdc202xx_reset(drive);
+ ide_dma_lost_irq(drive);
}
-static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
+static void pdc202xx_dma_timeout(ide_drive_t *drive)
{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- hwif->set_pio_mode = &pdc202xx_set_pio_mode;
- hwif->set_dma_mode = &pdc202xx_set_mode;
-
- hwif->quirkproc = &pdc202xx_quirkproc;
-
- if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
- hwif->resetproc = &pdc202xx_reset;
-
- hwif->cable_detect = pdc2026x_old_cable_detect;
- }
-
- if (hwif->dma_base == 0)
- return;
-
- hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
- hwif->dma_timeout = &pdc202xx_dma_timeout;
-
- if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
- hwif->dma_start = &pdc202xx_old_ide_dma_start;
- hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
- }
- hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+ pdc202xx_reset(drive);
+ ide_dma_timeout(drive);
}
-static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
+static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
+ const char *name)
{
+ unsigned long dmabase = pci_resource_start(dev, 4);
u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
- if (hwif->channel) {
- ide_setup_dma(hwif, dmabase);
- return;
- }
+ if (dmabase == 0)
+ goto out;
udma_speed_flag = inb(dmabase | 0x1f);
primary_mode = inb(dmabase | 0x1a);
secondary_mode = inb(dmabase | 0x1b);
printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
"Primary %s Mode " \
- "Secondary %s Mode.\n", hwif->cds->name,
+ "Secondary %s Mode.\n", pci_name(dev),
(udma_speed_flag & 1) ? "EN" : "DIS",
(primary_mode & 1) ? "MASTER" : "PCI",
(secondary_mode & 1) ? "MASTER" : "PCI" );
if (!(udma_speed_flag & 1)) {
printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
- hwif->cds->name, udma_speed_flag,
+ pci_name(dev), udma_speed_flag,
(udma_speed_flag|1));
outb(udma_speed_flag | 1, dmabase | 0x1f);
printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
}
-
- ide_setup_dma(hwif, dmabase);
+out:
+ return dev->irq;
}
static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
@@ -357,13 +315,48 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
IDE_HFLAG_ABUSE_SET_DMA_MODE | \
IDE_HFLAG_OFF_BOARD)
+static const struct ide_port_ops pdc20246_port_ops = {
+ .set_pio_mode = pdc202xx_set_pio_mode,
+ .set_dma_mode = pdc202xx_set_mode,
+ .quirkproc = pdc202xx_quirkproc,
+};
+
+static const struct ide_port_ops pdc2026x_port_ops = {
+ .set_pio_mode = pdc202xx_set_pio_mode,
+ .set_dma_mode = pdc202xx_set_mode,
+ .quirkproc = pdc202xx_quirkproc,
+ .resetproc = pdc202xx_reset,
+ .cable_detect = pdc2026x_cable_detect,
+};
+
+static const struct ide_dma_ops pdc20246_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
+ .dma_test_irq = pdc202xx_dma_test_irq,
+ .dma_lost_irq = pdc202xx_dma_lost_irq,
+ .dma_timeout = pdc202xx_dma_timeout,
+};
+
+static const struct ide_dma_ops pdc2026x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = pdc202xx_dma_start,
+ .dma_end = pdc202xx_dma_end,
+ .dma_test_irq = pdc202xx_dma_test_irq,
+ .dma_lost_irq = pdc202xx_dma_lost_irq,
+ .dma_timeout = pdc202xx_dma_timeout,
+};
+
#define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
{ \
.name = name_str, \
.init_chipset = init_chipset_pdc202xx, \
- .init_hwif = init_hwif_pdc202xx, \
- .init_dma = init_dma_pdc202xx, \
- .extra = 48, \
+ .port_ops = &pdc2026x_port_ops, \
+ .dma_ops = &pdc2026x_dma_ops, \
.host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
.pio_mask = ATA_PIO4, \
.mwdma_mask = ATA_MWDMA2, \
@@ -374,9 +367,8 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
{ /* 0 */
.name = "PDC20246",
.init_chipset = init_chipset_pdc202xx,
- .init_hwif = init_hwif_pdc202xx,
- .init_dma = init_dma_pdc202xx,
- .extra = 16,
+ .port_ops = &pdc20246_port_ops,
+ .dma_ops = &pdc20246_dma_ops,
.host_flags = IDE_HFLAGS_PDC202XX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index decef0f47674..f04738d14a6f 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -250,6 +250,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */
+ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
/* end marker */
{ 0, }
};
@@ -285,11 +286,6 @@ static u8 __devinit piix_cable_detect(ide_hwif_t *hwif)
static void __devinit init_hwif_piix(ide_hwif_t *hwif)
{
- hwif->set_pio_mode = &piix_set_pio_mode;
- hwif->set_dma_mode = &piix_set_dma_mode;
-
- hwif->cable_detect = piix_cable_detect;
-
if (!hwif->dma_base)
return;
@@ -306,10 +302,16 @@ static void __devinit init_hwif_ich(ide_hwif_t *hwif)
hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
}
+static const struct ide_port_ops piix_port_ops = {
+ .set_pio_mode = piix_set_pio_mode,
+ .set_dma_mode = piix_set_dma_mode,
+ .cable_detect = piix_cable_detect,
+};
+
#ifndef CONFIG_IA64
- #define IDE_HFLAGS_PIIX (IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE)
+ #define IDE_HFLAGS_PIIX IDE_HFLAG_LEGACY_IRQS
#else
- #define IDE_HFLAGS_PIIX IDE_HFLAG_BOOTABLE
+ #define IDE_HFLAGS_PIIX 0
#endif
#define DECLARE_PIIX_DEV(name_str, udma) \
@@ -317,6 +319,7 @@ static void __devinit init_hwif_ich(ide_hwif_t *hwif)
.name = name_str, \
.init_hwif = init_hwif_piix, \
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
+ .port_ops = &piix_port_ops, \
.host_flags = IDE_HFLAGS_PIIX, \
.pio_mask = ATA_PIO4, \
.swdma_mask = ATA_SWDMA2_ONLY, \
@@ -330,6 +333,7 @@ static void __devinit init_hwif_ich(ide_hwif_t *hwif)
.init_chipset = init_chipset_ich, \
.init_hwif = init_hwif_ich, \
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
+ .port_ops = &piix_port_ops, \
.host_flags = IDE_HFLAGS_PIIX, \
.pio_mask = ATA_PIO4, \
.swdma_mask = ATA_SWDMA2_ONLY, \
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 51676612f78f..532154adba29 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -43,7 +43,7 @@ static const struct ide_port_info rz1000_chipset __devinitdata = {
.name = "RZ100x",
.init_hwif = init_hwif_rz1000,
.chipset = ide_rz1000,
- .host_flags = IDE_HFLAG_NO_DMA | IDE_HFLAG_BOOTABLE,
+ .host_flags = IDE_HFLAG_NO_DMA,
};
static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 561aa47c7720..14c787b5d95f 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -165,7 +165,7 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
*
* returns 1 on error, 0 otherwise
*/
-static int sc1200_ide_dma_end (ide_drive_t *drive)
+static int sc1200_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long dma_base = hwif->dma_base;
@@ -214,7 +214,7 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
ide_dma_off_quietly(drive);
if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
- hwif->dma_host_set(drive, 1);
+ hwif->dma_ops->dma_host_set(drive, 1);
return;
}
@@ -286,29 +286,30 @@ static int sc1200_resume (struct pci_dev *dev)
}
#endif
-/*
- * This gets invoked by the IDE driver once for each channel,
- * and performs channel-specific pre-initialization before drive probing.
- */
-static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &sc1200_set_pio_mode;
- hwif->set_dma_mode = &sc1200_set_dma_mode;
-
- if (hwif->dma_base == 0)
- return;
+static const struct ide_port_ops sc1200_port_ops = {
+ .set_pio_mode = sc1200_set_pio_mode,
+ .set_dma_mode = sc1200_set_dma_mode,
+ .udma_filter = sc1200_udma_filter,
+};
- hwif->udma_filter = sc1200_udma_filter;
- hwif->ide_dma_end = &sc1200_ide_dma_end;
-}
+static const struct ide_dma_ops sc1200_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = sc1200_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
static const struct ide_port_info sc1200_chipset __devinitdata = {
.name = "SC1200",
- .init_hwif = init_hwif_sc1200,
+ .port_ops = &sc1200_port_ops,
+ .dma_ops = &sc1200_dma_ops,
.host_flags = IDE_HFLAG_SERIALIZE |
IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_ABUSE_DMA_MODES |
- IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_ABUSE_DMA_MODES,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index ef07c7a8b97a..910fb00deb71 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -65,7 +65,7 @@
static struct scc_ports {
unsigned long ctl, dma;
- unsigned char hwif_id; /* for removing hwif from system */
+ ide_hwif_t *hwif; /* for removing port from system */
} scc_ports[MAX_HWIFS];
/* PIO transfer mode table */
@@ -126,12 +126,6 @@ static u8 scc_ide_inb(unsigned long port)
return (u8)data;
}
-static u16 scc_ide_inw(unsigned long port)
-{
- u32 data = in_be32((void*)port);
- return (u16)data;
-}
-
static void scc_ide_insw(unsigned long port, void *addr, u32 count)
{
u16 *ptr = (u16 *)addr;
@@ -154,11 +148,6 @@ static void scc_ide_outb(u8 addr, unsigned long port)
out_be32((void*)port, addr);
}
-static void scc_ide_outw(u16 addr, unsigned long port)
-{
- out_be32((void*)port, addr);
-}
-
static void
scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port)
{
@@ -271,6 +260,20 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
out_be32((void __iomem *)udenvt_port, reg);
}
+static void scc_dma_host_set(ide_drive_t *drive, int on)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 dma_stat = scc_ide_inb(hwif->dma_status);
+
+ if (on)
+ dma_stat |= (1 << (5 + unit));
+ else
+ dma_stat &= ~(1 << (5 + unit));
+
+ scc_ide_outb(dma_stat, hwif->dma_status);
+}
+
/**
* scc_ide_dma_setup - begin a DMA phase
* @drive: target device
@@ -301,7 +304,7 @@ static int scc_dma_setup(ide_drive_t *drive)
}
/* PRD table */
- out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma);
+ out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma);
/* specify r/w */
out_be32((void __iomem *)hwif->dma_command, reading);
@@ -315,16 +318,48 @@ static int scc_dma_setup(ide_drive_t *drive)
return 0;
}
+static void scc_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_cmd = scc_ide_inb(hwif->dma_command);
+
+ /* start DMA */
+ scc_ide_outb(dma_cmd | 1, hwif->dma_command);
+ hwif->dma = 1;
+ wmb();
+}
+
+static int __scc_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_stat, dma_cmd;
+
+ drive->waiting_for_dma = 0;
+ /* get DMA command mode */
+ dma_cmd = scc_ide_inb(hwif->dma_command);
+ /* stop DMA */
+ scc_ide_outb(dma_cmd & ~1, hwif->dma_command);
+ /* get DMA status */
+ dma_stat = scc_ide_inb(hwif->dma_status);
+ /* clear the INTR & ERROR bits */
+ scc_ide_outb(dma_stat | 6, hwif->dma_status);
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ hwif->dma = 0;
+ wmb();
+ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
/**
- * scc_ide_dma_end - Stop DMA
+ * scc_dma_end - Stop DMA
* @drive: IDE drive
*
* Check and clear INT Status register.
- * Then call __ide_dma_end().
+ * Then call __scc_dma_end().
*/
-static int scc_ide_dma_end(ide_drive_t * drive)
+static int scc_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long intsts_port = hwif->dma_base + 0x014;
@@ -334,7 +369,7 @@ static int scc_ide_dma_end(ide_drive_t * drive)
/* errata A308 workaround: Step5 (check data loss) */
/* We don't check non ide_disk because it is limited to UDMA4 */
- if (!(in_be32((void __iomem *)hwif->io_ports[IDE_ALTSTATUS_OFFSET])
+ if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr)
& ERR_STAT) &&
drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
reg = in_be32((void __iomem *)intsts_port);
@@ -425,7 +460,7 @@ static int scc_ide_dma_end(ide_drive_t * drive)
break;
}
- dma_stat = __ide_dma_end(drive);
+ dma_stat = __scc_dma_end(drive);
if (data_loss)
dma_stat |= 2; /* emulate DMA error (to retry command) */
return dma_stat;
@@ -438,7 +473,7 @@ static int scc_dma_test_irq(ide_drive_t *drive)
u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
/* SCC errata A252,A308 workaround: Step4 */
- if ((in_be32((void __iomem *)hwif->io_ports[IDE_ALTSTATUS_OFFSET])
+ if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr)
& ERR_STAT) &&
(int_stat & INTSTS_INTRQ))
return 1;
@@ -449,7 +484,7 @@ static int scc_dma_test_irq(ide_drive_t *drive)
if (!drive->waiting_for_dma)
printk(KERN_WARNING "%s: (%s) called while not waiting\n",
- drive->name, __FUNCTION__);
+ drive->name, __func__);
return 0;
}
@@ -483,7 +518,7 @@ static int setup_mmio_scc (struct pci_dev *dev, const char *name)
unsigned long dma_size = pci_resource_len(dev, 1);
void __iomem *ctl_addr;
void __iomem *dma_addr;
- int i;
+ int i, ret;
for (i = 0; i < MAX_HWIFS; i++) {
if (scc_ports[i].ctl == 0)
@@ -492,21 +527,17 @@ static int setup_mmio_scc (struct pci_dev *dev, const char *name)
if (i >= MAX_HWIFS)
return -ENOMEM;
- if (!request_mem_region(ctl_base, ctl_size, name)) {
- printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME);
- goto fail_0;
- }
-
- if (!request_mem_region(dma_base, dma_size, name)) {
- printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME);
- goto fail_1;
+ ret = pci_request_selected_regions(dev, (1 << 2) - 1, name);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: can't reserve resources\n", name);
+ return ret;
}
if ((ctl_addr = ioremap(ctl_base, ctl_size)) == NULL)
- goto fail_2;
+ goto fail_0;
if ((dma_addr = ioremap(dma_base, dma_size)) == NULL)
- goto fail_3;
+ goto fail_1;
pci_set_master(dev);
scc_ports[i].ctl = (unsigned long)ctl_addr;
@@ -515,12 +546,8 @@ static int setup_mmio_scc (struct pci_dev *dev, const char *name)
return 1;
- fail_3:
- iounmap(ctl_addr);
- fail_2:
- release_mem_region(dma_base, dma_size);
fail_1:
- release_mem_region(ctl_base, ctl_size);
+ iounmap(ctl_addr);
fail_0:
return -ENOMEM;
}
@@ -534,26 +561,21 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev,
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
int i;
- for (i = 0; i < MAX_HWIFS; i++) {
- hwif = &ide_hwifs[i];
- if (hwif->chipset == ide_unknown)
- break; /* pick an unused entry */
- }
- if (i == MAX_HWIFS) {
+ hwif = ide_find_port();
+ if (hwif == NULL) {
printk(KERN_ERR "%s: too many IDE interfaces, "
"no room in table\n", SCC_PATA_NAME);
return -ENOMEM;
}
memset(&hw, 0, sizeof(hw));
- for (i = IDE_DATA_OFFSET; i <= IDE_CONTROL_OFFSET; i++)
- hw.io_ports[i] = ports->dma + 0x20 + i * 4;
+ for (i = 0; i <= 8; i++)
+ hw.io_ports_array[i] = ports->dma + 0x20 + i * 4;
hw.irq = dev->irq;
hw.dev = &dev->dev;
hw.chipset = ide_pci;
ide_init_port_hw(hwif, &hw);
hwif->dev = &dev->dev;
- hwif->cds = d;
idx[0] = hwif->index;
@@ -631,6 +653,122 @@ static int __devinit init_setup_scc(struct pci_dev *dev,
return rc;
}
+static void scc_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ struct ide_io_ports *io_ports = &drive->hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ ide_set_irq(drive, 1);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA)
+ out_be32((void *)io_ports->data_addr,
+ (tf->hob_data << 8) | tf->data);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ scc_ide_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ scc_ide_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ scc_ide_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ scc_ide_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ scc_ide_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ scc_ide_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ scc_ide_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ scc_ide_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ scc_ide_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ scc_ide_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ scc_ide_outb((tf->device & HIHI) | drive->select.all,
+ io_ports->device_addr);
+}
+
+static void scc_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ struct ide_io_ports *io_ports = &drive->hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data = (u16)in_be32((void *)io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ scc_ide_outb(drive->ctl & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = scc_ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = scc_ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = scc_ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = scc_ide_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = scc_ide_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ scc_ide_outb(drive->ctl | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = scc_ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr);
+ }
+}
+
+static void scc_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ len++;
+
+ if (drive->io_32bit) {
+ scc_ide_insl(data_addr, buf, len / 4);
+
+ if ((len & 3) >= 2)
+ scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1);
+ } else
+ scc_ide_insw(data_addr, buf, len / 2);
+}
+
+static void scc_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ len++;
+
+ if (drive->io_32bit) {
+ scc_ide_outsl(data_addr, buf, len / 4);
+
+ if ((len & 3) >= 2)
+ scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1);
+ } else
+ scc_ide_outsw(data_addr, buf, len / 2);
+}
+
/**
* init_mmio_iops_scc - set up the iops for MMIO
* @hwif: interface to set up
@@ -645,15 +783,15 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
ide_set_hwifdata(hwif, ports);
+ hwif->tf_load = scc_tf_load;
+ hwif->tf_read = scc_tf_read;
+
+ hwif->input_data = scc_input_data;
+ hwif->output_data = scc_output_data;
+
hwif->INB = scc_ide_inb;
- hwif->INW = scc_ide_inw;
- hwif->INSW = scc_ide_insw;
- hwif->INSL = scc_ide_insl;
hwif->OUTB = scc_ide_outb;
hwif->OUTBSYNC = scc_ide_outbsync;
- hwif->OUTW = scc_ide_outw;
- hwif->OUTSW = scc_ide_outsw;
- hwif->OUTSL = scc_ide_outsl;
hwif->dma_base = dma_base;
hwif->config_data = ports->ctl;
@@ -696,37 +834,46 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
{
struct scc_ports *ports = ide_get_hwifdata(hwif);
- ports->hwif_id = hwif->index;
+ ports->hwif = hwif;
hwif->dma_command = hwif->dma_base;
hwif->dma_status = hwif->dma_base + 0x04;
- hwif->dma_prdtable = hwif->dma_base + 0x08;
/* PTERADD */
out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
- hwif->dma_setup = scc_dma_setup;
- hwif->ide_dma_end = scc_ide_dma_end;
- hwif->set_pio_mode = scc_set_pio_mode;
- hwif->set_dma_mode = scc_set_dma_mode;
- hwif->ide_dma_test_irq = scc_dma_test_irq;
- hwif->udma_filter = scc_udma_filter;
-
if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN)
hwif->ultra_mask = ATA_UDMA6; /* 133MHz */
else
hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
-
- hwif->cable_detect = scc_cable_detect;
}
+static const struct ide_port_ops scc_port_ops = {
+ .set_pio_mode = scc_set_pio_mode,
+ .set_dma_mode = scc_set_dma_mode,
+ .udma_filter = scc_udma_filter,
+ .cable_detect = scc_cable_detect,
+};
+
+static const struct ide_dma_ops scc_dma_ops = {
+ .dma_host_set = scc_dma_host_set,
+ .dma_setup = scc_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = scc_dma_start,
+ .dma_end = scc_dma_end,
+ .dma_test_irq = scc_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
#define DECLARE_SCC_DEV(name_str) \
{ \
.name = name_str, \
.init_iops = init_iops_scc, \
.init_hwif = init_hwif_scc, \
- .host_flags = IDE_HFLAG_SINGLE | \
- IDE_HFLAG_BOOTABLE, \
+ .port_ops = &scc_port_ops, \
+ .dma_ops = &scc_dma_ops, \
+ .host_flags = IDE_HFLAG_SINGLE, \
.pio_mask = ATA_PIO4, \
}
@@ -758,11 +905,7 @@ static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_i
static void __devexit scc_remove(struct pci_dev *dev)
{
struct scc_ports *ports = pci_get_drvdata(dev);
- ide_hwif_t *hwif = &ide_hwifs[ports->hwif_id];
- unsigned long ctl_base = pci_resource_start(dev, 0);
- unsigned long dma_base = pci_resource_start(dev, 1);
- unsigned long ctl_size = pci_resource_len(dev, 0);
- unsigned long dma_size = pci_resource_len(dev, 1);
+ ide_hwif_t *hwif = ports->hwif;
if (hwif->dmatable_cpu) {
pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES,
@@ -770,13 +913,11 @@ static void __devexit scc_remove(struct pci_dev *dev)
hwif->dmatable_cpu = NULL;
}
- ide_unregister(hwif->index);
+ ide_unregister(hwif);
- hwif->chipset = ide_unknown;
iounmap((void*)ports->dma);
iounmap((void*)ports->ctl);
- release_mem_region(dma_base, dma_size);
- release_mem_region(ctl_base, ctl_size);
+ pci_release_selected_regions(dev, (1 << 2) - 1);
memset(ports, 0, sizeof(*ports));
}
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index c11880b0709f..a1fb20826a5b 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -312,7 +312,7 @@ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif)
return ATA_CBL_PATA40;
}
-static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
+static u8 __devinit svwks_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -336,28 +336,28 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
return ATA_CBL_PATA40;
}
-static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- hwif->set_pio_mode = &svwks_set_pio_mode;
- hwif->set_dma_mode = &svwks_set_dma_mode;
- hwif->udma_filter = &svwks_udma_filter;
+static const struct ide_port_ops osb4_port_ops = {
+ .set_pio_mode = svwks_set_pio_mode,
+ .set_dma_mode = svwks_set_dma_mode,
+ .udma_filter = svwks_udma_filter,
+};
- if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
- hwif->cable_detect = ata66_svwks;
-}
+static const struct ide_port_ops svwks_port_ops = {
+ .set_pio_mode = svwks_set_pio_mode,
+ .set_dma_mode = svwks_set_dma_mode,
+ .udma_filter = svwks_udma_filter,
+ .cable_detect = svwks_cable_detect,
+};
#define IDE_HFLAGS_SVWKS \
(IDE_HFLAG_LEGACY_IRQS | \
- IDE_HFLAG_ABUSE_SET_DMA_MODE | \
- IDE_HFLAG_BOOTABLE)
+ IDE_HFLAG_ABUSE_SET_DMA_MODE)
static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
{ /* 0 */
.name = "SvrWks OSB4",
.init_chipset = init_chipset_svwks,
- .init_hwif = init_hwif_svwks,
+ .port_ops = &osb4_port_ops,
.host_flags = IDE_HFLAGS_SVWKS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -365,7 +365,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
},{ /* 1 */
.name = "SvrWks CSB5",
.init_chipset = init_chipset_svwks,
- .init_hwif = init_hwif_svwks,
+ .port_ops = &svwks_port_ops,
.host_flags = IDE_HFLAGS_SVWKS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -373,7 +373,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
},{ /* 2 */
.name = "SvrWks CSB6",
.init_chipset = init_chipset_svwks,
- .init_hwif = init_hwif_svwks,
+ .port_ops = &svwks_port_ops,
.host_flags = IDE_HFLAGS_SVWKS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -381,7 +381,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
},{ /* 3 */
.name = "SvrWks CSB6",
.init_chipset = init_chipset_svwks,
- .init_hwif = init_hwif_svwks,
+ .port_ops = &svwks_port_ops,
.host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -389,7 +389,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
},{ /* 4 */
.name = "SvrWks HT1000",
.init_chipset = init_chipset_svwks,
- .init_hwif = init_hwif_svwks,
+ .port_ops = &svwks_port_ops,
.host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -418,7 +418,7 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device
else if (idx == 2 || idx == 3) {
if ((PCI_FUNC(dev->devfn) & 1) == 0) {
if (pci_resource_start(dev, 0) != 0x01f1)
- d.host_flags &= ~IDE_HFLAG_BOOTABLE;
+ d.host_flags |= IDE_HFLAG_NON_BOOTABLE;
d.host_flags |= IDE_HFLAG_SINGLE;
} else
d.host_flags &= ~IDE_HFLAG_SINGLE;
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 9d1a3038af9b..16a0bce17d69 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -98,28 +98,28 @@ sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
int i;
/* Registers are word (32 bit) aligned */
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- hw->io_ports[i] = reg + i * 4;
+ for (i = 0; i <= 7; i++)
+ hw->io_ports_array[i] = reg + i * 4;
if (ctrl_port)
- hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ hw->io_ports.ctl_addr = ctrl_port;
if (irq_port)
- hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+ hw->io_ports.irq_addr = irq_port;
}
static void
sgiioc4_maskproc(ide_drive_t * drive, int mask)
{
writeb(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
- (void __iomem *)drive->hwif->io_ports[IDE_CONTROL_OFFSET]);
+ (void __iomem *)drive->hwif->io_ports.ctl_addr);
}
static int
sgiioc4_checkirq(ide_hwif_t * hwif)
{
unsigned long intr_addr =
- hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4;
+ hwif->io_ports.irq_addr + IOC4_INTR_REG * 4;
if ((u8)readl((void __iomem *)intr_addr) & 0x03)
return 1;
@@ -134,8 +134,8 @@ sgiioc4_clearirq(ide_drive_t * drive)
{
u32 intr_reg;
ide_hwif_t *hwif = HWIF(drive);
- unsigned long other_ir =
- hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2);
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2);
/* Code to check for PCI error conditions */
intr_reg = readl((void __iomem *)other_ir);
@@ -147,12 +147,12 @@ sgiioc4_clearirq(ide_drive_t * drive)
* a "clear" status if it got cleared. If not, then spin
* for a bit trying to clear it.
*/
- u8 stat = sgiioc4_INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ u8 stat = sgiioc4_INB(io_ports->status_addr);
int count = 0;
- stat = sgiioc4_INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ stat = sgiioc4_INB(io_ports->status_addr);
while ((stat & 0x80) && (count++ < 100)) {
udelay(1);
- stat = sgiioc4_INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ stat = sgiioc4_INB(io_ports->status_addr);
}
if (intr_reg & 0x02) {
@@ -162,18 +162,18 @@ sgiioc4_clearirq(ide_drive_t * drive)
pci_stat_cmd_reg;
pci_err_addr_low =
- readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]);
+ readl((void __iomem *)io_ports->irq_addr);
pci_err_addr_high =
- readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4));
+ readl((void __iomem *)(io_ports->irq_addr + 4));
pci_read_config_dword(dev, PCI_COMMAND,
&pci_stat_cmd_reg);
printk(KERN_ERR
"%s(%s) : PCI Bus Error when doing DMA:"
" status-cmd reg is 0x%x\n",
- __FUNCTION__, drive->name, pci_stat_cmd_reg);
+ __func__, drive->name, pci_stat_cmd_reg);
printk(KERN_ERR
"%s(%s) : PCI Error Address is 0x%x%x\n",
- __FUNCTION__, drive->name,
+ __func__, drive->name,
pci_err_addr_high, pci_err_addr_low);
/* Clear the PCI Error indicator */
pci_write_config_dword(dev, PCI_COMMAND, 0x00000146);
@@ -188,7 +188,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
return intr_reg & 3;
}
-static void sgiioc4_ide_dma_start(ide_drive_t * drive)
+static void sgiioc4_dma_start(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4;
@@ -215,8 +215,7 @@ sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base)
}
/* Stops the IOC4 DMA Engine */
-static int
-sgiioc4_ide_dma_end(ide_drive_t * drive)
+static int sgiioc4_dma_end(ide_drive_t *drive)
{
u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
ide_hwif_t *hwif = HWIF(drive);
@@ -232,7 +231,7 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
printk(KERN_ERR
"%s(%s): IOC4 DMA STOP bit is still 1 :"
"ioc4_dma_reg 0x%x\n",
- __FUNCTION__, drive->name, ioc4_dma);
+ __func__, drive->name, ioc4_dma);
dma_stat = 1;
}
@@ -251,7 +250,7 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
udelay(1);
}
if (!valid) {
- printk(KERN_ERR "%s(%s) : DMA incomplete\n", __FUNCTION__,
+ printk(KERN_ERR "%s(%s) : DMA incomplete\n", __func__,
drive->name);
dma_stat = 1;
}
@@ -264,7 +263,7 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
printk(KERN_ERR
"%s(%s): WARNING!! byte_count_dev %d "
"!= byte_count_mem %d\n",
- __FUNCTION__, drive->name, bc_dev, bc_mem);
+ __func__, drive->name, bc_dev, bc_mem);
}
}
@@ -279,8 +278,7 @@ static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
}
/* returns 1 if dma irq issued, 0 otherwise */
-static int
-sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
+static int sgiioc4_dma_test_irq(ide_drive_t *drive)
{
return sgiioc4_checkirq(HWIF(drive));
}
@@ -294,7 +292,7 @@ static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
static void
sgiioc4_resetproc(ide_drive_t * drive)
{
- sgiioc4_ide_dma_end(drive);
+ sgiioc4_dma_end(drive);
sgiioc4_clearirq(drive);
}
@@ -329,13 +327,17 @@ sgiioc4_INB(unsigned long port)
/* Creates a dma map for the scatter-gather list entries */
static int __devinit
-ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
void __iomem *virt_dma_base;
int num_ports = sizeof (ioc4_dma_regs_t);
void *pad;
+ if (dma_base == 0)
+ return -1;
+
printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
dma_base, dma_base + num_ports - 1);
@@ -343,7 +345,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
printk(KERN_ERR
"%s(%s) -- ERROR, Addresses 0x%p to 0x%p "
"ALREADY in use\n",
- __FUNCTION__, hwif->name, (void *) dma_base,
+ __func__, hwif->name, (void *) dma_base,
(void *) dma_base + num_ports - 1);
return -1;
}
@@ -352,7 +354,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
if (virt_dma_base == NULL) {
printk(KERN_ERR
"%s(%s) -- ERROR, Unable to map addresses 0x%lx to 0x%lx\n",
- __FUNCTION__, hwif->name, dma_base, dma_base + num_ports - 1);
+ __func__, hwif->name, dma_base, dma_base + num_ports - 1);
goto dma_remap_failure;
}
hwif->dma_base = (unsigned long) virt_dma_base;
@@ -378,7 +380,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
hwif->dmatable_cpu, hwif->dmatable_dma);
printk(KERN_INFO
"%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
- __FUNCTION__, hwif->name);
+ __func__, hwif->name);
printk(KERN_INFO
"Changing from DMA to PIO mode for Drive %s\n", hwif->name);
@@ -406,14 +408,14 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
printk(KERN_WARNING
"%s(%s):Warning!! DMA from previous transfer was still active\n",
- __FUNCTION__, drive->name);
+ __func__, drive->name);
writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
if (ioc4_dma & IOC4_S_DMA_STOP)
printk(KERN_ERR
"%s(%s) : IOC4 Dma STOP bit is still 1\n",
- __FUNCTION__, drive->name);
+ __func__, drive->name);
}
ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
@@ -421,14 +423,14 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
printk(KERN_WARNING
"%s(%s) : Warning!! - DMA Error during Previous"
" transfer | status 0x%x\n",
- __FUNCTION__, drive->name, ioc4_dma);
+ __func__, drive->name, ioc4_dma);
writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
if (ioc4_dma & IOC4_S_DMA_STOP)
printk(KERN_ERR
"%s(%s) : IOC4 DMA STOP bit is still 1\n",
- __FUNCTION__, drive->name);
+ __func__, drive->name);
}
/* Address of the Scatter Gather List */
@@ -519,7 +521,7 @@ use_pio_instead:
return 0; /* revert to PIO for this request */
}
-static int sgiioc4_ide_dma_setup(ide_drive_t *drive)
+static int sgiioc4_dma_setup(ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
unsigned int count = 0;
@@ -548,62 +550,46 @@ static int sgiioc4_ide_dma_setup(ide_drive_t *drive)
return 0;
}
-static void __devinit
-ide_init_sgiioc4(ide_hwif_t * hwif)
-{
- hwif->mmio = 1;
- hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
- hwif->set_dma_mode = &sgiioc4_set_dma_mode;
- hwif->selectproc = NULL;/* Use the default routine to select drive */
- hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
- hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
- hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
- clear interrupts */
- hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */
- hwif->quirkproc = NULL;
-
- hwif->INB = &sgiioc4_INB;
-
- if (hwif->dma_base == 0)
- return;
+static const struct ide_port_ops sgiioc4_port_ops = {
+ .set_dma_mode = sgiioc4_set_dma_mode,
+ /* reset DMA engine, clear IRQs */
+ .resetproc = sgiioc4_resetproc,
+ /* mask on/off NIEN register */
+ .maskproc = sgiioc4_maskproc,
+};
- hwif->dma_host_set = &sgiioc4_dma_host_set;
- hwif->dma_setup = &sgiioc4_ide_dma_setup;
- hwif->dma_start = &sgiioc4_ide_dma_start;
- hwif->ide_dma_end = &sgiioc4_ide_dma_end;
- hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
- hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
- hwif->dma_timeout = &ide_dma_timeout;
-}
+static const struct ide_dma_ops sgiioc4_dma_ops = {
+ .dma_host_set = sgiioc4_dma_host_set,
+ .dma_setup = sgiioc4_dma_setup,
+ .dma_start = sgiioc4_dma_start,
+ .dma_end = sgiioc4_dma_end,
+ .dma_test_irq = sgiioc4_dma_test_irq,
+ .dma_lost_irq = sgiioc4_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
static const struct ide_port_info sgiioc4_port_info __devinitdata = {
.chipset = ide_pci,
- .host_flags = IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
- IDE_HFLAG_NO_AUTOTUNE,
+ .init_dma = ide_dma_sgiioc4,
+ .port_ops = &sgiioc4_port_ops,
+ .dma_ops = &sgiioc4_dma_ops,
+ .host_flags = IDE_HFLAG_MMIO,
.mwdma_mask = ATA_MWDMA2_ONLY,
};
static int __devinit
sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
{
- unsigned long cmd_base, dma_base, irqport;
+ unsigned long cmd_base, irqport;
unsigned long bar0, cmd_phys_base, ctl;
void __iomem *virt_base;
ide_hwif_t *hwif;
- int h;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
hw_regs_t hw;
struct ide_port_info d = sgiioc4_port_info;
- /*
- * Find an empty HWIF; if none available, return -ENOMEM.
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->chipset == ide_unknown)
- break;
- }
- if (h == MAX_HWIFS) {
+ hwif = ide_find_port();
+ if (hwif == NULL) {
printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n",
DRV_NAME);
return -ENOMEM;
@@ -620,7 +606,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET;
ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET;
irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET;
- dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
if (!request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
@@ -628,7 +613,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
printk(KERN_ERR
"%s : %s -- ERROR, Addresses "
"0x%p to 0x%p ALREADY in use\n",
- __FUNCTION__, hwif->name, (void *) cmd_phys_base,
+ __func__, hwif->name, (void *) cmd_phys_base,
(void *) cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
return -ENOMEM;
}
@@ -649,13 +634,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
/* Initializing chipset IRQ Registers */
writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
- if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base)) {
- printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
- hwif->name, DRV_NAME);
- d.mwdma_mask = 0;
- }
-
- ide_init_sgiioc4(hwif);
+ hwif->INB = &sgiioc4_INB;
idx[0] = hwif->index;
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index b6be1b45f329..4cf8fc54aa2a 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,8 +1,8 @@
/*
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat <alan@redhat.com>
- * Copyright (C) 2007 MontaVista Software, Inc.
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2007-2008 MontaVista Software, Inc.
+ * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz
*
* May be copied or modified under the terms of the GNU General Public License
*
@@ -17,10 +17,10 @@
*
* FAQ Items:
* If you are using Marvell SATA-IDE adapters with Maxtor drives
- * ensure the system is set up for ATA100/UDMA5 not UDMA6.
+ * ensure the system is set up for ATA100/UDMA5, not UDMA6.
*
* If you are using WD drives with SATA bridges you must set the
- * drive to "Single". "Master" will hang
+ * drive to "Single". "Master" will hang.
*
* If you have strange problems with nVidia chipset systems please
* see the SI support documentation and update your system BIOS
@@ -42,25 +42,24 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
/**
* pdev_is_sata - check if device is SATA
* @pdev: PCI device to check
- *
+ *
* Returns true if this is a SATA controller
*/
-
+
static int pdev_is_sata(struct pci_dev *pdev)
{
#ifdef CONFIG_BLK_DEV_IDE_SATA
- switch(pdev->device) {
- case PCI_DEVICE_ID_SII_3112:
- case PCI_DEVICE_ID_SII_1210SA:
- return 1;
- case PCI_DEVICE_ID_SII_680:
- return 0;
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_SII_3112:
+ case PCI_DEVICE_ID_SII_1210SA:
+ return 1;
+ case PCI_DEVICE_ID_SII_680:
+ return 0;
}
BUG();
#endif
@@ -70,10 +69,10 @@ static int pdev_is_sata(struct pci_dev *pdev)
/**
* is_sata - check if hwif is SATA
* @hwif: interface to check
- *
+ *
* Returns true if this is a SATA controller
*/
-
+
static inline int is_sata(ide_hwif_t *hwif)
{
return pdev_is_sata(to_pci_dev(hwif->dev));
@@ -86,21 +85,22 @@ static inline int is_sata(ide_hwif_t *hwif)
*
* Turn a config register offset into the right address in either
* PCI space or MMIO space to access the control register in question
- * Thankfully this is a configuration operation so isnt performance
- * criticial.
+ * Thankfully this is a configuration operation, so isn't performance
+ * critical.
*/
-
+
static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
{
unsigned long base = (unsigned long)hwif->hwif_data;
+
base += 0xA0 + r;
- if(hwif->mmio)
- base += (hwif->channel << 6);
+ if (hwif->mmio)
+ base += hwif->channel << 6;
else
- base += (hwif->channel << 4);
+ base += hwif->channel << 4;
return base;
}
-
+
/**
* siimage_seldev - return register base
* @hwif: interface
@@ -110,20 +110,69 @@ static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
* PCI space or MMIO space to access the control register in question
* including accounting for the unit shift.
*/
-
+
static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned long base = (unsigned long)hwif->hwif_data;
+ unsigned long base = (unsigned long)hwif->hwif_data;
+
base += 0xA0 + r;
- if(hwif->mmio)
- base += (hwif->channel << 6);
+ if (hwif->mmio)
+ base += hwif->channel << 6;
else
- base += (hwif->channel << 4);
+ base += hwif->channel << 4;
base |= drive->select.b.unit << drive->select.b.unit;
return base;
}
+static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr)
+{
+ u8 tmp = 0;
+
+ if (pci_get_drvdata(dev))
+ tmp = readb((void __iomem *)addr);
+ else
+ pci_read_config_byte(dev, addr, &tmp);
+
+ return tmp;
+}
+
+static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr)
+{
+ u16 tmp = 0;
+
+ if (pci_get_drvdata(dev))
+ tmp = readw((void __iomem *)addr);
+ else
+ pci_read_config_word(dev, addr, &tmp);
+
+ return tmp;
+}
+
+static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr)
+{
+ if (pci_get_drvdata(dev))
+ writeb(val, (void __iomem *)addr);
+ else
+ pci_write_config_byte(dev, addr, val);
+}
+
+static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr)
+{
+ if (pci_get_drvdata(dev))
+ writew(val, (void __iomem *)addr);
+ else
+ pci_write_config_word(dev, addr, val);
+}
+
+static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr)
+{
+ if (pci_get_drvdata(dev))
+ writel(val, (void __iomem *)addr);
+ else
+ pci_write_config_dword(dev, addr, val);
+}
+
/**
* sil_udma_filter - compute UDMA mask
* @drive: IDE device
@@ -136,24 +185,26 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
static u8 sil_pata_udma_filter(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long base = (unsigned long) hwif->hwif_data;
- u8 mask = 0, scsc = 0;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u8 scsc, mask = 0;
- if (hwif->mmio)
- scsc = hwif->INB(base + 0x4A);
- else
- pci_read_config_byte(dev, 0x8A, &scsc);
+ scsc = sil_ioread8(dev, base + (hwif->mmio ? 0x4A : 0x8A));
- if ((scsc & 0x30) == 0x10) /* 133 */
+ switch (scsc & 0x30) {
+ case 0x10: /* 133 */
mask = ATA_UDMA6;
- else if ((scsc & 0x30) == 0x20) /* 2xPCI */
+ break;
+ case 0x20: /* 2xPCI */
mask = ATA_UDMA6;
- else if ((scsc & 0x30) == 0x00) /* 100 */
+ break;
+ case 0x00: /* 100 */
mask = ATA_UDMA5;
- else /* Disabled ? */
+ break;
+ default: /* Disabled ? */
BUG();
+ }
return mask;
}
@@ -175,15 +226,16 @@ static u8 sil_sata_udma_filter(ide_drive_t *drive)
static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
{
- const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
- const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+ static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+ static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
ide_drive_t *pair = ide_get_paired_drive(drive);
u32 speedt = 0;
u16 speedp = 0;
unsigned long addr = siimage_seldev(drive, 0x04);
- unsigned long tfaddr = siimage_selreg(hwif, 0x02);
+ unsigned long tfaddr = siimage_selreg(hwif, 0x02);
unsigned long base = (unsigned long)hwif->hwif_data;
u8 tf_pio = pio;
u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84)
@@ -203,36 +255,20 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
speedp = data_speed[pio];
speedt = tf_speed[tf_pio];
- if (hwif->mmio) {
- hwif->OUTW(speedp, addr);
- hwif->OUTW(speedt, tfaddr);
- /* Now set up IORDY */
- if (pio > 2)
- hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
- else
- hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
-
- mode = hwif->INB(base + addr_mask);
- mode &= ~(unit ? 0x30 : 0x03);
- mode |= (unit ? 0x10 : 0x01);
- hwif->OUTB(mode, base + addr_mask);
- } else {
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- pci_write_config_word(dev, addr, speedp);
- pci_write_config_word(dev, tfaddr, speedt);
- pci_read_config_word(dev, tfaddr - 2, &speedp);
- speedp &= ~0x200;
- /* Set IORDY for mode 3 or 4 */
- if (pio > 2)
- speedp |= 0x200;
- pci_write_config_word(dev, tfaddr - 2, speedp);
-
- pci_read_config_byte(dev, addr_mask, &mode);
- mode &= ~(unit ? 0x30 : 0x03);
- mode |= (unit ? 0x10 : 0x01);
- pci_write_config_byte(dev, addr_mask, mode);
- }
+ sil_iowrite16(dev, speedp, addr);
+ sil_iowrite16(dev, speedt, tfaddr);
+
+ /* now set up IORDY */
+ speedp = sil_ioread16(dev, tfaddr - 2);
+ speedp &= ~0x200;
+ if (pio > 2)
+ speedp |= 0x200;
+ sil_iowrite16(dev, speedp, tfaddr - 2);
+
+ mode = sil_ioread8(dev, base + addr_mask);
+ mode &= ~(unit ? 0x30 : 0x03);
+ mode |= unit ? 0x10 : 0x01;
+ sil_iowrite8(dev, mode, base + addr_mask);
}
/**
@@ -245,63 +281,49 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
- u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
- u16 dma[] = { 0x2208, 0x10C2, 0x10C1 };
+ static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+ static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+ static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 };
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
u16 ultra = 0, multi = 0;
u8 mode = 0, unit = drive->select.b.unit;
unsigned long base = (unsigned long)hwif->hwif_data;
- u8 scsc = 0, addr_mask = ((hwif->channel) ?
- ((hwif->mmio) ? 0xF4 : 0x84) :
- ((hwif->mmio) ? 0xB4 : 0x80));
-
+ u8 scsc = 0, addr_mask = hwif->channel ?
+ (hwif->mmio ? 0xF4 : 0x84) :
+ (hwif->mmio ? 0xB4 : 0x80);
unsigned long ma = siimage_seldev(drive, 0x08);
unsigned long ua = siimage_seldev(drive, 0x0C);
- if (hwif->mmio) {
- scsc = hwif->INB(base + 0x4A);
- mode = hwif->INB(base + addr_mask);
- multi = hwif->INW(ma);
- ultra = hwif->INW(ua);
- } else {
- pci_read_config_byte(dev, 0x8A, &scsc);
- pci_read_config_byte(dev, addr_mask, &mode);
- pci_read_config_word(dev, ma, &multi);
- pci_read_config_word(dev, ua, &ultra);
- }
+ scsc = sil_ioread8 (dev, base + (hwif->mmio ? 0x4A : 0x8A));
+ mode = sil_ioread8 (dev, base + addr_mask);
+ multi = sil_ioread16(dev, ma);
+ ultra = sil_ioread16(dev, ua);
- mode &= ~((unit) ? 0x30 : 0x03);
+ mode &= ~(unit ? 0x30 : 0x03);
ultra &= ~0x3F;
scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
scsc = is_sata(hwif) ? 1 : scsc;
if (speed >= XFER_UDMA_0) {
- multi = dma[2];
- ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] :
- ultra5[speed - XFER_UDMA_0]);
- mode |= (unit ? 0x30 : 0x03);
+ multi = dma[2];
+ ultra |= scsc ? ultra6[speed - XFER_UDMA_0] :
+ ultra5[speed - XFER_UDMA_0];
+ mode |= unit ? 0x30 : 0x03;
} else {
multi = dma[speed - XFER_MW_DMA_0];
- mode |= (unit ? 0x20 : 0x02);
+ mode |= unit ? 0x20 : 0x02;
}
- if (hwif->mmio) {
- hwif->OUTB(mode, base + addr_mask);
- hwif->OUTW(multi, ma);
- hwif->OUTW(ultra, ua);
- } else {
- pci_write_config_byte(dev, addr_mask, mode);
- pci_write_config_word(dev, ma, multi);
- pci_write_config_word(dev, ua, ultra);
- }
+ sil_iowrite8 (dev, mode, base + addr_mask);
+ sil_iowrite16(dev, multi, ma);
+ sil_iowrite16(dev, ultra, ua);
}
/* returns 1 if dma irq issued, 0 otherwise */
-static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+static int siimage_io_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -309,25 +331,26 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
unsigned long addr = siimage_selreg(hwif, 1);
/* return 1 if INTR asserted */
- if ((hwif->INB(hwif->dma_status) & 4) == 4)
+ if (hwif->INB(hwif->dma_status) & 4)
return 1;
/* return 1 if Device INTR asserted */
pci_read_config_byte(dev, addr, &dma_altstat);
if (dma_altstat & 8)
- return 0; //return 1;
+ return 0; /* return 1; */
+
return 0;
}
/**
- * siimage_mmio_ide_dma_test_irq - check we caused an IRQ
+ * siimage_mmio_dma_test_irq - check we caused an IRQ
* @drive: drive we are testing
*
* Check if we caused an IDE DMA interrupt. We may also have caused
* SATA status interrupts, if so we clean them up and continue.
*/
-
-static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
+
+static int siimage_mmio_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long addr = siimage_selreg(hwif, 0x1);
@@ -335,9 +358,9 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
= (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET];
if (sata_error_addr) {
- unsigned long base = (unsigned long)hwif->hwif_data;
- u32 ext_stat = readl((void __iomem *)(base + 0x10));
- u8 watchdog = 0;
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u32 ext_stat = readl((void __iomem *)(base + 0x10));
+ u8 watchdog = 0;
if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
u32 sata_error = readl(sata_error_addr);
@@ -346,29 +369,34 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
watchdog = (sata_error & 0x00680000) ? 1 : 0;
printk(KERN_WARNING "%s: sata_error = 0x%08x, "
"watchdog = %d, %s\n",
- drive->name, sata_error, watchdog,
- __FUNCTION__);
-
- } else {
+ drive->name, sata_error, watchdog, __func__);
+ } else
watchdog = (ext_stat & 0x8000) ? 1 : 0;
- }
- ext_stat >>= 16;
+ ext_stat >>= 16;
if (!(ext_stat & 0x0404) && !watchdog)
return 0;
}
/* return 1 if INTR asserted */
- if ((readb((void __iomem *)hwif->dma_status) & 0x04) == 0x04)
+ if (readb((void __iomem *)hwif->dma_status) & 0x04)
return 1;
/* return 1 if Device INTR asserted */
- if ((readb((void __iomem *)addr) & 8) == 8)
- return 0; //return 1;
+ if (readb((void __iomem *)addr) & 8)
+ return 0; /* return 1; */
return 0;
}
+static int siimage_dma_test_irq(ide_drive_t *drive)
+{
+ if (drive->hwif->mmio)
+ return siimage_mmio_dma_test_irq(drive);
+ else
+ return siimage_io_dma_test_irq(drive);
+}
+
/**
* sil_sata_reset_poll - wait for SATA reset
* @drive: drive we are resetting
@@ -415,63 +443,33 @@ static void sil_sata_pre_reset(ide_drive_t *drive)
}
/**
- * proc_reports_siimage - add siimage controller to proc
- * @dev: PCI device
- * @clocking: SCSC value
- * @name: controller name
- *
- * Report the clocking mode of the controller and add it to
- * the /proc interface layer
- */
-
-static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
-{
- if (!pdev_is_sata(dev)) {
- printk(KERN_INFO "%s: BASE CLOCK ", name);
- clocking &= 0x03;
- switch (clocking) {
- case 0x03: printk("DISABLED!\n"); break;
- case 0x02: printk("== 2X PCI\n"); break;
- case 0x01: printk("== 133\n"); break;
- case 0x00: printk("== 100\n"); break;
- }
- }
-}
-
-/**
- * setup_mmio_siimage - switch an SI controller into MMIO
+ * setup_mmio_siimage - switch controller into MMIO mode
* @dev: PCI device we are configuring
* @name: device name
*
- * Attempt to put the device into mmio mode. There are some slight
- * complications here with certain systems where the mmio bar isnt
- * mapped so we have to be sure we can fall back to I/O.
+ * Attempt to put the device into MMIO mode. There are some slight
+ * complications here with certain systems where the MMIO BAR isn't
+ * mapped, so we have to be sure that we can fall back to I/O.
*/
-
-static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
+
+static unsigned int setup_mmio_siimage(struct pci_dev *dev, const char *name)
{
resource_size_t bar5 = pci_resource_start(dev, 5);
unsigned long barsize = pci_resource_len(dev, 5);
- u8 tmpbyte = 0;
void __iomem *ioaddr;
- u32 tmp, irq_mask;
/*
- * Drop back to PIO if we can't map the mmio. Some
- * systems seem to get terminally confused in the PCI
- * spaces.
+ * Drop back to PIO if we can't map the MMIO. Some systems
+ * seem to get terminally confused in the PCI spaces.
*/
-
- if(!request_mem_region(bar5, barsize, name))
- {
- printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n");
+ if (!request_mem_region(bar5, barsize, name)) {
+ printk(KERN_WARNING "siimage: IDE controller MMIO ports not "
+ "available.\n");
return 0;
}
-
- ioaddr = ioremap(bar5, barsize);
- if (ioaddr == NULL)
- {
+ ioaddr = ioremap(bar5, barsize);
+ if (ioaddr == NULL) {
release_mem_region(bar5, barsize);
return 0;
}
@@ -479,62 +477,6 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
pci_set_master(dev);
pci_set_drvdata(dev, (void *) ioaddr);
- if (pdev_is_sata(dev)) {
- /* make sure IDE0/1 interrupts are not masked */
- irq_mask = (1 << 22) | (1 << 23);
- tmp = readl(ioaddr + 0x48);
- if (tmp & irq_mask) {
- tmp &= ~irq_mask;
- writel(tmp, ioaddr + 0x48);
- readl(ioaddr + 0x48); /* flush */
- }
- writel(0, ioaddr + 0x148);
- writel(0, ioaddr + 0x1C8);
- }
-
- writeb(0, ioaddr + 0xB4);
- writeb(0, ioaddr + 0xF4);
- tmpbyte = readb(ioaddr + 0x4A);
-
- switch(tmpbyte & 0x30) {
- case 0x00:
- /* In 100 MHz clocking, try and switch to 133 */
- writeb(tmpbyte|0x10, ioaddr + 0x4A);
- break;
- case 0x10:
- /* On 133Mhz clocking */
- break;
- case 0x20:
- /* On PCIx2 clocking */
- break;
- case 0x30:
- /* Clocking is disabled */
- /* 133 clock attempt to force it on */
- writeb(tmpbyte & ~0x20, ioaddr + 0x4A);
- break;
- }
-
- writeb( 0x72, ioaddr + 0xA1);
- writew( 0x328A, ioaddr + 0xA2);
- writel(0x62DD62DD, ioaddr + 0xA4);
- writel(0x43924392, ioaddr + 0xA8);
- writel(0x40094009, ioaddr + 0xAC);
- writeb( 0x72, ioaddr + 0xE1);
- writew( 0x328A, ioaddr + 0xE2);
- writel(0x62DD62DD, ioaddr + 0xE4);
- writel(0x43924392, ioaddr + 0xE8);
- writel(0x40094009, ioaddr + 0xEC);
-
- if (pdev_is_sata(dev)) {
- writel(0xFFFF0000, ioaddr + 0x108);
- writel(0xFFFF0000, ioaddr + 0x188);
- writel(0x00680000, ioaddr + 0x148);
- writel(0x00680000, ioaddr + 0x1C8);
- }
-
- tmpbyte = readb(ioaddr + 0x4A);
-
- proc_reports_siimage(dev, (tmpbyte>>4), name);
return 1;
}
@@ -544,55 +486,92 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
* @name: device name
*
* Perform the initial PCI set up for this device. Attempt to switch
- * to 133MHz clocking if the system isn't already set up to do it.
+ * to 133 MHz clocking if the system isn't already set up to do it.
*/
-static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev,
+ const char *name)
{
- u8 rev = dev->revision, tmpbyte = 0, BA5_EN = 0;
+ unsigned long base, scsc_addr;
+ void __iomem *ioaddr = NULL;
+ u8 rev = dev->revision, tmp, BA5_EN;
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255);
pci_read_config_byte(dev, 0x8A, &BA5_EN);
- if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
- if (setup_mmio_siimage(dev, name)) {
- return 0;
+
+ if ((BA5_EN & 0x01) || pci_resource_start(dev, 5))
+ if (setup_mmio_siimage(dev, name))
+ ioaddr = pci_get_drvdata(dev);
+
+ base = (unsigned long)ioaddr;
+
+ if (ioaddr && pdev_is_sata(dev)) {
+ u32 tmp32, irq_mask;
+
+ /* make sure IDE0/1 interrupts are not masked */
+ irq_mask = (1 << 22) | (1 << 23);
+ tmp32 = readl(ioaddr + 0x48);
+ if (tmp32 & irq_mask) {
+ tmp32 &= ~irq_mask;
+ writel(tmp32, ioaddr + 0x48);
+ readl(ioaddr + 0x48); /* flush */
}
+ writel(0, ioaddr + 0x148);
+ writel(0, ioaddr + 0x1C8);
}
- pci_write_config_byte(dev, 0x80, 0x00);
- pci_write_config_byte(dev, 0x84, 0x00);
- pci_read_config_byte(dev, 0x8A, &tmpbyte);
- switch(tmpbyte & 0x30) {
- case 0x00:
- /* 133 clock attempt to force it on */
- pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);
- case 0x30:
- /* if clocking is disabled */
- /* 133 clock attempt to force it on */
- pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20);
- case 0x10:
- /* 133 already */
- break;
- case 0x20:
- /* BIOS set PCI x2 clocking */
- break;
+ sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80);
+ sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84);
+
+ scsc_addr = base ? (base + 0x4A) : 0x8A;
+ tmp = sil_ioread8(dev, scsc_addr);
+
+ switch (tmp & 0x30) {
+ case 0x00:
+ /* On 100 MHz clocking, try and switch to 133 MHz */
+ sil_iowrite8(dev, tmp | 0x10, scsc_addr);
+ break;
+ case 0x30:
+ /* Clocking is disabled, attempt to force 133MHz clocking. */
+ sil_iowrite8(dev, tmp & ~0x20, scsc_addr);
+ case 0x10:
+ /* On 133Mhz clocking. */
+ break;
+ case 0x20:
+ /* On PCIx2 clocking. */
+ break;
}
- pci_read_config_byte(dev, 0x8A, &tmpbyte);
+ tmp = sil_ioread8(dev, scsc_addr);
- pci_write_config_byte(dev, 0xA1, 0x72);
- pci_write_config_word(dev, 0xA2, 0x328A);
- pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
- pci_write_config_dword(dev, 0xA8, 0x43924392);
- pci_write_config_dword(dev, 0xAC, 0x40094009);
- pci_write_config_byte(dev, 0xB1, 0x72);
- pci_write_config_word(dev, 0xB2, 0x328A);
- pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
- pci_write_config_dword(dev, 0xB8, 0x43924392);
- pci_write_config_dword(dev, 0xBC, 0x40094009);
+ sil_iowrite8 (dev, 0x72, base + 0xA1);
+ sil_iowrite16(dev, 0x328A, base + 0xA2);
+ sil_iowrite32(dev, 0x62DD62DD, base + 0xA4);
+ sil_iowrite32(dev, 0x43924392, base + 0xA8);
+ sil_iowrite32(dev, 0x40094009, base + 0xAC);
+ sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1);
+ sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2);
+ sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4);
+ sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8);
+ sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC);
+
+ if (base && pdev_is_sata(dev)) {
+ writel(0xFFFF0000, ioaddr + 0x108);
+ writel(0xFFFF0000, ioaddr + 0x188);
+ writel(0x00680000, ioaddr + 0x148);
+ writel(0x00680000, ioaddr + 0x1C8);
+ }
+
+ /* report the clocking mode of the controller */
+ if (!pdev_is_sata(dev)) {
+ static const char *clk_str[] =
+ { "== 100", "== 133", "== 2X PCI", "DISABLED!" };
+
+ tmp >>= 4;
+ printk(KERN_INFO "%s: BASE CLOCK %s\n", name, clk_str[tmp & 3]);
+ }
- proc_reports_siimage(dev, (tmpbyte>>4), name);
return 0;
}
@@ -602,8 +581,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch
*
* The basic setup here is fairly simple, we can use standard MMIO
* operations. However we do have to set the taskfile register offsets
- * by hand as there isnt a standard defined layout for them this
- * time.
+ * by hand as there isn't a standard defined layout for them this time.
*
* The hardware supports buffered taskfiles and also some rather nice
* extended PRD tables. For better SI3112 support use the libata driver
@@ -614,23 +592,21 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
struct pci_dev *dev = to_pci_dev(hwif->dev);
void *addr = pci_get_drvdata(dev);
u8 ch = hwif->channel;
- hw_regs_t hw;
- unsigned long base;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long base;
/*
- * Fill in the basic HWIF bits
+ * Fill in the basic hwif bits
*/
-
+ hwif->host_flags |= IDE_HFLAG_MMIO;
default_hwif_mmiops(hwif);
- hwif->hwif_data = addr;
+ hwif->hwif_data = addr;
/*
- * Now set up the hw. We have to do this ourselves as
- * the MMIO layout isnt the same as the standard port
- * based I/O
+ * Now set up the hw. We have to do this ourselves as the
+ * MMIO layout isn't the same as the standard port based I/O.
*/
-
- memset(&hw, 0, sizeof(hw_regs_t));
+ memset(io_ports, 0, sizeof(*io_ports));
base = (unsigned long)addr;
if (ch)
@@ -639,21 +615,18 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
base += 0x80;
/*
- * The buffered task file doesn't have status/control
- * so we can't currently use it sanely since we want to
- * use LBA48 mode.
- */
- hw.io_ports[IDE_DATA_OFFSET] = base;
- hw.io_ports[IDE_ERROR_OFFSET] = base + 1;
- hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2;
- hw.io_ports[IDE_SECTOR_OFFSET] = base + 3;
- hw.io_ports[IDE_LCYL_OFFSET] = base + 4;
- hw.io_ports[IDE_HCYL_OFFSET] = base + 5;
- hw.io_ports[IDE_SELECT_OFFSET] = base + 6;
- hw.io_ports[IDE_STATUS_OFFSET] = base + 7;
- hw.io_ports[IDE_CONTROL_OFFSET] = base + 10;
-
- hw.io_ports[IDE_IRQ_OFFSET] = 0;
+ * The buffered task file doesn't have status/control, so we
+ * can't currently use it sanely since we want to use LBA48 mode.
+ */
+ io_ports->data_addr = base;
+ io_ports->error_addr = base + 1;
+ io_ports->nsect_addr = base + 2;
+ io_ports->lbal_addr = base + 3;
+ io_ports->lbam_addr = base + 4;
+ io_ports->lbah_addr = base + 5;
+ io_ports->device_addr = base + 6;
+ io_ports->status_addr = base + 7;
+ io_ports->ctl_addr = base + 10;
if (pdev_is_sata(dev)) {
base = (unsigned long)addr;
@@ -664,8 +637,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100;
}
- memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-
hwif->irq = dev->irq;
hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00);
@@ -675,19 +646,17 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
static int is_dev_seagate_sata(ide_drive_t *drive)
{
- const char *s = &drive->id->model[0];
- unsigned len;
-
- len = strnlen(s, sizeof(drive->id->model));
+ const char *s = &drive->id->model[0];
+ unsigned len = strnlen(s, sizeof(drive->id->model));
- if ((len > 4) && (!memcmp(s, "ST", 2))) {
+ if ((len > 4) && (!memcmp(s, "ST", 2)))
if ((!memcmp(s + len - 2, "AS", 2)) ||
(!memcmp(s + len - 3, "ASL", 3))) {
printk(KERN_INFO "%s: applying pessimistic Seagate "
"errata fix\n", drive->name);
return 1;
}
- }
+
return 0;
}
@@ -704,7 +673,7 @@ static void __devinit sil_quirkproc(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
- /* Try and raise the rqsize */
+ /* Try and rise the rqsize */
if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
hwif->rqsize = 128;
}
@@ -735,103 +704,91 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif)
}
/**
- * ata66_siimage - check for 80 pin cable
+ * sil_cable_detect - cable detection
* @hwif: interface to check
*
- * Check for the presence of an ATA66 capable cable on the
- * interface.
+ * Check for the presence of an ATA66 capable cable on the interface.
*/
-static u8 __devinit ata66_siimage(ide_hwif_t *hwif)
+static u8 __devinit sil_cable_detect(ide_hwif_t *hwif)
{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long addr = siimage_selreg(hwif, 0);
- u8 ata66 = 0;
-
- if (pci_get_drvdata(dev) == NULL)
- pci_read_config_byte(dev, addr, &ata66);
- else
- ata66 = hwif->INB(addr);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long addr = siimage_selreg(hwif, 0);
+ u8 ata66 = sil_ioread8(dev, addr);
return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
}
-/**
- * init_hwif_siimage - set up hwif structs
- * @hwif: interface to set up
- *
- * We do the basic set up of the interface structure. The SIIMAGE
- * requires several custom handlers so we override the default
- * ide DMA handlers appropriately
- */
-
-static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
-{
- u8 sata = is_sata(hwif);
-
- hwif->set_pio_mode = &sil_set_pio_mode;
- hwif->set_dma_mode = &sil_set_dma_mode;
- hwif->quirkproc = &sil_quirkproc;
-
- if (sata) {
- static int first = 1;
-
- hwif->reset_poll = &sil_sata_reset_poll;
- hwif->pre_reset = &sil_sata_pre_reset;
- hwif->udma_filter = &sil_sata_udma_filter;
-
- if (first) {
- printk(KERN_INFO "siimage: For full SATA support you should use the libata sata_sil module.\n");
- first = 0;
- }
- } else
- hwif->udma_filter = &sil_pata_udma_filter;
-
- hwif->cable_detect = ata66_siimage;
-
- if (hwif->dma_base == 0)
- return;
+static const struct ide_port_ops sil_pata_port_ops = {
+ .set_pio_mode = sil_set_pio_mode,
+ .set_dma_mode = sil_set_dma_mode,
+ .quirkproc = sil_quirkproc,
+ .udma_filter = sil_pata_udma_filter,
+ .cable_detect = sil_cable_detect,
+};
- if (sata)
- hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+static const struct ide_port_ops sil_sata_port_ops = {
+ .set_pio_mode = sil_set_pio_mode,
+ .set_dma_mode = sil_set_dma_mode,
+ .reset_poll = sil_sata_reset_poll,
+ .pre_reset = sil_sata_pre_reset,
+ .quirkproc = sil_quirkproc,
+ .udma_filter = sil_sata_udma_filter,
+ .cable_detect = sil_cable_detect,
+};
- if (hwif->mmio) {
- hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
- } else {
- hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
- }
-}
+static struct ide_dma_ops sil_dma_ops = {
+ .dma_test_irq = siimage_dma_test_irq,
+};
-#define DECLARE_SII_DEV(name_str) \
+#define DECLARE_SII_DEV(name_str, p_ops) \
{ \
.name = name_str, \
.init_chipset = init_chipset_siimage, \
.init_iops = init_iops_siimage, \
- .init_hwif = init_hwif_siimage, \
- .host_flags = IDE_HFLAG_BOOTABLE, \
+ .port_ops = p_ops, \
+ .dma_ops = &sil_dma_ops, \
.pio_mask = ATA_PIO4, \
.mwdma_mask = ATA_MWDMA2, \
.udma_mask = ATA_UDMA6, \
}
static const struct ide_port_info siimage_chipsets[] __devinitdata = {
- /* 0 */ DECLARE_SII_DEV("SiI680"),
- /* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA"),
- /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA")
+ /* 0 */ DECLARE_SII_DEV("SiI680", &sil_pata_port_ops),
+ /* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA", &sil_sata_port_ops),
+ /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA", &sil_sata_port_ops)
};
/**
- * siimage_init_one - pci layer discovery entry
+ * siimage_init_one - PCI layer discovery entry
* @dev: PCI device
* @id: ident table entry
*
- * Called by the PCI code when it finds an SI680 or SI3112 controller.
+ * Called by the PCI code when it finds an SiI680 or SiI3112 controller.
* We then use the IDE PCI generic helper to do most of the work.
*/
-
-static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+
+static int __devinit siimage_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
{
- return ide_setup_pci_device(dev, &siimage_chipsets[id->driver_data]);
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = siimage_chipsets[idx];
+
+ if (idx) {
+ static int first = 1;
+
+ if (first) {
+ printk(KERN_INFO "siimage: For full SATA support you "
+ "should use the libata sata_sil module.\n");
+ first = 0;
+ }
+
+ d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+ }
+
+ return ide_setup_pci_device(dev, &d);
}
static const struct pci_device_id siimage_pci_tbl[] = {
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 512bb4c1fd5c..4b0b85d8faf5 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -59,10 +59,10 @@
#define ATA_16 0x01
#define ATA_33 0x02
#define ATA_66 0x03
-#define ATA_100a 0x04 // SiS730/SiS550 is ATA100 with ATA66 layout
+#define ATA_100a 0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */
#define ATA_100 0x05
-#define ATA_133a 0x06 // SiS961b with 133 support
-#define ATA_133 0x07 // SiS962/963
+#define ATA_133a 0x06 /* SiS961b with 133 support */
+#define ATA_133 0x07 /* SiS962/963 */
static u8 chipset_family;
@@ -111,69 +111,70 @@ static const struct {
Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
-static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
-static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
+static u8 cycle_time_offset[] = { 0, 0, 5, 4, 4, 0, 0 };
+static u8 cycle_time_range[] = { 0, 0, 2, 3, 3, 4, 4 };
static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
- {0,0,0,0,0,0,0}, /* no udma */
- {0,0,0,0,0,0,0}, /* no udma */
- {3,2,1,0,0,0,0}, /* ATA_33 */
- {7,5,3,2,1,0,0}, /* ATA_66 */
- {7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */
- {11,7,5,4,2,1,0}, /* ATA_100 */
- {15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */
- {15,10,7,5,3,2,1}, /* ATA_133 */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 3, 2, 1, 0, 0, 0, 0 }, /* ATA_33 */
+ { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_66 */
+ { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_100a (730 specific),
+ different cycle_time range and offset */
+ { 11, 7, 5, 4, 2, 1, 0 }, /* ATA_100 */
+ { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133a (earliest 691 southbridges) */
+ { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133 */
};
/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133
See SiS962 data sheet for more detail */
static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
- {0,0,0,0,0,0,0}, /* no udma */
- {0,0,0,0,0,0,0}, /* no udma */
- {2,1,1,0,0,0,0},
- {4,3,2,1,0,0,0},
- {4,3,2,1,0,0,0},
- {6,4,3,1,1,1,0},
- {9,6,4,2,2,2,2},
- {9,6,4,2,2,2,2},
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 2, 1, 1, 0, 0, 0, 0 },
+ { 4, 3, 2, 1, 0, 0, 0 },
+ { 4, 3, 2, 1, 0, 0, 0 },
+ { 6, 4, 3, 1, 1, 1, 0 },
+ { 9, 6, 4, 2, 2, 2, 2 },
+ { 9, 6, 4, 2, 2, 2, 2 },
};
/* Initialize time, Active time, Recovery time vary across
IDE clock settings. These 3 arrays hold the register value
for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
static u8 ini_time_value[][8] = {
- {0,0,0,0,0,0,0,0},
- {0,0,0,0,0,0,0,0},
- {2,1,0,0,0,1,0,0},
- {4,3,1,1,1,3,1,1},
- {4,3,1,1,1,3,1,1},
- {6,4,2,2,2,4,2,2},
- {9,6,3,3,3,6,3,3},
- {9,6,3,3,3,6,3,3},
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 2, 1, 0, 0, 0, 1, 0, 0 },
+ { 4, 3, 1, 1, 1, 3, 1, 1 },
+ { 4, 3, 1, 1, 1, 3, 1, 1 },
+ { 6, 4, 2, 2, 2, 4, 2, 2 },
+ { 9, 6, 3, 3, 3, 6, 3, 3 },
+ { 9, 6, 3, 3, 3, 6, 3, 3 },
};
static u8 act_time_value[][8] = {
- {0,0,0,0,0,0,0,0},
- {0,0,0,0,0,0,0,0},
- {9,9,9,2,2,7,2,2},
- {19,19,19,5,4,14,5,4},
- {19,19,19,5,4,14,5,4},
- {28,28,28,7,6,21,7,6},
- {38,38,38,10,9,28,10,9},
- {38,38,38,10,9,28,10,9},
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 9, 9, 9, 2, 2, 7, 2, 2 },
+ { 19, 19, 19, 5, 4, 14, 5, 4 },
+ { 19, 19, 19, 5, 4, 14, 5, 4 },
+ { 28, 28, 28, 7, 6, 21, 7, 6 },
+ { 38, 38, 38, 10, 9, 28, 10, 9 },
+ { 38, 38, 38, 10, 9, 28, 10, 9 },
};
static u8 rco_time_value[][8] = {
- {0,0,0,0,0,0,0,0},
- {0,0,0,0,0,0,0,0},
- {9,2,0,2,0,7,1,1},
- {19,5,1,5,2,16,3,2},
- {19,5,1,5,2,16,3,2},
- {30,9,3,9,4,25,6,4},
- {40,12,4,12,5,34,12,5},
- {40,12,4,12,5,34,12,5},
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 9, 2, 0, 2, 0, 7, 1, 1 },
+ { 19, 5, 1, 5, 2, 16, 3, 2 },
+ { 19, 5, 1, 5, 2, 16, 3, 2 },
+ { 30, 9, 3, 9, 4, 25, 6, 4 },
+ { 40, 12, 4, 12, 5, 34, 12, 5 },
+ { 40, 12, 4, 12, 5, 34, 12, 5 },
};
/*
* Printing configuration
*/
/* Used for chipset type printing at boot time */
-static char* chipset_capability[] = {
+static char *chipset_capability[] = {
"ATA", "ATA 16",
"ATA 33", "ATA 66",
"ATA 100 (1st gen)", "ATA 100 (2nd gen)",
@@ -272,7 +273,7 @@ static void sis_program_timings(ide_drive_t *drive, const u8 mode)
sis_ata133_program_timings(drive, mode);
}
-static void config_drive_art_rwp (ide_drive_t *drive)
+static void config_drive_art_rwp(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -346,7 +347,7 @@ static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
sis_program_timings(drive, speed);
}
-static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
+static u8 sis_ata133_udma_filter(ide_drive_t *drive)
{
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
u32 regdw = 0;
@@ -358,8 +359,7 @@ static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
}
-/* Chip detection and general config */
-static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+static int __devinit sis_find_family(struct pci_dev *dev)
{
struct pci_dev *host;
int i = 0;
@@ -381,7 +381,7 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
chipset_family = ATA_100a;
}
pci_dev_put(host);
-
+
printk(KERN_INFO "SIS5513: %s %s controller\n",
SiSHostChipInfo[i].name, chipset_capability[chipset_family]);
}
@@ -440,63 +440,60 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
}
}
- if (!chipset_family)
- return -1;
+ return chipset_family;
+}
+static unsigned int __devinit init_chipset_sis5513(struct pci_dev *dev,
+ const char *name)
+{
/* Make general config ops here
1/ tell IDE channels to operate in Compatibility mode only
2/ tell old chips to allow per drive IDE timings */
- {
- u8 reg;
- u16 regw;
-
- switch(chipset_family) {
- case ATA_133:
- /* SiS962 operation mode */
- pci_read_config_word(dev, 0x50, &regw);
- if (regw & 0x08)
- pci_write_config_word(dev, 0x50, regw&0xfff7);
- pci_read_config_word(dev, 0x52, &regw);
- if (regw & 0x08)
- pci_write_config_word(dev, 0x52, regw&0xfff7);
- break;
- case ATA_133a:
- case ATA_100:
- /* Fixup latency */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
- /* Set compatibility bit */
- pci_read_config_byte(dev, 0x49, &reg);
- if (!(reg & 0x01)) {
- pci_write_config_byte(dev, 0x49, reg|0x01);
- }
- break;
- case ATA_100a:
- case ATA_66:
- /* Fixup latency */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
-
- /* On ATA_66 chips the bit was elsewhere */
- pci_read_config_byte(dev, 0x52, &reg);
- if (!(reg & 0x04)) {
- pci_write_config_byte(dev, 0x52, reg|0x04);
- }
- break;
- case ATA_33:
- /* On ATA_33 we didn't have a single bit to set */
- pci_read_config_byte(dev, 0x09, &reg);
- if ((reg & 0x0f) != 0x00) {
- pci_write_config_byte(dev, 0x09, reg&0xf0);
- }
- case ATA_16:
- /* force per drive recovery and active timings
- needed on ATA_33 and below chips */
- pci_read_config_byte(dev, 0x52, &reg);
- if (!(reg & 0x08)) {
- pci_write_config_byte(dev, 0x52, reg|0x08);
- }
- break;
- }
+ u8 reg;
+ u16 regw;
+
+ switch (chipset_family) {
+ case ATA_133:
+ /* SiS962 operation mode */
+ pci_read_config_word(dev, 0x50, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(dev, 0x50, regw&0xfff7);
+ pci_read_config_word(dev, 0x52, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(dev, 0x52, regw&0xfff7);
+ break;
+ case ATA_133a:
+ case ATA_100:
+ /* Fixup latency */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+ /* Set compatibility bit */
+ pci_read_config_byte(dev, 0x49, &reg);
+ if (!(reg & 0x01))
+ pci_write_config_byte(dev, 0x49, reg|0x01);
+ break;
+ case ATA_100a:
+ case ATA_66:
+ /* Fixup latency */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
+
+ /* On ATA_66 chips the bit was elsewhere */
+ pci_read_config_byte(dev, 0x52, &reg);
+ if (!(reg & 0x04))
+ pci_write_config_byte(dev, 0x52, reg|0x04);
+ break;
+ case ATA_33:
+ /* On ATA_33 we didn't have a single bit to set */
+ pci_read_config_byte(dev, 0x09, &reg);
+ if ((reg & 0x0f) != 0x00)
+ pci_write_config_byte(dev, 0x09, reg&0xf0);
+ case ATA_16:
+ /* force per drive recovery and active timings
+ needed on ATA_33 and below chips */
+ pci_read_config_byte(dev, 0x52, &reg);
+ if (!(reg & 0x08))
+ pci_write_config_byte(dev, 0x52, reg|0x08);
+ break;
}
return 0;
@@ -517,7 +514,7 @@ static const struct sis_laptop sis_laptop[] = {
{ 0, }
};
-static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
+static u8 __devinit sis_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *pdev = to_pci_dev(hwif->dev);
const struct sis_laptop *lap = &sis_laptop[0];
@@ -546,38 +543,44 @@ static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
}
-static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
-{
- u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
-
- hwif->set_pio_mode = &sis_set_pio_mode;
- hwif->set_dma_mode = &sis_set_dma_mode;
-
- if (chipset_family >= ATA_133)
- hwif->udma_filter = sis5513_ata133_udma_filter;
-
- hwif->cable_detect = ata66_sis5513;
-
- if (hwif->dma_base == 0)
- return;
+static const struct ide_port_ops sis_port_ops = {
+ .set_pio_mode = sis_set_pio_mode,
+ .set_dma_mode = sis_set_dma_mode,
+ .cable_detect = sis_cable_detect,
+};
- hwif->ultra_mask = udma_rates[chipset_family];
-}
+static const struct ide_port_ops sis_ata133_port_ops = {
+ .set_pio_mode = sis_set_pio_mode,
+ .set_dma_mode = sis_set_dma_mode,
+ .udma_filter = sis_ata133_udma_filter,
+ .cable_detect = sis_cable_detect,
+};
static const struct ide_port_info sis5513_chipset __devinitdata = {
.name = "SIS5513",
.init_chipset = init_chipset_sis5513,
- .init_hwif = init_hwif_sis5513,
- .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_NO_AUTODMA |
- IDE_HFLAG_BOOTABLE,
+ .enablebits = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} },
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_NO_AUTODMA,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
};
static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- return ide_setup_pci_device(dev, &sis5513_chipset);
+ struct ide_port_info d = sis5513_chipset;
+ u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
+
+ if (sis_find_family(dev) == 0)
+ return -ENOTSUPP;
+
+ if (chipset_family >= ATA_133)
+ d.port_ops = &sis_ata133_port_ops;
+ else
+ d.port_ops = &sis_port_ops;
+
+ d.udma_mask = udma_rates[chipset_family];
+
+ return ide_setup_pci_device(dev, &d);
}
static const struct pci_device_id sis5513_pci_tbl[] = {
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 1f00251a4a87..ce84fa045d39 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -179,7 +179,7 @@ static void sl82c105_dma_start(ide_drive_t *drive)
struct pci_dev *dev = to_pci_dev(hwif->dev);
int reg = 0x44 + drive->dn * 4;
- DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+ DBG(("%s(drive:%s)\n", __func__, drive->name));
pci_write_config_word(dev, reg, drive->drive_data >> 16);
@@ -203,7 +203,7 @@ static int sl82c105_dma_end(ide_drive_t *drive)
int reg = 0x44 + drive->dn * 4;
int ret;
- DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+ DBG(("%s(drive:%s)\n", __func__, drive->name));
ret = __ide_dma_end(drive);
@@ -232,7 +232,7 @@ static void sl82c105_resetproc(ide_drive_t *drive)
* Return the revision of the Winbond bridge
* which this function is part of.
*/
-static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+static u8 sl82c105_bridge_revision(struct pci_dev *dev)
{
struct pci_dev *bridge;
@@ -282,64 +282,59 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
return dev->irq;
}
-/*
- * Initialise IDE channel
- */
-static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned int rev;
-
- DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
-
- hwif->set_pio_mode = &sl82c105_set_pio_mode;
- hwif->set_dma_mode = &sl82c105_set_dma_mode;
- hwif->resetproc = &sl82c105_resetproc;
-
- if (!hwif->dma_base)
- return;
-
- rev = sl82c105_bridge_revision(dev);
- if (rev <= 5) {
- /*
- * Never ever EVER under any circumstances enable
- * DMA when the bridge is this old.
- */
- printk(" %s: Winbond W83C553 bridge revision %d, "
- "BM-DMA disabled\n", hwif->name, rev);
- return;
- }
-
- hwif->mwdma_mask = ATA_MWDMA2;
-
- hwif->dma_lost_irq = &sl82c105_dma_lost_irq;
- hwif->dma_start = &sl82c105_dma_start;
- hwif->ide_dma_end = &sl82c105_dma_end;
- hwif->dma_timeout = &sl82c105_dma_timeout;
+static const struct ide_port_ops sl82c105_port_ops = {
+ .set_pio_mode = sl82c105_set_pio_mode,
+ .set_dma_mode = sl82c105_set_dma_mode,
+ .resetproc = sl82c105_resetproc,
+};
- if (hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
-}
+static const struct ide_dma_ops sl82c105_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = sl82c105_dma_start,
+ .dma_end = sl82c105_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = sl82c105_dma_lost_irq,
+ .dma_timeout = sl82c105_dma_timeout,
+};
static const struct ide_port_info sl82c105_chipset __devinitdata = {
.name = "W82C105",
.init_chipset = init_chipset_sl82c105,
- .init_hwif = init_hwif_sl82c105,
.enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+ .port_ops = &sl82c105_port_ops,
+ .dma_ops = &sl82c105_dma_ops,
.host_flags = IDE_HFLAG_IO_32BIT |
IDE_HFLAG_UNMASK_IRQS |
/* FIXME: check for Compatibility mode in generic IDE PCI code */
#if defined(CONFIG_LOPEC) || defined(CONFIG_SANDPOINT)
IDE_HFLAG_FORCE_LEGACY_IRQS |
#endif
- IDE_HFLAG_NO_AUTODMA |
- IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_SERIALIZE_DMA |
+ IDE_HFLAG_NO_AUTODMA,
.pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
};
static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- return ide_setup_pci_device(dev, &sl82c105_chipset);
+ struct ide_port_info d = sl82c105_chipset;
+ u8 rev = sl82c105_bridge_revision(dev);
+
+ if (rev <= 5) {
+ /*
+ * Never ever EVER under any circumstances enable
+ * DMA when the bridge is this old.
+ */
+ printk(KERN_INFO "W82C105_IDE: Winbond W83C553 bridge "
+ "revision %d, BM-DMA disabled\n", rev);
+ d.dma_ops = NULL;
+ d.mwdma_mask = 0;
+ d.host_flags &= ~IDE_HFLAG_SERIALIZE_DMA;
+ }
+
+ return ide_setup_pci_device(dev, &d);
}
static const struct pci_device_id sl82c105_pci_tbl[] = {
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 65f4c2ffaa59..dae6e2c94d86 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -27,9 +27,9 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
unsigned long flags;
u16 master_data;
u8 slave_data;
- int control = 0;
+ int control = 0;
/* ISP RTC */
- static const u8 timings[][2]= {
+ static const u8 timings[][2] = {
{ 0, 0 },
{ 0, 0 },
{ 1, 0 },
@@ -125,19 +125,17 @@ static u8 __devinit slc90e66_cable_detect(ide_hwif_t *hwif)
return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
}
-static void __devinit init_hwif_slc90e66(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &slc90e66_set_pio_mode;
- hwif->set_dma_mode = &slc90e66_set_dma_mode;
-
- hwif->cable_detect = slc90e66_cable_detect;
-}
+static const struct ide_port_ops slc90e66_port_ops = {
+ .set_pio_mode = slc90e66_set_pio_mode,
+ .set_dma_mode = slc90e66_set_dma_mode,
+ .cable_detect = slc90e66_cable_detect,
+};
static const struct ide_port_info slc90e66_chipset __devinitdata = {
.name = "SLC90E66",
- .init_hwif = init_hwif_slc90e66,
- .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
- .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+ .enablebits = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} },
+ .port_ops = &slc90e66_port_ops,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS,
.pio_mask = ATA_PIO4,
.swdma_mask = ATA_SWDMA2_ONLY,
.mwdma_mask = ATA_MWDMA12_ONLY,
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 1e4a6262bcef..9b4b27a4c711 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -18,20 +18,20 @@ static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
u16 mode, scr = inw(scr_port);
switch (speed) {
- case XFER_UDMA_4: mode = 0x00c0; break;
- case XFER_UDMA_3: mode = 0x00b0; break;
- case XFER_UDMA_2: mode = 0x00a0; break;
- case XFER_UDMA_1: mode = 0x0090; break;
- case XFER_UDMA_0: mode = 0x0080; break;
- case XFER_MW_DMA_2: mode = 0x0070; break;
- case XFER_MW_DMA_1: mode = 0x0060; break;
- case XFER_MW_DMA_0: mode = 0x0050; break;
- case XFER_PIO_4: mode = 0x0400; break;
- case XFER_PIO_3: mode = 0x0300; break;
- case XFER_PIO_2: mode = 0x0200; break;
- case XFER_PIO_1: mode = 0x0100; break;
- case XFER_PIO_0:
- default: mode = 0x0000; break;
+ case XFER_UDMA_4: mode = 0x00c0; break;
+ case XFER_UDMA_3: mode = 0x00b0; break;
+ case XFER_UDMA_2: mode = 0x00a0; break;
+ case XFER_UDMA_1: mode = 0x0090; break;
+ case XFER_UDMA_0: mode = 0x0080; break;
+ case XFER_MW_DMA_2: mode = 0x0070; break;
+ case XFER_MW_DMA_1: mode = 0x0060; break;
+ case XFER_MW_DMA_0: mode = 0x0050; break;
+ case XFER_PIO_4: mode = 0x0400; break;
+ case XFER_PIO_3: mode = 0x0300; break;
+ case XFER_PIO_2: mode = 0x0200; break;
+ case XFER_PIO_1: mode = 0x0100; break;
+ case XFER_PIO_0:
+ default: mode = 0x0000; break;
}
scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
@@ -157,11 +157,6 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
/* Store the system control register base for convenience... */
hwif->config_data = sc_base;
- hwif->set_pio_mode = &tc86c001_set_pio_mode;
- hwif->set_dma_mode = &tc86c001_set_mode;
-
- hwif->cable_detect = tc86c001_cable_detect;
-
if (!hwif->dma_base)
return;
@@ -173,8 +168,6 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
/* Sector Count Register limit */
hwif->rqsize = 0xffff;
-
- hwif->dma_start = &tc86c001_dma_start;
}
static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
@@ -187,10 +180,29 @@ static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
return err;
}
+static const struct ide_port_ops tc86c001_port_ops = {
+ .set_pio_mode = tc86c001_set_pio_mode,
+ .set_dma_mode = tc86c001_set_mode,
+ .cable_detect = tc86c001_cable_detect,
+};
+
+static const struct ide_dma_ops tc86c001_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = tc86c001_dma_start,
+ .dma_end = __ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
static const struct ide_port_info tc86c001_chipset __devinitdata = {
.name = "TC86C001",
.init_chipset = init_chipset_tc86c001,
.init_hwif = init_hwif_tc86c001,
+ .port_ops = &tc86c001_port_ops,
+ .dma_ops = &tc86c001_dma_ops,
.host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD |
IDE_HFLAG_ABUSE_SET_DMA_MODE,
.pio_mask = ATA_PIO4,
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index a67d02a3f96e..db65a558d4ec 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -87,17 +87,15 @@ static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
triflex_set_mode(drive, XFER_PIO_0 + pio);
}
-static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &triflex_set_pio_mode;
- hwif->set_dma_mode = &triflex_set_mode;
-}
+static const struct ide_port_ops triflex_port_ops = {
+ .set_pio_mode = triflex_set_pio_mode,
+ .set_dma_mode = triflex_set_mode,
+};
static const struct ide_port_info triflex_device __devinitdata = {
.name = "TRIFLEX",
- .init_hwif = init_hwif_triflex,
.enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
- .host_flags = IDE_HFLAG_BOOTABLE,
+ .port_ops = &triflex_port_ops,
.pio_mask = ATA_PIO4,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index de750f7a43e9..a8a3138682ef 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -214,7 +214,7 @@ static void trm290_dma_start(ide_drive_t *drive)
{
}
-static int trm290_ide_dma_end (ide_drive_t *drive)
+static int trm290_dma_end(ide_drive_t *drive)
{
u16 status;
@@ -225,7 +225,7 @@ static int trm290_ide_dma_end (ide_drive_t *drive)
return status != 0x00ff;
}
-static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+static int trm290_dma_test_irq(ide_drive_t *drive)
{
u16 status;
@@ -254,22 +254,11 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
hwif->config_data = cfg_base;
hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
- printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx",
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
hwif->name, hwif->dma_base, hwif->dma_base + 3);
- if (!request_region(hwif->dma_base, 4, hwif->name)) {
- printk(KERN_CONT " -- Error, ports in use.\n");
+ if (ide_allocate_dma_engine(hwif))
return;
- }
-
- hwif->dmatable_cpu = pci_alloc_consistent(dev, PRD_ENTRIES * PRD_BYTES,
- &hwif->dmatable_dma);
- if (!hwif->dmatable_cpu) {
- printk(KERN_CONT " -- Error, unable to allocate DMA table.\n");
- release_region(hwif->dma_base, 4);
- return;
- }
- printk(KERN_CONT "\n");
local_irq_save(flags);
/* put config reg into first byte of hwif->select_data */
@@ -291,14 +280,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
/* sharing IRQ with mate */
hwif->irq = hwif->mate->irq;
- hwif->dma_host_set = &trm290_dma_host_set;
- hwif->dma_setup = &trm290_dma_setup;
- hwif->dma_exec_cmd = &trm290_dma_exec_cmd;
- hwif->dma_start = &trm290_dma_start;
- hwif->ide_dma_end = &trm290_ide_dma_end;
- hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
-
- hwif->selectproc = &trm290_selectproc;
#if 1
{
/*
@@ -317,7 +298,7 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
if (old != compat && old_mask == 0xff) {
/* leave lower 10 bits untouched */
compat += (next_offset += 0x400);
- hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+ hwif->io_ports.ctl_addr = compat + 2;
outw(compat | 1, hwif->config_data);
new = inw(hwif->config_data);
printk(KERN_INFO "%s: control basereg workaround: "
@@ -328,16 +309,32 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
#endif
}
+static const struct ide_port_ops trm290_port_ops = {
+ .selectproc = trm290_selectproc,
+};
+
+static struct ide_dma_ops trm290_dma_ops = {
+ .dma_host_set = trm290_dma_host_set,
+ .dma_setup = trm290_dma_setup,
+ .dma_exec_cmd = trm290_dma_exec_cmd,
+ .dma_start = trm290_dma_start,
+ .dma_end = trm290_dma_end,
+ .dma_test_irq = trm290_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
static const struct ide_port_info trm290_chipset __devinitdata = {
.name = "TRM290",
.init_hwif = init_hwif_trm290,
.chipset = ide_trm290,
+ .port_ops = &trm290_port_ops,
+ .dma_ops = &trm290_dma_ops,
.host_flags = IDE_HFLAG_NO_ATAPI_DMA |
#if 0 /* play it safe for now */
IDE_HFLAG_TRUST_BIOS_FOR_DMA |
#endif
IDE_HFLAG_NO_AUTODMA |
- IDE_HFLAG_BOOTABLE |
IDE_HFLAG_NO_LBA48,
};
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 9004e7521889..566e0ecb8db1 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -340,7 +340,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
* Determine system bus clock.
*/
- via_clock = system_bus_clock() * 1000;
+ via_clock = (ide_pci_clk ? ide_pci_clk : system_bus_clock()) * 1000;
switch (via_clock) {
case 33000: via_clock = 33333; break;
@@ -415,25 +415,21 @@ static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
return ATA_CBL_PATA40;
}
-static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
-{
- hwif->set_pio_mode = &via_set_pio_mode;
- hwif->set_dma_mode = &via_set_drive;
-
- hwif->cable_detect = via82cxxx_cable_detect;
-}
+static const struct ide_port_ops via_port_ops = {
+ .set_pio_mode = via_set_pio_mode,
+ .set_dma_mode = via_set_drive,
+ .cable_detect = via82cxxx_cable_detect,
+};
static const struct ide_port_info via82cxxx_chipset __devinitdata = {
.name = "VP_IDE",
.init_chipset = init_chipset_via82cxxx,
- .init_hwif = init_hwif_via82cxxx,
.enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
+ .port_ops = &via_port_ops,
.host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
- IDE_HFLAG_PIO_NO_DOWNGRADE |
IDE_HFLAG_ABUSE_SET_DMA_MODE |
IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_IO_32BIT |
- IDE_HFLAG_BOOTABLE,
+ IDE_HFLAG_IO_32BIT,
.pio_mask = ATA_PIO5,
.swdma_mask = ATA_SWDMA2,
.mwdma_mask = ATA_MWDMA2,
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index a784a97ca7ec..f0e638dcc3ab 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -36,6 +36,8 @@
#include <asm/machdep.h>
#include <asm/irq.h>
+#define DRV_NAME "ide-mpc8xx"
+
static int identify (volatile u8 *p);
static void print_fixed (volatile u8 *p);
static void print_funcid (int func);
@@ -127,9 +129,9 @@ static int pcmcia_schlvl = PCMCIA_SCHLVL;
* MPC8xx's internal PCMCIA interface
*/
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
+static int __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
{
- unsigned long *p = hw->io_ports;
+ unsigned long *p = hw->io_ports_array;
int i;
typedef struct {
@@ -182,6 +184,13 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
pcmcia_phy_base, pcmcia_phy_end,
pcmcia_phy_end - pcmcia_phy_base);
+ if (!request_mem_region(pcmcia_phy_base,
+ pcmcia_phy_end - pcmcia_phy_base,
+ DRV_NAME)) {
+ printk(KERN_ERR "%s: resources busy\n", DRV_NAME);
+ return -EBUSY;
+ }
+
pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
pcmcia_phy_end-pcmcia_phy_base);
@@ -236,7 +245,7 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
printk ("No card in slot %c: PIPR=%08x\n",
'A' + _slot_, (u32) pcmp->pcmc_pipr);
- return; /* No card in slot */
+ return -ENODEV; /* No card in slot */
}
check_ide_device (pcmcia_base);
@@ -279,9 +288,6 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
}
#endif /* CONFIG_IDE_8xx_PCCARD */
- ide_hwifs[data_port].pio_mask = ATA_PIO4;
- ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
-
/* Enable Harddisk Interrupt,
* and make it edge sensitive
*/
@@ -296,6 +302,8 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
/* Enable falling edge irq */
pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
#endif /* CONFIG_IDE_8xx_PCCARD */
+
+ return 0;
}
#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
@@ -304,9 +312,9 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
* MPC8xx's internal PCMCIA interface
*/
#if defined(CONFIG_IDE_EXT_DIRECT)
-static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
+static int __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
{
- unsigned long *p = hw->io_ports;
+ unsigned long *p = hw->io_ports_array;
int i;
u32 ide_phy_base;
@@ -327,7 +335,12 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
printk ("IDE phys mem : %08x...%08x (size %08x)\n",
ide_phy_base, ide_phy_end,
ide_phy_end - ide_phy_base);
-
+
+ if (!request_mem_region(ide_phy_base, 0x200, DRV_NAME)) {
+ printk(KERN_ERR "%s: resources busy\n", DRV_NAME);
+ return -EBUSY;
+ }
+
ide_base=(unsigned long)ioremap(ide_phy_base,
ide_phy_end-ide_phy_base);
@@ -357,15 +370,14 @@ static void __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
hw->irq = ioport_dsc[data_port].irq;
hw->ack_intr = (ide_ack_intr_t *)ide_interrupt_ack;
- ide_hwifs[data_port].pio_mask = ATA_PIO4;
- ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
-
/* Enable Harddisk Interrupt,
* and make it edge sensitive
*/
/* (11-18) Set edge detect for irq, no wakeup from low power mode */
((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
(0x80000000 >> ioport_dsc[data_port].irq);
+
+ return 0;
}
#endif /* CONFIG_IDE_8xx_DIRECT */
@@ -426,10 +438,14 @@ static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
#elif defined(CONFIG_IDE_EXT_DIRECT)
printk("%s[%d] %s: not implemented yet!\n",
- __FILE__,__LINE__,__FUNCTION__);
+ __FILE__, __LINE__, __func__);
#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
}
+static const struct ide_port_ops m8xx_port_ops = {
+ .set_pio_mode = m8xx_ide_set_pio_mode,
+};
+
static void
ide_interrupt_ack (void *dev)
{
@@ -794,14 +810,30 @@ static int __init mpc8xx_ide_probe(void)
#ifdef IDE0_BASE_OFFSET
memset(&hw, 0, sizeof(hw));
- m8xx_ide_init_ports(&hw, 0);
- ide_init_port_hw(&ide_hwifs[0], &hw);
- idx[0] = 0;
+ if (!m8xx_ide_init_ports(&hw, 0)) {
+ ide_hwif_t *hwif = ide_find_port();
+
+ if (hwif) {
+ ide_init_port_hw(hwif, &hw);
+ hwif->pio_mask = ATA_PIO4;
+ hwif->port_ops = &m8xx_port_ops;
+
+ idx[0] = hwif->index;
+ }
+ }
#ifdef IDE1_BASE_OFFSET
memset(&hw, 0, sizeof(hw));
- m8xx_ide_init_ports(&hw, 1);
- ide_init_port_hw(&ide_hwifs[1], &hw);
- idx[1] = 1;
+ if (!m8xx_ide_init_ports(&hw, 1)) {
+ ide_hwif_t *mate = ide_find_port();
+
+ if (mate) {
+ ide_init_port_hw(mate, &hw);
+ mate->pio_mask = ATA_PIO4;
+ mate->port_ops = &m8xx_port_ops;
+
+ idx[1] = mate->index;
+ }
+ }
#endif
#endif
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 88619b50d9ef..48aa019127bc 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -79,8 +79,6 @@ typedef struct pmac_ide_hwif {
} pmac_ide_hwif_t;
-static pmac_ide_hwif_t pmac_ide[MAX_HWIFS];
-
enum {
controller_ohare, /* OHare based */
controller_heathrow, /* Heathrow/Paddington */
@@ -411,7 +409,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
*/
#define IDE_WAKEUP_DELAY (1*HZ)
-static int pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
+static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
static void pmac_ide_selectproc(ide_drive_t *drive);
static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
@@ -419,7 +417,7 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
#define PMAC_IDE_REG(x) \
- ((void __iomem *)((drive)->hwif->io_ports[IDE_DATA_OFFSET] + (x)))
+ ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
/*
* Apply the timings of the proper unit (master/slave) to the shared
@@ -920,12 +918,30 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
return 0;
}
+static const struct ide_port_ops pmac_ide_ata6_port_ops = {
+ .set_pio_mode = pmac_ide_set_pio_mode,
+ .set_dma_mode = pmac_ide_set_dma_mode,
+ .selectproc = pmac_ide_kauai_selectproc,
+};
+
+static const struct ide_port_ops pmac_ide_port_ops = {
+ .set_pio_mode = pmac_ide_set_pio_mode,
+ .set_dma_mode = pmac_ide_set_dma_mode,
+ .selectproc = pmac_ide_selectproc,
+};
+
+static const struct ide_dma_ops pmac_dma_ops;
+
static const struct ide_port_info pmac_port_info = {
+ .init_dma = pmac_ide_init_dma,
.chipset = ide_pmac,
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ .dma_ops = &pmac_dma_ops,
+#endif
+ .port_ops = &pmac_ide_port_ops,
.host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
- IDE_HFLAG_PIO_NO_DOWNGRADE |
IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+ IDE_HFLAG_MMIO |
IDE_HFLAG_UNMASK_IRQS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
@@ -950,12 +966,15 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
pmif->broken_dma = pmif->broken_dma_warn = 0;
if (of_device_is_compatible(np, "shasta-ata")) {
pmif->kind = controller_sh_ata6;
+ d.port_ops = &pmac_ide_ata6_port_ops;
d.udma_mask = ATA_UDMA6;
} else if (of_device_is_compatible(np, "kauai-ata")) {
pmif->kind = controller_un_ata6;
+ d.port_ops = &pmac_ide_ata6_port_ops;
d.udma_mask = ATA_UDMA5;
} else if (of_device_is_compatible(np, "K2-UATA")) {
pmif->kind = controller_k2_ata6;
+ d.port_ops = &pmac_ide_ata6_port_ops;
d.udma_mask = ATA_UDMA5;
} else if (of_device_is_compatible(np, "keylargo-ata")) {
if (strcmp(np->name, "ata-4") == 0) {
@@ -1032,37 +1051,29 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
default_hwif_mmiops(hwif);
hwif->OUTBSYNC = pmac_outbsync;
- /* Tell common code _not_ to mess with resources */
- hwif->mmio = 1;
hwif->hwif_data = pmif;
ide_init_port_hw(hwif, hw);
- hwif->noprobe = pmif->mediabay;
hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
- hwif->set_pio_mode = pmac_ide_set_pio_mode;
- if (pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6
- || pmif->kind == controller_sh_ata6)
- hwif->selectproc = pmac_ide_kauai_selectproc;
- else
- hwif->selectproc = pmac_ide_selectproc;
- hwif->set_dma_mode = pmac_ide_set_dma_mode;
printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
pmif->mediabay ? " (mediabay)" : "", hwif->irq);
-
+
+ if (pmif->mediabay) {
#ifdef CONFIG_PMAC_MEDIABAY
- if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
- hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_MEDIABAY */
+ if (check_media_bay_by_base(pmif->regbase, MB_CD)) {
+#else
+ if (1) {
+#endif
+ hwif->drives[0].noprobe = 1;
+ hwif->drives[1].noprobe = 1;
+ }
+ }
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
if (pmif->cable_80 == 0)
d.udma_mask &= ATA_UDMA2;
- /* has a DBDMA controller channel */
- if (pmif->dma_regs == 0 || pmac_ide_setup_dma(pmif, hwif) < 0)
#endif
- d.udma_mask = d.mwdma_mask = 0;
idx[0] = hwif->index;
@@ -1076,8 +1087,9 @@ static void __devinit pmac_ide_init_ports(hw_regs_t *hw, unsigned long base)
int i;
for (i = 0; i < 8; ++i)
- hw->io_ports[i] = base + i * 0x10;
- hw->io_ports[8] = base + 0x160;
+ hw->io_ports_array[i] = base + i * 0x10;
+
+ hw->io_ports.ctl_addr = base + 0x160;
}
/*
@@ -1088,35 +1100,36 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
void __iomem *base;
unsigned long regbase;
- int irq;
ide_hwif_t *hwif;
pmac_ide_hwif_t *pmif;
- int i, rc;
+ int irq, rc;
hw_regs_t hw;
- i = 0;
- while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
- || pmac_ide[i].node != NULL))
- ++i;
- if (i >= MAX_HWIFS) {
+ pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
+ if (pmif == NULL)
+ return -ENOMEM;
+
+ hwif = ide_find_port();
+ if (hwif == NULL) {
printk(KERN_ERR "ide-pmac: MacIO interface attach with no slot\n");
printk(KERN_ERR " %s\n", mdev->ofdev.node->full_name);
- return -ENODEV;
+ rc = -ENODEV;
+ goto out_free_pmif;
}
- pmif = &pmac_ide[i];
- hwif = &ide_hwifs[i];
-
if (macio_resource_count(mdev) == 0) {
- printk(KERN_WARNING "ide%d: no address for %s\n",
- i, mdev->ofdev.node->full_name);
- return -ENXIO;
+ printk(KERN_WARNING "ide-pmac: no address for %s\n",
+ mdev->ofdev.node->full_name);
+ rc = -ENXIO;
+ goto out_free_pmif;
}
/* Request memory resource for IO ports */
if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
- printk(KERN_ERR "ide%d: can't request mmio resource !\n", i);
- return -EBUSY;
+ printk(KERN_ERR "ide-pmac: can't request MMIO resource for "
+ "%s!\n", mdev->ofdev.node->full_name);
+ rc = -EBUSY;
+ goto out_free_pmif;
}
/* XXX This is bogus. Should be fixed in the registry by checking
@@ -1125,8 +1138,8 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
* where that happens though...
*/
if (macio_irq_count(mdev) == 0) {
- printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n",
- i, mdev->ofdev.node->full_name);
+ printk(KERN_WARNING "ide-pmac: no intrs for device %s, using "
+ "13\n", mdev->ofdev.node->full_name);
irq = irq_create_mapping(NULL, 13);
} else
irq = macio_irq(mdev, 0);
@@ -1144,7 +1157,9 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
if (macio_resource_count(mdev) >= 2) {
if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
- printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i);
+ printk(KERN_WARNING "ide-pmac: can't request DMA "
+ "resource for %s!\n",
+ mdev->ofdev.node->full_name);
else
pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000);
} else
@@ -1166,11 +1181,15 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
iounmap(pmif->dma_regs);
macio_release_resource(mdev, 1);
}
- memset(pmif, 0, sizeof(*pmif));
macio_release_resource(mdev, 0);
+ kfree(pmif);
}
return rc;
+
+out_free_pmif:
+ kfree(pmif);
+ return rc;
}
static int
@@ -1215,7 +1234,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
pmac_ide_hwif_t *pmif;
void __iomem *base;
unsigned long rbase, rlen;
- int i, rc;
+ int rc;
hw_regs_t hw;
np = pci_device_to_OF_node(pdev);
@@ -1223,30 +1242,32 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n");
return -ENODEV;
}
- i = 0;
- while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
- || pmac_ide[i].node != NULL))
- ++i;
- if (i >= MAX_HWIFS) {
+
+ pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
+ if (pmif == NULL)
+ return -ENOMEM;
+
+ hwif = ide_find_port();
+ if (hwif == NULL) {
printk(KERN_ERR "ide-pmac: PCI interface attach with no slot\n");
printk(KERN_ERR " %s\n", np->full_name);
- return -ENODEV;
+ rc = -ENODEV;
+ goto out_free_pmif;
}
- pmif = &pmac_ide[i];
- hwif = &ide_hwifs[i];
-
if (pci_enable_device(pdev)) {
- printk(KERN_WARNING "ide%i: Can't enable PCI device for %s\n",
- i, np->full_name);
- return -ENXIO;
+ printk(KERN_WARNING "ide-pmac: Can't enable PCI device for "
+ "%s\n", np->full_name);
+ rc = -ENXIO;
+ goto out_free_pmif;
}
pci_set_master(pdev);
if (pci_request_regions(pdev, "Kauai ATA")) {
- printk(KERN_ERR "ide%d: Cannot obtain PCI resources for %s\n",
- i, np->full_name);
- return -ENXIO;
+ printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for "
+ "%s\n", np->full_name);
+ rc = -ENXIO;
+ goto out_free_pmif;
}
hwif->dev = &pdev->dev;
@@ -1276,11 +1297,15 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
/* The inteface is released to the common IDE layer */
pci_set_drvdata(pdev, NULL);
iounmap(base);
- memset(pmif, 0, sizeof(*pmif));
pci_release_regions(pdev);
+ kfree(pmif);
}
return rc;
+
+out_free_pmif:
+ kfree(pmif);
+ return rc;
}
static int
@@ -1652,18 +1677,31 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive)
printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
}
+static const struct ide_dma_ops pmac_dma_ops = {
+ .dma_host_set = pmac_ide_dma_host_set,
+ .dma_setup = pmac_ide_dma_setup,
+ .dma_exec_cmd = pmac_ide_dma_exec_cmd,
+ .dma_start = pmac_ide_dma_start,
+ .dma_end = pmac_ide_dma_end,
+ .dma_test_irq = pmac_ide_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = pmac_ide_dma_lost_irq,
+};
+
/*
* Allocate the data structures needed for using DMA with an interface
* and fill the proper list of functions pointers
*/
-static int __devinit pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+static int __devinit pmac_ide_init_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
{
+ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
struct pci_dev *dev = to_pci_dev(hwif->dev);
/* We won't need pci_dev if we switch to generic consistent
* DMA routines ...
*/
- if (dev == NULL)
+ if (dev == NULL || pmif->dma_regs == 0)
return -ENODEV;
/*
* Allocate space for the DBDMA commands.
@@ -1682,18 +1720,14 @@ static int __devinit pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->sg_max_nents = MAX_DCMDS;
- hwif->dma_host_set = &pmac_ide_dma_host_set;
- hwif->dma_setup = &pmac_ide_dma_setup;
- hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
- hwif->dma_start = &pmac_ide_dma_start;
- hwif->ide_dma_end = &pmac_ide_dma_end;
- hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
- hwif->dma_timeout = &ide_dma_timeout;
- hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
-
return 0;
}
-
+#else
+static int __devinit pmac_ide_init_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
module_init(pmac_ide_probe);
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index f7ede0e42881..5171601fb255 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -20,73 +20,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-
-/**
- * ide_match_hwif - match a PCI IDE against an ide_hwif
- * @io_base: I/O base of device
- * @bootable: set if its bootable
- * @name: name of device
- *
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible. Return the matching hwif,
- * or a new hwif. If we find an error (clashing, out of devices, etc)
- * return NULL
- *
- * FIXME: we need to handle mmio matches here too
- */
-
-static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name)
-{
- int h;
- ide_hwif_t *hwif;
-
- /*
- * Look for a hwif with matching io_base default value.
- * If chipset is "ide_unknown", then claim that hwif slot.
- * Otherwise, some other chipset has already claimed it.. :(
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
- if (hwif->chipset == ide_unknown)
- return hwif; /* match */
- printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n",
- name, io_base, hwif->name);
- return NULL; /* already claimed */
- }
- }
- /*
- * Okay, there is no hwif matching our io_base,
- * so we'll just claim an unassigned slot.
- * Give preference to claiming other slots before claiming ide0/ide1,
- * just in case there's another interface yet-to-be-scanned
- * which uses ports 1f0/170 (the ide0/ide1 defaults).
- *
- * Unless there is a bootable card that does not use the standard
- * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
- */
- if (bootable) {
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->chipset == ide_unknown)
- return hwif; /* pick an unused entry */
- }
- } else {
- for (h = 2; h < MAX_HWIFS; ++h) {
- hwif = ide_hwifs + h;
- if (hwif->chipset == ide_unknown)
- return hwif; /* pick an unused entry */
- }
- }
- for (h = 0; h < 2 && h < MAX_HWIFS; ++h) {
- hwif = ide_hwifs + h;
- if (hwif->chipset == ide_unknown)
- return hwif; /* pick an unused entry */
- }
- printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name);
- return NULL;
-}
-
/**
* ide_setup_pci_baseregs - place a PCI IDE controller native
* @dev: PCI device of interface to switch native
@@ -94,13 +27,13 @@ static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char
*
* We attempt to place the PCI interface into PCI native mode. If
* we succeed the BARs are ok and the controller is in PCI mode.
- * Returns 0 on success or an errno code.
+ * Returns 0 on success or an errno code.
*
* FIXME: if we program the interface and then fail to set the BARS
* we don't switch it back to legacy mode. Do we actually care ??
*/
-
-static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+
+static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name)
{
u8 progif = 0;
@@ -139,16 +72,16 @@ static void ide_pci_clear_simplex(unsigned long dma_base, const char *name)
}
/**
- * ide_get_or_set_dma_base - setup BMIBA
- * @d: IDE port info
+ * ide_pci_dma_base - setup BMIBA
* @hwif: IDE interface
+ * @d: IDE port info
*
* Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space.
* Where a device has a partner that is already in DMA mode we check
* and enforce IDE simplex rules.
*/
-static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_hwif_t *hwif)
+unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
unsigned long dma_base = 0;
@@ -199,6 +132,31 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
out:
return dma_base;
}
+EXPORT_SYMBOL_GPL(ide_pci_dma_base);
+
+/*
+ * Set up BM-DMA capability (PnP BIOS should have done this)
+ */
+int ide_pci_set_master(struct pci_dev *dev, const char *name)
+{
+ u16 pcicmd;
+
+ pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+ if ((pcicmd & PCI_COMMAND_MASTER) == 0) {
+ pci_set_master(dev);
+
+ if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) ||
+ (pcicmd & PCI_COMMAND_MASTER) == 0) {
+ printk(KERN_ERR "%s: error updating PCICMD on %s\n",
+ name, pci_name(dev));
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_set_master);
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
@@ -207,7 +165,6 @@ void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
" PCI slot %s\n", d->name, dev->vendor, dev->device,
dev->revision, pci_name(dev));
}
-
EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
@@ -220,13 +177,13 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
* but if that fails then we only need IO space. The PCI code should
* have setup the proper resources for us already for controllers in
* legacy mode.
- *
+ *
* Returns zero on success or an error code
*/
static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
{
- int ret;
+ int ret, bars;
if (pci_enable_device(dev)) {
ret = pci_enable_device_io(dev);
@@ -249,13 +206,21 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
goto out;
}
- /* FIXME: Temporary - until we put in the hotplug interface logic
- Check that the bits we want are not in use by someone else. */
- ret = pci_request_region(dev, 4, "ide_tmp");
- if (ret < 0)
- goto out;
+ if (d->host_flags & IDE_HFLAG_SINGLE)
+ bars = (1 << 2) - 1;
+ else
+ bars = (1 << 4) - 1;
+
+ if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
+ if (d->host_flags & IDE_HFLAG_CS5520)
+ bars |= (1 << 2);
+ else
+ bars |= (1 << 4);
+ }
- pci_release_region(dev, 4);
+ ret = pci_request_selected_regions(dev, bars, d->name);
+ if (ret < 0)
+ printk(KERN_ERR "%s: can't reserve resources\n", d->name);
out:
return ret;
}
@@ -279,8 +244,8 @@ static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
* Maybe the user deliberately *disabled* the device,
* but we'll eventually ignore it again if no drives respond.
*/
- if (ide_setup_pci_baseregs(dev, d->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd|PCI_COMMAND_IO))
- {
+ if (ide_setup_pci_baseregs(dev, d->name) ||
+ pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
printk(KERN_INFO "%s: device disabled (BIOS)\n", d->name);
return -ENODEV;
}
@@ -301,26 +266,24 @@ static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
* @d: IDE port info
* @bar: BAR number
*
- * Checks if a BAR is configured and points to MMIO space. If so
- * print an error and return an error code. Otherwise return 0
+ * Checks if a BAR is configured and points to MMIO space. If so,
+ * return an error code. Otherwise return 0
*/
-static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d, int bar)
+static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d,
+ int bar)
{
ulong flags = pci_resource_flags(dev, bar);
-
+
/* Unconfigured ? */
if (!flags || pci_resource_len(dev, bar) == 0)
return 0;
- /* I/O space */
- if(flags & PCI_BASE_ADDRESS_IO_MASK)
+ /* I/O space */
+ if (flags & IORESOURCE_IO)
return 0;
-
+
/* Bad */
- printk(KERN_ERR "%s: IO baseregs (BIOS) are reported "
- "as MEM, report to "
- "<andre@linux-ide.org>.\n", d->name);
return -EINVAL;
}
@@ -344,14 +307,16 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev,
{
unsigned long ctl = 0, base = 0;
ide_hwif_t *hwif;
- u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
struct hw_regs_s hw;
if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
- /* Possibly we should fail if these checks report true */
- ide_pci_check_iomem(dev, d, 2*port);
- ide_pci_check_iomem(dev, d, 2*port+1);
-
+ if (ide_pci_check_iomem(dev, d, 2 * port) ||
+ ide_pci_check_iomem(dev, d, 2 * port + 1)) {
+ printk(KERN_ERR "%s: I/O baseregs (BIOS) are reported "
+ "as MEM for port %d!\n", d->name, port);
+ return NULL;
+ }
+
ctl = pci_resource_start(dev, 2*port+1);
base = pci_resource_start(dev, 2*port);
if ((ctl && !base) || (base && !ctl)) {
@@ -360,14 +325,18 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev,
return NULL;
}
}
- if (!ctl)
- {
+ if (!ctl) {
/* Use default values */
ctl = port ? 0x374 : 0x3f4;
base = port ? 0x170 : 0x1f0;
}
- if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
- return NULL; /* no room in ide_hwifs[] */
+
+ hwif = ide_find_port_slot(d);
+ if (hwif == NULL) {
+ printk(KERN_ERR "%s: too many IDE interfaces, no room in "
+ "table\n", d->name);
+ return NULL;
+ }
memset(&hw, 0, sizeof(hw));
hw.irq = irq;
@@ -378,7 +347,6 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev,
ide_init_port_hw(hwif, &hw);
hwif->dev = &dev->dev;
- hwif->cds = d;
return hwif;
}
@@ -394,40 +362,33 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev,
* state
*/
-void ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
+int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- u16 pcicmd;
-
- pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 ||
((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
(dev->class & 0x80))) {
- unsigned long dma_base = ide_get_or_set_dma_base(d, hwif);
- if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
- /*
- * Set up BM-DMA capability
- * (PnP BIOS should have done this)
- */
- pci_set_master(dev);
- if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
- printk(KERN_ERR "%s: %s error updating PCICMD\n",
- hwif->name, d->name);
- dma_base = 0;
- }
- }
- if (dma_base) {
- if (d->init_dma) {
- d->init_dma(hwif, dma_base);
- } else {
- ide_setup_dma(hwif, dma_base);
- }
- } else {
- printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
- "(BIOS)\n", hwif->name, d->name);
- }
+ unsigned long base = ide_pci_dma_base(hwif, d);
+
+ if (base == 0 || ide_pci_set_master(dev, d->name) < 0)
+ return -1;
+
+ if (hwif->mmio)
+ printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
+ else
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, base, base + 7);
+
+ hwif->extra_base = base + (hwif->channel ? 8 : 16);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ ide_setup_dma(hwif, base);
}
+
+ return 0;
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
@@ -514,7 +475,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
*(idx + port) = hwif->index;
}
}
-
EXPORT_SYMBOL_GPL(ide_pci_setup_ports);
/*
@@ -597,7 +557,6 @@ int ide_setup_pci_device(struct pci_dev *dev, const struct ide_port_info *d)
return ret;
}
-
EXPORT_SYMBOL_GPL(ide_setup_pci_device);
int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
@@ -621,5 +580,4 @@ int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
out:
return ret;
}
-
EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 6228fadacd38..9d19aec5820a 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -2167,6 +2167,7 @@ static const struct file_operations dv1394_fops=
/*
* Export information about protocols/devices supported by this driver.
*/
+#ifdef MODULE
static struct ieee1394_device_id dv1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
@@ -2177,6 +2178,7 @@ static struct ieee1394_device_id dv1394_id_table[] = {
};
MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
+#endif /* MODULE */
static struct hpsb_protocol_driver dv1394_driver = {
.name = "dv1394",
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
index b94e55e6eaa5..b5de5f21ef78 100644
--- a/drivers/ieee1394/iso.h
+++ b/drivers/ieee1394/iso.h
@@ -123,6 +123,8 @@ struct hpsb_iso {
/* how many times the buffer has overflowed or underflowed */
atomic_t overflows;
+ /* how many cycles were skipped for a given context */
+ atomic_t skips;
/* Current number of bytes lost in discarded packets */
int bytes_discarded;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 0690469fcecf..e509e13cb7a7 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -1723,6 +1723,8 @@ struct ohci_iso_xmit {
struct dma_prog_region prog;
struct ohci1394_iso_tasklet task;
int task_active;
+ int last_cycle;
+ atomic_t skips;
u32 ContextControlSet;
u32 ContextControlClear;
@@ -1759,6 +1761,8 @@ static int ohci_iso_xmit_init(struct hpsb_iso *iso)
iso->hostdata = xmit;
xmit->ohci = iso->host->hostdata;
xmit->task_active = 0;
+ xmit->last_cycle = -1;
+ atomic_set(&iso->skips, 0);
dma_prog_region_init(&xmit->prog);
@@ -1856,6 +1860,26 @@ static void ohci_iso_xmit_task(unsigned long data)
/* parse cycle */
cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
+ if (xmit->last_cycle > -1) {
+ int cycle_diff = cycle - xmit->last_cycle;
+ int skip;
+
+ /* unwrap */
+ if (cycle_diff < 0) {
+ cycle_diff += 8000;
+ if (cycle_diff < 0)
+ PRINT(KERN_ERR, "bogus cycle diff %d\n",
+ cycle_diff);
+ }
+
+ skip = cycle_diff - 1;
+ if (skip > 0) {
+ DBGMSG("skipped %d cycles without packet loss", skip);
+ atomic_add(skip, &iso->skips);
+ }
+ }
+ xmit->last_cycle = cycle;
+
/* tell the subsystem the packet has gone out */
hpsb_iso_packet_sent(iso, cycle, event != 0x11);
@@ -1943,6 +1967,16 @@ static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info
prev->output_last.branchAddress = cpu_to_le32(
dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
+ /*
+ * Link the skip address to this descriptor itself. This causes a
+ * context to skip a cycle whenever lost cycles or FIFO overruns occur,
+ * without dropping the data at that point the application should then
+ * decide whether this is an error condition or not. Some protocols
+ * can deal with this by dropping some rate-matching padding packets.
+ */
+ next->output_more_immediate.branchAddress =
+ prev->output_last.branchAddress;
+
/* disable interrupt, unless required by the IRQ interval */
if (prev_i % iso->irq_interval) {
prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 04e96ba56e09..ec2a0adbedb2 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -2356,13 +2356,16 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
static void raw1394_iso_fill_status(struct hpsb_iso *iso,
struct raw1394_iso_status *stat)
{
+ int overflows = atomic_read(&iso->overflows);
+ int skips = atomic_read(&iso->skips);
+
stat->config.data_buf_size = iso->buf_size;
stat->config.buf_packets = iso->buf_packets;
stat->config.channel = iso->channel;
stat->config.speed = iso->speed;
stat->config.irq_interval = iso->irq_interval;
stat->n_packets = hpsb_iso_n_ready(iso);
- stat->overflows = atomic_read(&iso->overflows);
+ stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF));
stat->xmit_cycle = iso->xmit_cycle;
}
@@ -2437,6 +2440,8 @@ static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
/* reset overflow counter */
atomic_set(&iso->overflows, 0);
+ /* reset skip counter */
+ atomic_set(&iso->skips, 0);
return 0;
}
@@ -2935,6 +2940,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
/*
* Export information about protocols/devices supported by this driver.
*/
+#ifdef MODULE
static struct ieee1394_device_id raw1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
@@ -2956,6 +2962,7 @@ static struct ieee1394_device_id raw1394_id_table[] = {
};
MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
+#endif /* MODULE */
static struct hpsb_protocol_driver raw1394_driver = {
.name = "raw1394",
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index e03024eeeac1..e24772d336e1 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -1293,6 +1293,7 @@ static const struct file_operations video1394_fops=
/*
* Export information about protocols/devices supported by this driver.
*/
+#ifdef MODULE
static struct ieee1394_device_id video1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
@@ -1313,6 +1314,7 @@ static struct ieee1394_device_id video1394_id_table[] = {
};
MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
+#endif /* MODULE */
static struct hpsb_protocol_driver video1394_driver = {
.name = VIDEO1394_DRIVER_NAME,
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 0d13fe0a260b..3d6d9461c31d 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -160,6 +160,7 @@ struct ehca_qp {
};
u32 qp_type;
enum ehca_ext_qp_type ext_type;
+ enum ib_qp_state state;
struct ipz_queue ipz_squeue;
struct ipz_queue ipz_rqueue;
struct h_galpas galpas;
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index b5ca94c6b8d9..ca5eb0cb628c 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -633,7 +633,7 @@ static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
unsigned long flags;
WARN_ON_ONCE(!in_interrupt());
- if (ehca_debug_level)
+ if (ehca_debug_level >= 3)
ehca_dmp(&cpu_online_map, sizeof(cpumask_t), "");
spin_lock_irqsave(&pool->last_cpu_lock, flags);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 65b3362cdb9b..65048976198c 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -50,7 +50,7 @@
#include "ehca_tools.h"
#include "hcp_if.h"
-#define HCAD_VERSION "0025"
+#define HCAD_VERSION "0026"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
@@ -60,7 +60,6 @@ MODULE_VERSION(HCAD_VERSION);
static int ehca_open_aqp1 = 0;
static int ehca_hw_level = 0;
static int ehca_poll_all_eqs = 1;
-static int ehca_mr_largepage = 1;
int ehca_debug_level = 0;
int ehca_nr_ports = 2;
@@ -70,45 +69,40 @@ int ehca_static_rate = -1;
int ehca_scaling_code = 0;
int ehca_lock_hcalls = -1;
-module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO);
-module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);
-module_param_named(hw_level, ehca_hw_level, int, S_IRUGO);
-module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO);
-module_param_named(use_hp_mr, ehca_use_hp_mr, int, S_IRUGO);
-module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO);
-module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO);
-module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);
-module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO);
-module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO);
+module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO);
+module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);
+module_param_named(hw_level, ehca_hw_level, int, S_IRUGO);
+module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO);
+module_param_named(use_hp_mr, ehca_use_hp_mr, bool, S_IRUGO);
+module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO);
+module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO);
+module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);
+module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO);
module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO);
MODULE_PARM_DESC(open_aqp1,
- "AQP1 on startup (0: no (default), 1: yes)");
+ "Open AQP1 on startup (default: no)");
MODULE_PARM_DESC(debug_level,
- "debug level"
- " (0: no debug traces (default), 1: with debug traces)");
+ "Amount of debug output (0: none (default), 1: traces, "
+ "2: some dumps, 3: lots)");
MODULE_PARM_DESC(hw_level,
- "hardware level"
- " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
+ "Hardware level (0: autosensing (default), "
+ "0x10..0x14: eHCA, 0x20..0x23: eHCA2)");
MODULE_PARM_DESC(nr_ports,
"number of connected ports (-1: autodetect, 1: port one only, "
"2: two ports (default)");
MODULE_PARM_DESC(use_hp_mr,
- "high performance MRs (0: no (default), 1: yes)");
+ "Use high performance MRs (default: no)");
MODULE_PARM_DESC(port_act_time,
- "time to wait for port activation (default: 30 sec)");
+ "Time to wait for port activation (default: 30 sec)");
MODULE_PARM_DESC(poll_all_eqs,
- "polls all event queues periodically"
- " (0: no, 1: yes (default))");
+ "Poll all event queues periodically (default: yes)");
MODULE_PARM_DESC(static_rate,
- "set permanent static rate (default: disabled)");
+ "Set permanent static rate (default: no static rate)");
MODULE_PARM_DESC(scaling_code,
- "set scaling code (0: disabled/default, 1: enabled)");
-MODULE_PARM_DESC(mr_largepage,
- "use large page for MR (0: use PAGE_SIZE (default), "
- "1: use large page depending on MR size");
+ "Enable scaling code (default: no)");
MODULE_PARM_DESC(lock_hcalls,
- "serialize all hCalls made by the driver "
+ "Serialize all hCalls made by the driver "
"(default: autodetect)");
DEFINE_RWLOCK(ehca_qp_idr_lock);
@@ -275,6 +269,7 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
u64 h_ret;
struct hipz_query_hca *rblock;
struct hipz_query_port *port;
+ const char *loc_code;
static const u32 pgsize_map[] = {
HCA_CAP_MR_PGSIZE_4K, 0x1000,
@@ -283,6 +278,12 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
HCA_CAP_MR_PGSIZE_16M, 0x1000000,
};
+ ehca_gen_dbg("Probing adapter %s...",
+ shca->ofdev->node->full_name);
+ loc_code = of_get_property(shca->ofdev->node, "ibm,loc-code", NULL);
+ if (loc_code)
+ ehca_gen_dbg(" ... location lode=%s", loc_code);
+
rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_gen_err("Cannot allocate rblock memory.");
@@ -350,11 +351,9 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
/* translate supported MR page sizes; always support 4K */
shca->hca_cap_mr_pgsize = EHCA_PAGESIZE;
- if (ehca_mr_largepage) { /* support extra sizes only if enabled */
- for (i = 0; i < ARRAY_SIZE(pgsize_map); i += 2)
- if (rblock->memory_page_size_supported & pgsize_map[i])
- shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
- }
+ for (i = 0; i < ARRAY_SIZE(pgsize_map); i += 2)
+ if (rblock->memory_page_size_supported & pgsize_map[i])
+ shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
/* query max MTU from first port -- it's the same for all ports */
port = (struct hipz_query_port *)rblock;
@@ -567,8 +566,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n",
- ehca_debug_level);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ehca_debug_level);
}
static ssize_t ehca_store_debug_level(struct device_driver *ddp,
@@ -657,14 +655,6 @@ static ssize_t ehca_show_adapter_handle(struct device *dev,
}
static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
-static ssize_t ehca_show_mr_largepage(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%d\n", ehca_mr_largepage);
-}
-static DEVICE_ATTR(mr_largepage, S_IRUGO, ehca_show_mr_largepage, NULL);
-
static struct attribute *ehca_dev_attrs[] = {
&dev_attr_adapter_handle.attr,
&dev_attr_num_ports.attr,
@@ -681,7 +671,6 @@ static struct attribute *ehca_dev_attrs[] = {
&dev_attr_cur_mw.attr,
&dev_attr_max_pd.attr,
&dev_attr_max_ah.attr,
- &dev_attr_mr_largepage.attr,
NULL
};
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index f26997fc00f8..46ae4eb2c4e1 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -1794,8 +1794,9 @@ static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
int t;
for (t = start_idx; t <= end_idx; t++) {
u64 pgaddr = page_to_pfn(sg_page(&page_list[t])) << PAGE_SHIFT;
- ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
- *(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
+ if (ehca_debug_level >= 3)
+ ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
+ *(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
ehca_gen_err("uncontiguous page found pgaddr=%lx "
"prev_pgaddr=%lx page_list_i=%x",
@@ -1862,10 +1863,13 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
pgaddr &
~(pginfo->hwpage_size - 1));
}
- ehca_gen_dbg("kpage=%lx chunk_page=%lx "
- "value=%016lx", *kpage, pgaddr,
- *(u64 *)abs_to_virt(
- phys_to_abs(pgaddr)));
+ if (ehca_debug_level >= 3) {
+ u64 val = *(u64 *)abs_to_virt(
+ phys_to_abs(pgaddr));
+ ehca_gen_dbg("kpage=%lx chunk_page=%lx "
+ "value=%016lx",
+ *kpage, pgaddr, val);
+ }
prev_pgaddr = pgaddr;
i++;
pginfo->kpage_cnt++;
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 3eb14a52cbf2..57bef1152cc2 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -550,6 +550,7 @@ static struct ehca_qp *internal_create_qp(
spin_lock_init(&my_qp->spinlock_r);
my_qp->qp_type = qp_type;
my_qp->ext_type = parms.ext_type;
+ my_qp->state = IB_QPS_RESET;
if (init_attr->recv_cq)
my_qp->recv_cq =
@@ -965,7 +966,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
qp_num, bad_send_wqe_p);
/* convert wqe pointer to vadr */
bad_send_wqe_v = abs_to_virt((u64)bad_send_wqe_p);
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num);
squeue = &my_qp->ipz_squeue;
if (ipz_queue_abs_to_offset(squeue, (u64)bad_send_wqe_p, &q_ofs)) {
@@ -978,7 +979,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
*bad_wqe_cnt = 0;
while (wqe->optype != 0xff && wqe->wqef != 0xff) {
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(wqe, 32, "qp_num=%x wqe", qp_num);
wqe->nr_of_data_seg = 0; /* suppress data access */
wqe->wqef = WQEF_PURGE; /* WQE to be purged */
@@ -1450,7 +1451,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
/* no support for max_send/recv_sge yet */
}
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(mqpcb, 4*70, "qp_num=%x", ibqp->qp_num);
h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
@@ -1508,6 +1509,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_QKEY)
my_qp->qkey = attr->qkey;
+ my_qp->state = qp_new_state;
+
modify_qp_exit2:
if (squeue_locked) { /* this means: sqe -> rts */
spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
@@ -1763,7 +1766,7 @@ int ehca_query_qp(struct ib_qp *qp,
if (qp_init_attr)
*qp_init_attr = my_qp->init_attr;
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(qpcb, 4*70, "qp_num=%x", qp->qp_num);
query_qp_exit1:
@@ -1811,7 +1814,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
goto modify_srq_exit0;
}
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(mqpcb, 4*70, "qp_num=%x", my_qp->real_qp_num);
h_ret = hipz_h_modify_qp(shca->ipz_hca_handle, my_qp->ipz_qp_handle,
@@ -1864,7 +1867,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
srq_attr->srq_limit = EHCA_BMASK_GET(
MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(qpcb, 4*70, "qp_num=%x", my_qp->real_qp_num);
query_srq_exit1:
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index a20bbf466188..bbe0436f4f75 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -81,7 +81,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
recv_wr->sg_list[cnt_ds].length;
}
- if (ehca_debug_level) {
+ if (ehca_debug_level >= 3) {
ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
ipz_rqueue);
ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
@@ -281,7 +281,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
return -EINVAL;
}
- if (ehca_debug_level) {
+ if (ehca_debug_level >= 3) {
ehca_gen_dbg("SEND WQE written into queue qp=%p ", qp);
ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "send wqe");
}
@@ -421,6 +421,11 @@ int ehca_post_send(struct ib_qp *qp,
int ret = 0;
unsigned long flags;
+ if (unlikely(my_qp->state != IB_QPS_RTS)) {
+ ehca_err(qp->device, "QP not in RTS state qpn=%x", qp->qp_num);
+ return -EINVAL;
+ }
+
/* LOCK the QUEUE */
spin_lock_irqsave(&my_qp->spinlock_s, flags);
@@ -454,13 +459,14 @@ int ehca_post_send(struct ib_qp *qp,
goto post_send_exit0;
}
wqe_cnt++;
- ehca_dbg(qp->device, "ehca_qp=%p qp_num=%x wqe_cnt=%d",
- my_qp, qp->qp_num, wqe_cnt);
} /* eof for cur_send_wr */
post_send_exit0:
iosync(); /* serialize GAL register access */
hipz_update_sqa(my_qp, wqe_cnt);
+ if (unlikely(ret || ehca_debug_level >= 2))
+ ehca_dbg(qp->device, "ehca_qp=%p qp_num=%x wqe_cnt=%d ret=%i",
+ my_qp, qp->qp_num, wqe_cnt, ret);
my_qp->message_count += wqe_cnt;
spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
return ret;
@@ -520,13 +526,14 @@ static int internal_post_recv(struct ehca_qp *my_qp,
goto post_recv_exit0;
}
wqe_cnt++;
- ehca_dbg(dev, "ehca_qp=%p qp_num=%x wqe_cnt=%d",
- my_qp, my_qp->real_qp_num, wqe_cnt);
} /* eof for cur_recv_wr */
post_recv_exit0:
iosync(); /* serialize GAL register access */
hipz_update_rqa(my_qp, wqe_cnt);
+ if (unlikely(ret || ehca_debug_level >= 2))
+ ehca_dbg(dev, "ehca_qp=%p qp_num=%x wqe_cnt=%d ret=%i",
+ my_qp, my_qp->real_qp_num, wqe_cnt, ret);
spin_unlock_irqrestore(&my_qp->spinlock_r, flags);
return ret;
}
@@ -570,16 +577,17 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
struct ehca_cqe *cqe;
struct ehca_qp *my_qp;
- int cqe_count = 0;
+ int cqe_count = 0, is_error;
poll_cq_one_read_cqe:
cqe = (struct ehca_cqe *)
ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
if (!cqe) {
ret = -EAGAIN;
- ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p "
- "cq_num=%x ret=%i", my_cq, my_cq->cq_number, ret);
- goto poll_cq_one_exit0;
+ if (ehca_debug_level >= 3)
+ ehca_dbg(cq->device, "Completion queue is empty "
+ "my_cq=%p cq_num=%x", my_cq, my_cq->cq_number);
+ goto poll_cq_one_exit0;
}
/* prevents loads being reordered across this point */
@@ -609,7 +617,7 @@ poll_cq_one_read_cqe:
ehca_dbg(cq->device,
"Got CQE with purged bit qp_num=%x src_qp=%x",
cqe->local_qp_number, cqe->remote_qp_number);
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
cqe->local_qp_number,
cqe->remote_qp_number);
@@ -622,11 +630,13 @@ poll_cq_one_read_cqe:
}
}
- /* tracing cqe */
- if (unlikely(ehca_debug_level)) {
+ is_error = cqe->status & WC_STATUS_ERROR_BIT;
+
+ /* trace error CQEs if debug_level >= 1, trace all CQEs if >= 3 */
+ if (unlikely(ehca_debug_level >= 3 || (ehca_debug_level && is_error))) {
ehca_dbg(cq->device,
- "Received COMPLETION ehca_cq=%p cq_num=%x -----",
- my_cq, my_cq->cq_number);
+ "Received %sCOMPLETION ehca_cq=%p cq_num=%x -----",
+ is_error ? "ERROR " : "", my_cq, my_cq->cq_number);
ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
my_cq, my_cq->cq_number);
ehca_dbg(cq->device,
@@ -649,8 +659,9 @@ poll_cq_one_read_cqe:
/* update also queue adder to throw away this entry!!! */
goto poll_cq_one_exit0;
}
+
/* eval ib_wc_status */
- if (unlikely(cqe->status & WC_STATUS_ERROR_BIT)) {
+ if (unlikely(is_error)) {
/* complete with errors */
map_ib_wc_status(cqe->status, &wc->status);
wc->vendor_err = wc->status;
@@ -671,14 +682,6 @@ poll_cq_one_read_cqe:
wc->imm_data = cpu_to_be32(cqe->immediate_data);
wc->sl = cqe->service_level;
- if (unlikely(wc->status != IB_WC_SUCCESS))
- ehca_dbg(cq->device,
- "ehca_cq=%p cq_num=%x WARNING unsuccessful cqe "
- "OPType=%x status=%x qp_num=%x src_qp=%x wr_id=%lx "
- "cqe=%p", my_cq, my_cq->cq_number, cqe->optype,
- cqe->status, cqe->local_qp_number,
- cqe->remote_qp_number, cqe->work_request_id, cqe);
-
poll_cq_one_exit0:
if (cqe_count > 0)
hipz_update_feca(my_cq, cqe_count);
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 1b07f2beafaf..e43ed8f8a0c8 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -211,8 +211,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
break;
case 1: /* qp rqueue_addr */
- ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
- qp->ib_qp.qp_num);
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x rq", qp->ib_qp.qp_num);
ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
&qp->mm_count_rqueue);
if (unlikely(ret)) {
@@ -224,8 +223,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
break;
case 2: /* qp squeue_addr */
- ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
- qp->ib_qp.qp_num);
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x sq", qp->ib_qp.qp_num);
ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
&qp->mm_count_squeue);
if (unlikely(ret)) {
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 7029aa653751..5245e13c3a30 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -123,8 +123,9 @@ static long ehca_plpar_hcall_norets(unsigned long opcode,
int i, sleep_msecs;
unsigned long flags = 0;
- ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT,
- opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ if (unlikely(ehca_debug_level >= 2))
+ ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT,
+ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
for (i = 0; i < 5; i++) {
/* serialize hCalls to work around firmware issue */
@@ -148,7 +149,8 @@ static long ehca_plpar_hcall_norets(unsigned long opcode,
opcode, ret, arg1, arg2, arg3,
arg4, arg5, arg6, arg7);
else
- ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret);
+ if (unlikely(ehca_debug_level >= 2))
+ ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret);
return ret;
}
@@ -172,8 +174,10 @@ static long ehca_plpar_hcall9(unsigned long opcode,
int i, sleep_msecs;
unsigned long flags = 0;
- ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode,
- arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+ if (unlikely(ehca_debug_level >= 2))
+ ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9);
for (i = 0; i < 5; i++) {
/* serialize hCalls to work around firmware issue */
@@ -201,7 +205,7 @@ static long ehca_plpar_hcall9(unsigned long opcode,
ret, outs[0], outs[1], outs[2], outs[3],
outs[4], outs[5], outs[6], outs[7],
outs[8]);
- } else
+ } else if (unlikely(ehca_debug_level >= 2))
ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
ret, outs[0], outs[1], outs[2], outs[3],
outs[4], outs[5], outs[6], outs[7],
@@ -381,7 +385,7 @@ u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
r_cb, /* r6 */
0, 0, 0, 0);
- if (ehca_debug_level)
+ if (ehca_debug_level >= 2)
ehca_dmp(query_port_response_block, 64, "response_block");
return ret;
@@ -731,9 +735,6 @@ u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
u64 ret;
u64 outs[PLPAR_HCALL9_BUFSIZE];
- ehca_gen_dbg("kernel PAGE_SIZE=%x access_ctrl=%016x "
- "vaddr=%lx length=%lx",
- (u32)PAGE_SIZE, access_ctrl, vaddr, length);
ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
adapter_handle.handle, /* r4 */
5, /* r5 */
@@ -758,7 +759,7 @@ u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
{
u64 ret;
- if (unlikely(ehca_debug_level >= 2)) {
+ if (unlikely(ehca_debug_level >= 3)) {
if (count > 1) {
u64 *kpage;
int i;
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 3557e7edc9b6..5e570bb0bb6f 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -204,7 +204,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
uar = &to_mucontext(context)->uar;
} else {
- err = mlx4_ib_db_alloc(dev, &cq->db, 1);
+ err = mlx4_db_alloc(dev->dev, &cq->db, 1);
if (err)
goto err_cq;
@@ -250,7 +250,7 @@ err_mtt:
err_db:
if (!context)
- mlx4_ib_db_free(dev, &cq->db);
+ mlx4_db_free(dev->dev, &cq->db);
err_cq:
kfree(cq);
@@ -435,7 +435,7 @@ int mlx4_ib_destroy_cq(struct ib_cq *cq)
ib_umem_release(mcq->umem);
} else {
mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe + 1);
- mlx4_ib_db_free(dev, &mcq->db);
+ mlx4_db_free(dev->dev, &mcq->db);
}
kfree(mcq);
diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c
index 1c36087aef14..8e342cc9baec 100644
--- a/drivers/infiniband/hw/mlx4/doorbell.c
+++ b/drivers/infiniband/hw/mlx4/doorbell.c
@@ -34,124 +34,6 @@
#include "mlx4_ib.h"
-struct mlx4_ib_db_pgdir {
- struct list_head list;
- DECLARE_BITMAP(order0, MLX4_IB_DB_PER_PAGE);
- DECLARE_BITMAP(order1, MLX4_IB_DB_PER_PAGE / 2);
- unsigned long *bits[2];
- __be32 *db_page;
- dma_addr_t db_dma;
-};
-
-static struct mlx4_ib_db_pgdir *mlx4_ib_alloc_db_pgdir(struct mlx4_ib_dev *dev)
-{
- struct mlx4_ib_db_pgdir *pgdir;
-
- pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL);
- if (!pgdir)
- return NULL;
-
- bitmap_fill(pgdir->order1, MLX4_IB_DB_PER_PAGE / 2);
- pgdir->bits[0] = pgdir->order0;
- pgdir->bits[1] = pgdir->order1;
- pgdir->db_page = dma_alloc_coherent(dev->ib_dev.dma_device,
- PAGE_SIZE, &pgdir->db_dma,
- GFP_KERNEL);
- if (!pgdir->db_page) {
- kfree(pgdir);
- return NULL;
- }
-
- return pgdir;
-}
-
-static int mlx4_ib_alloc_db_from_pgdir(struct mlx4_ib_db_pgdir *pgdir,
- struct mlx4_ib_db *db, int order)
-{
- int o;
- int i;
-
- for (o = order; o <= 1; ++o) {
- i = find_first_bit(pgdir->bits[o], MLX4_IB_DB_PER_PAGE >> o);
- if (i < MLX4_IB_DB_PER_PAGE >> o)
- goto found;
- }
-
- return -ENOMEM;
-
-found:
- clear_bit(i, pgdir->bits[o]);
-
- i <<= o;
-
- if (o > order)
- set_bit(i ^ 1, pgdir->bits[order]);
-
- db->u.pgdir = pgdir;
- db->index = i;
- db->db = pgdir->db_page + db->index;
- db->dma = pgdir->db_dma + db->index * 4;
- db->order = order;
-
- return 0;
-}
-
-int mlx4_ib_db_alloc(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db, int order)
-{
- struct mlx4_ib_db_pgdir *pgdir;
- int ret = 0;
-
- mutex_lock(&dev->pgdir_mutex);
-
- list_for_each_entry(pgdir, &dev->pgdir_list, list)
- if (!mlx4_ib_alloc_db_from_pgdir(pgdir, db, order))
- goto out;
-
- pgdir = mlx4_ib_alloc_db_pgdir(dev);
- if (!pgdir) {
- ret = -ENOMEM;
- goto out;
- }
-
- list_add(&pgdir->list, &dev->pgdir_list);
-
- /* This should never fail -- we just allocated an empty page: */
- WARN_ON(mlx4_ib_alloc_db_from_pgdir(pgdir, db, order));
-
-out:
- mutex_unlock(&dev->pgdir_mutex);
-
- return ret;
-}
-
-void mlx4_ib_db_free(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db)
-{
- int o;
- int i;
-
- mutex_lock(&dev->pgdir_mutex);
-
- o = db->order;
- i = db->index;
-
- if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) {
- clear_bit(i ^ 1, db->u.pgdir->order0);
- ++o;
- }
-
- i >>= o;
- set_bit(i, db->u.pgdir->bits[o]);
-
- if (bitmap_full(db->u.pgdir->order1, MLX4_IB_DB_PER_PAGE / 2)) {
- dma_free_coherent(dev->ib_dev.dma_device, PAGE_SIZE,
- db->u.pgdir->db_page, db->u.pgdir->db_dma);
- list_del(&db->u.pgdir->list);
- kfree(db->u.pgdir);
- }
-
- mutex_unlock(&dev->pgdir_mutex);
-}
-
struct mlx4_ib_user_db_page {
struct list_head list;
struct ib_umem *umem;
@@ -160,7 +42,7 @@ struct mlx4_ib_user_db_page {
};
int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
- struct mlx4_ib_db *db)
+ struct mlx4_db *db)
{
struct mlx4_ib_user_db_page *page;
struct ib_umem_chunk *chunk;
@@ -202,7 +84,7 @@ out:
return err;
}
-void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_ib_db *db)
+void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db)
{
mutex_lock(&context->db_page_mutex);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 4d9b5ac42202..4d61e32866c6 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -557,9 +557,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
goto err_uar;
MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
- INIT_LIST_HEAD(&ibdev->pgdir_list);
- mutex_init(&ibdev->pgdir_mutex);
-
ibdev->dev = dev;
strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX);
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 9e637323c155..5cf994794d25 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -43,24 +43,6 @@
#include <linux/mlx4/device.h>
#include <linux/mlx4/doorbell.h>
-enum {
- MLX4_IB_DB_PER_PAGE = PAGE_SIZE / 4
-};
-
-struct mlx4_ib_db_pgdir;
-struct mlx4_ib_user_db_page;
-
-struct mlx4_ib_db {
- __be32 *db;
- union {
- struct mlx4_ib_db_pgdir *pgdir;
- struct mlx4_ib_user_db_page *user_page;
- } u;
- dma_addr_t dma;
- int index;
- int order;
-};
-
struct mlx4_ib_ucontext {
struct ib_ucontext ibucontext;
struct mlx4_uar uar;
@@ -88,7 +70,7 @@ struct mlx4_ib_cq {
struct mlx4_cq mcq;
struct mlx4_ib_cq_buf buf;
struct mlx4_ib_cq_resize *resize_buf;
- struct mlx4_ib_db db;
+ struct mlx4_db db;
spinlock_t lock;
struct mutex resize_mutex;
struct ib_umem *umem;
@@ -127,7 +109,7 @@ struct mlx4_ib_qp {
struct mlx4_qp mqp;
struct mlx4_buf buf;
- struct mlx4_ib_db db;
+ struct mlx4_db db;
struct mlx4_ib_wq rq;
u32 doorbell_qpn;
@@ -154,7 +136,7 @@ struct mlx4_ib_srq {
struct ib_srq ibsrq;
struct mlx4_srq msrq;
struct mlx4_buf buf;
- struct mlx4_ib_db db;
+ struct mlx4_db db;
u64 *wrid;
spinlock_t lock;
int head;
@@ -175,9 +157,6 @@ struct mlx4_ib_dev {
struct mlx4_dev *dev;
void __iomem *uar_map;
- struct list_head pgdir_list;
- struct mutex pgdir_mutex;
-
struct mlx4_uar priv_uar;
u32 priv_pdn;
MLX4_DECLARE_DOORBELL_LOCK(uar_lock);
@@ -248,11 +227,9 @@ static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah)
return container_of(ibah, struct mlx4_ib_ah, ibah);
}
-int mlx4_ib_db_alloc(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db, int order);
-void mlx4_ib_db_free(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db);
int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
- struct mlx4_ib_db *db);
-void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_ib_db *db);
+ struct mlx4_db *db);
+void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db);
struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc);
int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index b75efae7e449..80ea8b9e7761 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -514,7 +514,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
goto err;
if (!init_attr->srq) {
- err = mlx4_ib_db_alloc(dev, &qp->db, 0);
+ err = mlx4_db_alloc(dev->dev, &qp->db, 0);
if (err)
goto err;
@@ -580,7 +580,7 @@ err_buf:
err_db:
if (!pd->uobject && !init_attr->srq)
- mlx4_ib_db_free(dev, &qp->db);
+ mlx4_db_free(dev->dev, &qp->db);
err:
return err;
@@ -666,7 +666,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
kfree(qp->rq.wrid);
mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
if (!qp->ibqp.srq)
- mlx4_ib_db_free(dev, &qp->db);
+ mlx4_db_free(dev->dev, &qp->db);
}
}
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index beaa3b06cf58..204619702f9d 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -129,7 +129,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
if (err)
goto err_mtt;
} else {
- err = mlx4_ib_db_alloc(dev, &srq->db, 0);
+ err = mlx4_db_alloc(dev->dev, &srq->db, 0);
if (err)
goto err_srq;
@@ -200,7 +200,7 @@ err_buf:
err_db:
if (!pd->uobject)
- mlx4_ib_db_free(dev, &srq->db);
+ mlx4_db_free(dev->dev, &srq->db);
err_srq:
kfree(srq);
@@ -267,7 +267,7 @@ int mlx4_ib_destroy_srq(struct ib_srq *srq)
kfree(msrq->wrid);
mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
&msrq->buf);
- mlx4_ib_db_free(dev, &msrq->db);
+ mlx4_db_free(dev->dev, &msrq->db);
}
kfree(msrq);
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index b046262ed638..a4e9269a29bd 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -139,8 +139,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
addr = ntohl(ifa->ifa_address);
mask = ntohl(ifa->ifa_mask);
- nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %08X, netmask %08X.\n",
- addr, mask);
+ nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address " NIPQUAD_FMT
+ ", netmask " NIPQUAD_FMT ".\n",
+ HIPQUAD(addr), HIPQUAD(mask));
list_for_each_entry(nesdev, &nes_dev_list, list) {
nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n",
nesdev, nesdev->netdev[0]->name);
@@ -353,13 +354,11 @@ struct ib_qp *nes_get_qp(struct ib_device *device, int qpn)
*/
static void nes_print_macaddr(struct net_device *netdev)
{
- nes_debug(NES_DBG_INIT, "%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, IRQ %u\n",
- netdev->name,
- netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
- netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5],
- netdev->irq);
-}
+ DECLARE_MAC_BUF(mac);
+ nes_debug(NES_DBG_INIT, "%s: %s, IRQ %u\n",
+ netdev->name, print_mac(mac, netdev->dev_addr), netdev->irq);
+}
/**
* nes_interrupt - handle interrupts
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index d0738623bcf3..d940fc27129a 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -852,8 +852,8 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
/* get a handle on the hte */
hte = &cm_core->connected_nodes;
- nes_debug(NES_DBG_CM, "Searching for an owner node:%x:%x from core %p->%p\n",
- loc_addr, loc_port, cm_core, hte);
+ nes_debug(NES_DBG_CM, "Searching for an owner node: " NIPQUAD_FMT ":%x from core %p->%p\n",
+ HIPQUAD(loc_addr), loc_port, cm_core, hte);
/* walk list and find cm_node associated with this session ID */
spin_lock_irqsave(&cm_core->ht_lock, flags);
@@ -902,8 +902,8 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
}
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- nes_debug(NES_DBG_CM, "Unable to find listener- %x:%x\n",
- dst_addr, dst_port);
+ nes_debug(NES_DBG_CM, "Unable to find listener for " NIPQUAD_FMT ":%x\n",
+ HIPQUAD(dst_addr), dst_port);
/* no listener */
return NULL;
@@ -1054,6 +1054,7 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
int arpindex = 0;
struct nes_device *nesdev;
struct nes_adapter *nesadapter;
+ DECLARE_MAC_BUF(mac);
/* create an hte and cm_node for this instance */
cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
@@ -1066,8 +1067,9 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
cm_node->loc_port = cm_info->loc_port;
cm_node->rem_port = cm_info->rem_port;
cm_node->send_write0 = send_first;
- nes_debug(NES_DBG_CM, "Make node addresses : loc = %x:%x, rem = %x:%x\n",
- cm_node->loc_addr, cm_node->loc_port, cm_node->rem_addr, cm_node->rem_port);
+ nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT ":%x, rem = " NIPQUAD_FMT ":%x\n",
+ HIPQUAD(cm_node->loc_addr), cm_node->loc_port,
+ HIPQUAD(cm_node->rem_addr), cm_node->rem_port);
cm_node->listener = listener;
cm_node->netdev = nesvnic->netdev;
cm_node->cm_id = cm_info->cm_id;
@@ -1116,11 +1118,8 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
/* copy the mac addr to node context */
memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
- nes_debug(NES_DBG_CM, "Remote mac addr from arp table:%02x,"
- " %02x, %02x, %02x, %02x, %02x\n",
- cm_node->rem_mac[0], cm_node->rem_mac[1],
- cm_node->rem_mac[2], cm_node->rem_mac[3],
- cm_node->rem_mac[4], cm_node->rem_mac[5]);
+ nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %s\n",
+ print_mac(mac, cm_node->rem_mac));
add_hte_node(cm_core, cm_node);
atomic_inc(&cm_nodes_created);
@@ -1850,8 +1849,10 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvni
nfo.rem_addr = ntohl(iph->saddr);
nfo.rem_port = ntohs(tcph->source);
- nes_debug(NES_DBG_CM, "Received packet: dest=0x%08X:0x%04X src=0x%08X:0x%04X\n",
- iph->daddr, tcph->dest, iph->saddr, tcph->source);
+ nes_debug(NES_DBG_CM, "Received packet: dest=" NIPQUAD_FMT
+ ":0x%04X src=" NIPQUAD_FMT ":0x%04X\n",
+ NIPQUAD(iph->daddr), tcph->dest,
+ NIPQUAD(iph->saddr), tcph->source);
/* note: this call is going to increment cm_node ref count */
cm_node = find_node(cm_core,
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index aa53aab91bf8..08964cc7e98a 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -636,6 +636,15 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
return 0;
}
+
+ i = 0;
+ while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
+ mdelay(1);
+ if (i >= 10000) {
+ printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
+ return 0;
+ }
}
/* port reset */
@@ -684,17 +693,6 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
}
}
-
-
- i = 0;
- while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
- mdelay(1);
- if (i >= 10000) {
- printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
- nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
- return 0;
- }
-
return port_count;
}
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index b7e2844f096b..8f36e231bdf5 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -905,7 +905,7 @@ struct nes_hw_qp {
};
struct nes_hw_cq {
- struct nes_hw_cqe volatile *cq_vbase; /* PCI memory for host rings */
+ struct nes_hw_cqe *cq_vbase; /* PCI memory for host rings */
void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_cq *cq);
dma_addr_t cq_pbase; /* PCI memory for host rings */
u16 cq_head;
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 01cd0effc492..e5366b013c1a 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -787,16 +787,14 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
int i;
u32 macaddr_low;
u16 macaddr_high;
+ DECLARE_MAC_BUF(mac);
if (!is_valid_ether_addr(mac_addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
- printk(PFX "%s: Address length = %d, Address = %02X%02X%02X%02X%02X%02X..\n",
- __func__, netdev->addr_len,
- mac_addr->sa_data[0], mac_addr->sa_data[1],
- mac_addr->sa_data[2], mac_addr->sa_data[3],
- mac_addr->sa_data[4], mac_addr->sa_data[5]);
+ printk(PFX "%s: Address length = %d, Address = %s\n",
+ __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data));
macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
macaddr_high += (u16)netdev->dev_addr[1];
macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
@@ -878,11 +876,11 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
if (mc_nic_index < 0)
mc_nic_index = nesvnic->nic_index;
if (multicast_addr) {
- nes_debug(NES_DBG_NIC_RX, "Assigning MC Address = %02X%02X%02X%02X%02X%02X to register 0x%04X nic_idx=%d\n",
- multicast_addr->dmi_addr[0], multicast_addr->dmi_addr[1],
- multicast_addr->dmi_addr[2], multicast_addr->dmi_addr[3],
- multicast_addr->dmi_addr[4], multicast_addr->dmi_addr[5],
- perfect_filter_register_address+(mc_index * 8), mc_nic_index);
+ DECLARE_MAC_BUF(mac);
+ nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n",
+ print_mac(mac, multicast_addr->dmi_addr),
+ perfect_filter_register_address+(mc_index * 8),
+ mc_nic_index);
macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
macaddr_high += (u16)multicast_addr->dmi_addr[1];
macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index f9db07c2717d..c6d5631a6995 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -660,7 +660,9 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti
/* DELETE or RESOLVE */
if (arp_index == nesadapter->arp_table_size) {
- nes_debug(NES_DBG_NETDEV, "mac address not in ARP table - cannot delete or resolve\n");
+ nes_debug(NES_DBG_NETDEV, "MAC for " NIPQUAD_FMT " not in ARP table - cannot %s\n",
+ HIPQUAD(ip_addr),
+ action == NES_ARP_RESOLVE ? "resolve" : "delete");
return -1;
}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index f9a5d4390892..ee74f7c7a6da 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1976,7 +1976,7 @@ static int nes_destroy_cq(struct ib_cq *ib_cq)
if (nescq->cq_mem_size)
pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size,
- (void *)nescq->hw_cq.cq_vbase, nescq->hw_cq.cq_pbase);
+ nescq->hw_cq.cq_vbase, nescq->hw_cq.cq_pbase);
kfree(nescq);
return ret;
@@ -3610,6 +3610,12 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
while (cqe_count < num_entries) {
if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
NES_CQE_VALID) {
+ /*
+ * Make sure we read CQ entry contents *after*
+ * we've checked the valid bit.
+ */
+ rmb();
+
cqe = nescq->hw_cq.cq_vbase[head];
nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 73b2b176ad0e..f1f142dc64b1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -56,11 +56,11 @@
/* constants */
enum {
- IPOIB_PACKET_SIZE = 2048,
- IPOIB_BUF_SIZE = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
-
IPOIB_ENCAP_LEN = 4,
+ IPOIB_UD_HEAD_SIZE = IB_GRH_BYTES + IPOIB_ENCAP_LEN,
+ IPOIB_UD_RX_SG = 2, /* max buffer needed for 4K mtu */
+
IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */
IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN,
IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
@@ -139,7 +139,7 @@ struct ipoib_mcast {
struct ipoib_rx_buf {
struct sk_buff *skb;
- u64 mapping;
+ u64 mapping[IPOIB_UD_RX_SG];
};
struct ipoib_tx_buf {
@@ -294,6 +294,7 @@ struct ipoib_dev_priv {
unsigned int admin_mtu;
unsigned int mcast_mtu;
+ unsigned int max_ib_mtu;
struct ipoib_rx_buf *rx_ring;
@@ -305,6 +306,9 @@ struct ipoib_dev_priv {
struct ib_send_wr tx_wr;
unsigned tx_outstanding;
+ struct ib_recv_wr rx_wr;
+ struct ib_sge rx_sge[IPOIB_UD_RX_SG];
+
struct ib_wc ibwc[IPOIB_NUM_WC];
struct list_head dead_ahs;
@@ -366,6 +370,14 @@ struct ipoib_neigh {
struct list_head list;
};
+#define IPOIB_UD_MTU(ib_mtu) (ib_mtu - IPOIB_ENCAP_LEN)
+#define IPOIB_UD_BUF_SIZE(ib_mtu) (ib_mtu + IB_GRH_BYTES)
+
+static inline int ipoib_ud_need_sg(unsigned int ib_mtu)
+{
+ return IPOIB_UD_BUF_SIZE(ib_mtu) > PAGE_SIZE;
+}
+
/*
* We stash a pointer to our private neighbour information after our
* hardware address in neigh->ha. The ALIGN() expression here makes
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 0205eb7c1bd3..7cf1fa7074ab 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -89,28 +89,59 @@ void ipoib_free_ah(struct kref *kref)
spin_unlock_irqrestore(&priv->lock, flags);
}
+static void ipoib_ud_dma_unmap_rx(struct ipoib_dev_priv *priv,
+ u64 mapping[IPOIB_UD_RX_SG])
+{
+ if (ipoib_ud_need_sg(priv->max_ib_mtu)) {
+ ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_UD_HEAD_SIZE,
+ DMA_FROM_DEVICE);
+ ib_dma_unmap_page(priv->ca, mapping[1], PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ } else
+ ib_dma_unmap_single(priv->ca, mapping[0],
+ IPOIB_UD_BUF_SIZE(priv->max_ib_mtu),
+ DMA_FROM_DEVICE);
+}
+
+static void ipoib_ud_skb_put_frags(struct ipoib_dev_priv *priv,
+ struct sk_buff *skb,
+ unsigned int length)
+{
+ if (ipoib_ud_need_sg(priv->max_ib_mtu)) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
+ unsigned int size;
+ /*
+ * There is only two buffers needed for max_payload = 4K,
+ * first buf size is IPOIB_UD_HEAD_SIZE
+ */
+ skb->tail += IPOIB_UD_HEAD_SIZE;
+ skb->len += length;
+
+ size = length - IPOIB_UD_HEAD_SIZE;
+
+ frag->size = size;
+ skb->data_len += size;
+ skb->truesize += size;
+ } else
+ skb_put(skb, length);
+
+}
+
static int ipoib_ib_post_receive(struct net_device *dev, int id)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- struct ib_sge list;
- struct ib_recv_wr param;
struct ib_recv_wr *bad_wr;
int ret;
- list.addr = priv->rx_ring[id].mapping;
- list.length = IPOIB_BUF_SIZE;
- list.lkey = priv->mr->lkey;
+ priv->rx_wr.wr_id = id | IPOIB_OP_RECV;
+ priv->rx_sge[0].addr = priv->rx_ring[id].mapping[0];
+ priv->rx_sge[1].addr = priv->rx_ring[id].mapping[1];
- param.next = NULL;
- param.wr_id = id | IPOIB_OP_RECV;
- param.sg_list = &list;
- param.num_sge = 1;
- ret = ib_post_recv(priv->qp, &param, &bad_wr);
+ ret = ib_post_recv(priv->qp, &priv->rx_wr, &bad_wr);
if (unlikely(ret)) {
ipoib_warn(priv, "receive failed for buf %d (%d)\n", id, ret);
- ib_dma_unmap_single(priv->ca, priv->rx_ring[id].mapping,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ ipoib_ud_dma_unmap_rx(priv, priv->rx_ring[id].mapping);
dev_kfree_skb_any(priv->rx_ring[id].skb);
priv->rx_ring[id].skb = NULL;
}
@@ -118,15 +149,21 @@ static int ipoib_ib_post_receive(struct net_device *dev, int id)
return ret;
}
-static int ipoib_alloc_rx_skb(struct net_device *dev, int id)
+static struct sk_buff *ipoib_alloc_rx_skb(struct net_device *dev, int id)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
- u64 addr;
+ int buf_size;
+ u64 *mapping;
- skb = dev_alloc_skb(IPOIB_BUF_SIZE + 4);
- if (!skb)
- return -ENOMEM;
+ if (ipoib_ud_need_sg(priv->max_ib_mtu))
+ buf_size = IPOIB_UD_HEAD_SIZE;
+ else
+ buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu);
+
+ skb = dev_alloc_skb(buf_size + 4);
+ if (unlikely(!skb))
+ return NULL;
/*
* IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte
@@ -135,17 +172,32 @@ static int ipoib_alloc_rx_skb(struct net_device *dev, int id)
*/
skb_reserve(skb, 4);
- addr = ib_dma_map_single(priv->ca, skb->data, IPOIB_BUF_SIZE,
- DMA_FROM_DEVICE);
- if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
- dev_kfree_skb_any(skb);
- return -EIO;
+ mapping = priv->rx_ring[id].mapping;
+ mapping[0] = ib_dma_map_single(priv->ca, skb->data, buf_size,
+ DMA_FROM_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, mapping[0])))
+ goto error;
+
+ if (ipoib_ud_need_sg(priv->max_ib_mtu)) {
+ struct page *page = alloc_page(GFP_ATOMIC);
+ if (!page)
+ goto partial_error;
+ skb_fill_page_desc(skb, 0, page, 0, PAGE_SIZE);
+ mapping[1] =
+ ib_dma_map_page(priv->ca, skb_shinfo(skb)->frags[0].page,
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, mapping[1])))
+ goto partial_error;
}
- priv->rx_ring[id].skb = skb;
- priv->rx_ring[id].mapping = addr;
+ priv->rx_ring[id].skb = skb;
+ return skb;
- return 0;
+partial_error:
+ ib_dma_unmap_single(priv->ca, mapping[0], buf_size, DMA_FROM_DEVICE);
+error:
+ dev_kfree_skb_any(skb);
+ return NULL;
}
static int ipoib_ib_post_receives(struct net_device *dev)
@@ -154,7 +206,7 @@ static int ipoib_ib_post_receives(struct net_device *dev)
int i;
for (i = 0; i < ipoib_recvq_size; ++i) {
- if (ipoib_alloc_rx_skb(dev, i)) {
+ if (!ipoib_alloc_rx_skb(dev, i)) {
ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
return -ENOMEM;
}
@@ -172,7 +224,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
struct ipoib_dev_priv *priv = netdev_priv(dev);
unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
struct sk_buff *skb;
- u64 addr;
+ u64 mapping[IPOIB_UD_RX_SG];
ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n",
wr_id, wc->status);
@@ -184,15 +236,13 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
}
skb = priv->rx_ring[wr_id].skb;
- addr = priv->rx_ring[wr_id].mapping;
if (unlikely(wc->status != IB_WC_SUCCESS)) {
if (wc->status != IB_WC_WR_FLUSH_ERR)
ipoib_warn(priv, "failed recv event "
"(status=%d, wrid=%d vend_err %x)\n",
wc->status, wr_id, wc->vendor_err);
- ib_dma_unmap_single(priv->ca, addr,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ ipoib_ud_dma_unmap_rx(priv, priv->rx_ring[wr_id].mapping);
dev_kfree_skb_any(skb);
priv->rx_ring[wr_id].skb = NULL;
return;
@@ -205,11 +255,14 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
if (wc->slid == priv->local_lid && wc->src_qp == priv->qp->qp_num)
goto repost;
+ memcpy(mapping, priv->rx_ring[wr_id].mapping,
+ IPOIB_UD_RX_SG * sizeof *mapping);
+
/*
* If we can't allocate a new RX buffer, dump
* this packet and reuse the old buffer.
*/
- if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
+ if (unlikely(!ipoib_alloc_rx_skb(dev, wr_id))) {
++dev->stats.rx_dropped;
goto repost;
}
@@ -217,9 +270,9 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
wc->byte_len, wc->slid);
- ib_dma_unmap_single(priv->ca, addr, IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ ipoib_ud_dma_unmap_rx(priv, mapping);
+ ipoib_ud_skb_put_frags(priv, skb, wc->byte_len);
- skb_put(skb, wc->byte_len);
skb_pull(skb, IB_GRH_BYTES);
skb->protocol = ((struct ipoib_header *) skb->data)->proto;
@@ -733,10 +786,8 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
rx_req = &priv->rx_ring[i];
if (!rx_req->skb)
continue;
- ib_dma_unmap_single(priv->ca,
- rx_req->mapping,
- IPOIB_BUF_SIZE,
- DMA_FROM_DEVICE);
+ ipoib_ud_dma_unmap_rx(priv,
+ priv->rx_ring[i].mapping);
dev_kfree_skb_any(rx_req->skb);
rx_req->skb = NULL;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index bd07f02cf02b..7a4ed9d3d844 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -195,7 +195,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
- if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN)
+ if (new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu))
return -EINVAL;
priv->admin_mtu = new_mtu;
@@ -971,10 +971,6 @@ static void ipoib_setup(struct net_device *dev)
NETIF_F_LLTX |
NETIF_F_HIGHDMA);
- /* MTU will be reset when mcast join happens */
- dev->mtu = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
- priv->mcast_mtu = priv->admin_mtu = dev->mtu;
-
memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
netif_carrier_off(dev);
@@ -1107,6 +1103,7 @@ static struct net_device *ipoib_add_port(const char *format,
{
struct ipoib_dev_priv *priv;
struct ib_device_attr *device_attr;
+ struct ib_port_attr attr;
int result = -ENOMEM;
priv = ipoib_intf_alloc(format);
@@ -1115,6 +1112,18 @@ static struct net_device *ipoib_add_port(const char *format,
SET_NETDEV_DEV(priv->dev, hca->dma_device);
+ if (!ib_query_port(hca, port, &attr))
+ priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu);
+ else {
+ printk(KERN_WARNING "%s: ib_query_port %d failed\n",
+ hca->name, port);
+ goto device_init_failed;
+ }
+
+ /* MTU will be reset when mcast join happens */
+ priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu);
+ priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu;
+
result = ib_query_pkey(hca, port, 0, &priv->pkey);
if (result) {
printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n",
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 31a53c5bcb13..d00a2c174aee 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -567,8 +567,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
return;
}
- priv->mcast_mtu = ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu) -
- IPOIB_ENCAP_LEN;
+ priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu));
if (!ipoib_cm_admin_enabled(dev))
dev->mtu = min(priv->mcast_mtu, priv->admin_mtu);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 8a20e3742c43..07c03f178a49 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -150,7 +150,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
.max_send_wr = ipoib_sendq_size,
.max_recv_wr = ipoib_recvq_size,
.max_send_sge = 1,
- .max_recv_sge = 1
+ .max_recv_sge = IPOIB_UD_RX_SG
},
.sq_sig_type = IB_SIGNAL_ALL_WR,
.qp_type = IB_QPT_UD
@@ -215,6 +215,19 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
priv->tx_wr.sg_list = priv->tx_sge;
priv->tx_wr.send_flags = IB_SEND_SIGNALED;
+ priv->rx_sge[0].lkey = priv->mr->lkey;
+ if (ipoib_ud_need_sg(priv->max_ib_mtu)) {
+ priv->rx_sge[0].length = IPOIB_UD_HEAD_SIZE;
+ priv->rx_sge[1].length = PAGE_SIZE;
+ priv->rx_sge[1].lkey = priv->mr->lkey;
+ priv->rx_wr.num_sge = IPOIB_UD_RX_SG;
+ } else {
+ priv->rx_sge[0].length = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu);
+ priv->rx_wr.num_sge = 1;
+ }
+ priv->rx_wr.next = NULL;
+ priv->rx_wr.sg_list = priv->rx_sge;
+
return 0;
out_free_cq:
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 293f5b892e3f..431fdeaa2dc4 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -89,6 +89,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
goto err;
}
+ priv->max_ib_mtu = ppriv->max_ib_mtu;
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
priv->pkey = pkey;
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 9dea14db724c..5f9d860925a1 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -149,6 +149,15 @@ config INPUT_APMPOWER
To compile this driver as a module, choose M here: the
module will be called apm-power.
+config XEN_KBDDEV_FRONTEND
+ tristate "Xen virtual keyboard and mouse support"
+ depends on XEN_FBDEV_FRONTEND
+ default y
+ help
+ This driver implements the front-end of the Xen virtual
+ keyboard and mouse device driver. It communicates with a back-end
+ in another domain.
+
comment "Input Device Drivers"
source "drivers/input/keyboard/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 2ae87b19caa8..98c4f9a77876 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -23,3 +23,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
+
+obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 490918a5d192..0d3ce7a50fb1 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -73,7 +73,7 @@ static void input_polled_device_work(struct work_struct *work)
static int input_open_polled_device(struct input_dev *input)
{
- struct input_polled_dev *dev = input->private;
+ struct input_polled_dev *dev = input_get_drvdata(input);
int error;
error = input_polldev_start_workqueue();
@@ -91,7 +91,7 @@ static int input_open_polled_device(struct input_dev *input)
static void input_close_polled_device(struct input_dev *input)
{
- struct input_polled_dev *dev = input->private;
+ struct input_polled_dev *dev = input_get_drvdata(input);
cancel_delayed_work_sync(&dev->work);
input_polldev_stop_workqueue();
@@ -151,10 +151,10 @@ int input_register_polled_device(struct input_polled_dev *dev)
{
struct input_dev *input = dev->input;
+ input_set_drvdata(input, dev);
INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
if (!dev->poll_interval)
dev->poll_interval = 500;
- input->private = dev;
input->open = input_open_polled_device;
input->close = input_close_polled_device;
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 7c662ee594a3..be5c14a5a0a4 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -193,6 +193,18 @@ config JOYSTICK_TWIDJOY
To compile this driver as a module, choose M here: the
module will be called twidjoy.
+config JOYSTICK_ZHENHUA
+ tristate "5-byte Zhenhua RC transmitter"
+ select SERIO
+ help
+ Say Y here if you have a Zhen Hua PPM-4CH transmitter which is
+ supplied with a ready to fly micro electric indoor helicopters
+ such as EasyCopter, Lama, MiniCopter, DragonFly or Jabo and want
+ to use it via serial cable as a joystick.
+
+ To compile this driver as a module, choose M here: the
+ module will be called zhenhua.
+
config JOYSTICK_DB9
tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
depends on PARPORT
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index e855abb0cc51..fdbf8c4c2876 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o
obj-$(CONFIG_JOYSTICK_GRIP) += grip.o
obj-$(CONFIG_JOYSTICK_GRIP_MP) += grip_mp.o
obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o
+obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/
obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o
obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o
obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
@@ -27,5 +28,5 @@ obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o
obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o
obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
+obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
-obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 1457b73850e7..7fb3cf81cfbf 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -159,7 +159,7 @@ static int iforce_usb_probe(struct usb_interface *intf,
iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
iforce->cr.wIndex = 0;
- iforce->cr.wLength = 16;
+ iforce->cr.wLength = cpu_to_le16(16);
usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 0380597249bb..b29e3affb805 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -1,5 +1,5 @@
/*
- * X-Box gamepad - v0.0.6
+ * X-Box gamepad driver
*
* Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
* 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
@@ -68,6 +68,8 @@
* - dance pads will map D-PAD to buttons, not axes
* - pass the module paramater 'dpad_to_buttons' to force
* the D-PAD to map to buttons if your pad is not detected
+ *
+ * Later changes can be tracked in SCM.
*/
#include <linux/kernel.h>
@@ -77,7 +79,6 @@
#include <linux/module.h>
#include <linux/usb/input.h>
-#define DRIVER_VERSION "v0.0.6"
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
@@ -87,10 +88,12 @@
but we map them to axes when possible to simplify things */
#define MAP_DPAD_TO_BUTTONS 0
#define MAP_DPAD_TO_AXES 1
-#define MAP_DPAD_UNKNOWN -1
+#define MAP_DPAD_UNKNOWN 2
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
+#define XTYPE_XBOX360W 2
+#define XTYPE_UNKNOWN 3
static int dpad_to_buttons;
module_param(dpad_to_buttons, bool, S_IRUGO);
@@ -107,8 +110,10 @@ static const struct xpad_device {
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
@@ -135,18 +140,26 @@ static const struct xpad_device {
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+ { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
- { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_XBOX }
+ { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
};
-static const signed short xpad_btn[] = {
- BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* "analog" buttons */
+/* buttons shared with xbox and xbox360 */
+static const signed short xpad_common_btn[] = {
+ BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */
BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
-1 /* terminating entry */
};
+/* original xbox controllers only */
+static const signed short xpad_btn[] = {
+ BTN_C, BTN_Z, /* "analog" buttons */
+ -1 /* terminating entry */
+};
+
/* only used if MAP_DPAD_TO_BUTTONS */
static const signed short xpad_btn_pad[] = {
BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
@@ -173,12 +186,27 @@ static const signed short xpad_abs_pad[] = {
-1 /* terminating entry */
};
-/* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only
- * USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols,
- * but we need only one of them. */
+/* Xbox 360 has a vendor-specific class, so we cannot match it with only
+ * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
+ * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
+ * wireless controllers have protocol 129. */
+#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
+ .idVendor = (vend), \
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
+ .bInterfaceSubClass = 93, \
+ .bInterfaceProtocol = (pr)
+#define XPAD_XBOX360_VENDOR(vend) \
+ { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
+ { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
+
static struct usb_device_id xpad_table [] = {
{ USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */
- { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */
+ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */
+ XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */
+ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
+ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
+ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
{ }
};
@@ -188,10 +216,15 @@ struct usb_xpad {
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
+ int pad_present;
+
struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
+ struct urb *bulk_out;
+ unsigned char *bdata;
+
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct urb *irq_out; /* urb for interrupt out report */
unsigned char *odata; /* output data */
@@ -227,13 +260,13 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
input_report_abs(dev, ABS_X,
(__s16) le16_to_cpup((__le16 *)(data + 12)));
input_report_abs(dev, ABS_Y,
- (__s16) le16_to_cpup((__le16 *)(data + 14)));
+ ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
/* right stick */
input_report_abs(dev, ABS_RX,
(__s16) le16_to_cpup((__le16 *)(data + 16)));
input_report_abs(dev, ABS_RY,
- (__s16) le16_to_cpup((__le16 *)(data + 18)));
+ ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[10]);
@@ -321,13 +354,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_report_abs(dev, ABS_X,
(__s16) le16_to_cpup((__le16 *)(data + 6)));
input_report_abs(dev, ABS_Y,
- (__s16) le16_to_cpup((__le16 *)(data + 8)));
+ ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
/* right stick */
input_report_abs(dev, ABS_RX,
(__s16) le16_to_cpup((__le16 *)(data + 10)));
input_report_abs(dev, ABS_RY,
- (__s16) le16_to_cpup((__le16 *)(data + 12)));
+ ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[4]);
@@ -336,12 +369,47 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_sync(dev);
}
+/*
+ * xpad360w_process_packet
+ *
+ * Completes a request by converting the data into events for the
+ * input subsystem. It is version for xbox 360 wireless controller.
+ *
+ * Byte.Bit
+ * 00.1 - Status change: The controller or headset has connected/disconnected
+ * Bits 01.7 and 01.6 are valid
+ * 01.7 - Controller present
+ * 01.6 - Headset present
+ * 01.1 - Pad state (Bytes 4+) valid
+ *
+ */
+
+static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+{
+ /* Presence change */
+ if (data[0] & 0x08) {
+ if (data[1] & 0x80) {
+ xpad->pad_present = 1;
+ usb_submit_urb(xpad->bulk_out, GFP_ATOMIC);
+ } else
+ xpad->pad_present = 0;
+ }
+
+ /* Valid pad data */
+ if (!(data[1] & 0x1))
+ return;
+
+ xpad360_process_packet(xpad, cmd, &data[4]);
+}
+
static void xpad_irq_in(struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
- int retval;
+ int retval, status;
- switch (urb->status) {
+ status = urb->status;
+
+ switch (status) {
case 0:
/* success */
break;
@@ -350,18 +418,24 @@ static void xpad_irq_in(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
- if (xpad->xtype == XTYPE_XBOX360)
+ switch (xpad->xtype) {
+ case XTYPE_XBOX360:
xpad360_process_packet(xpad, 0, xpad->idata);
- else
+ break;
+ case XTYPE_XBOX360W:
+ xpad360w_process_packet(xpad, 0, xpad->idata);
+ break;
+ default:
xpad_process_packet(xpad, 0, xpad->idata);
+ }
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
@@ -370,12 +444,31 @@ exit:
__FUNCTION__, retval);
}
+static void xpad_bulk_out(struct urb *urb)
+{
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ break;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ }
+}
+
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
static void xpad_irq_out(struct urb *urb)
{
- int retval;
+ int retval, status;
- switch (urb->status) {
+ status = urb->status;
+
+ switch (status) {
case 0:
/* success */
break;
@@ -384,11 +477,11 @@ static void xpad_irq_out(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
@@ -408,7 +501,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
return 0;
xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
- GFP_ATOMIC, &xpad->odata_dma );
+ GFP_KERNEL, &xpad->odata_dma);
if (!xpad->odata)
goto fail1;
@@ -469,6 +562,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
xpad->odata[5] = 0x00;
xpad->odata[6] = 0x00;
xpad->odata[7] = 0x00;
+ xpad->irq_out->transfer_buffer_length = 8;
usb_submit_urb(xpad->irq_out, GFP_KERNEL);
}
@@ -477,6 +571,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
static int xpad_init_ff(struct usb_xpad *xpad)
{
+ if (xpad->xtype != XTYPE_XBOX360)
+ return 0;
+
input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
@@ -502,6 +599,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
xpad->odata[0] = 0x01;
xpad->odata[1] = 0x03;
xpad->odata[2] = command;
+ xpad->irq_out->transfer_buffer_length = 3;
usb_submit_urb(xpad->irq_out, GFP_KERNEL);
mutex_unlock(&xpad->odata_mutex);
}
@@ -574,6 +672,10 @@ static int xpad_open(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
+ /* URB was submitted in probe */
+ if(xpad->xtype == XTYPE_XBOX360W)
+ return 0;
+
xpad->irq_in->dev = xpad->udev;
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
return -EIO;
@@ -585,7 +687,8 @@ static void xpad_close(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
- usb_kill_urb(xpad->irq_in);
+ if(xpad->xtype != XTYPE_XBOX360W)
+ usb_kill_urb(xpad->irq_in);
xpad_stop_output(xpad);
}
@@ -632,7 +735,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto fail1;
xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
- GFP_ATOMIC, &xpad->idata_dma);
+ GFP_KERNEL, &xpad->idata_dma);
if (!xpad->idata)
goto fail1;
@@ -644,7 +747,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->dpad_mapping = xpad_device[i].dpad_mapping;
xpad->xtype = xpad_device[i].xtype;
if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
- xpad->dpad_mapping = dpad_to_buttons;
+ xpad->dpad_mapping = !dpad_to_buttons;
+ if (xpad->xtype == XTYPE_UNKNOWN) {
+ if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
+ if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
+ xpad->xtype = XTYPE_XBOX360W;
+ else
+ xpad->xtype = XTYPE_XBOX360;
+ } else
+ xpad->xtype = XTYPE_XBOX;
+ }
xpad->dev = input_dev;
usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -662,11 +774,14 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
/* set up buttons */
- for (i = 0; xpad_btn[i] >= 0; i++)
- set_bit(xpad_btn[i], input_dev->keybit);
- if (xpad->xtype == XTYPE_XBOX360)
+ for (i = 0; xpad_common_btn[i] >= 0; i++)
+ set_bit(xpad_common_btn[i], input_dev->keybit);
+ if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W))
for (i = 0; xpad360_btn[i] >= 0; i++)
set_bit(xpad360_btn[i], input_dev->keybit);
+ else
+ for (i = 0; xpad_btn[i] >= 0; i++)
+ set_bit(xpad_btn[i], input_dev->keybit);
if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
for (i = 0; xpad_btn_pad[i] >= 0; i++)
set_bit(xpad_btn_pad[i], input_dev->keybit);
@@ -703,8 +818,57 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto fail4;
usb_set_intfdata(intf, xpad);
+
+ /*
+ * Submit the int URB immediatly rather than waiting for open
+ * because we get status messages from the device whether
+ * or not any controllers are attached. In fact, it's
+ * exactly the message that a controller has arrived that
+ * we're waiting for.
+ */
+ if (xpad->xtype == XTYPE_XBOX360W) {
+ xpad->irq_in->dev = xpad->udev;
+ error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+ if (error)
+ goto fail4;
+
+ /*
+ * Setup the message to set the LEDs on the
+ * controller when it shows up
+ */
+ xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
+ if(!xpad->bulk_out)
+ goto fail5;
+
+ xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
+ if(!xpad->bdata)
+ goto fail6;
+
+ xpad->bdata[2] = 0x08;
+ switch (intf->cur_altsetting->desc.bInterfaceNumber) {
+ case 0:
+ xpad->bdata[3] = 0x42;
+ break;
+ case 2:
+ xpad->bdata[3] = 0x43;
+ break;
+ case 4:
+ xpad->bdata[3] = 0x44;
+ break;
+ case 6:
+ xpad->bdata[3] = 0x45;
+ }
+
+ ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
+ usb_fill_bulk_urb(xpad->bulk_out, udev,
+ usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
+ xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
+ }
+
return 0;
+ fail6: usb_free_urb(xpad->bulk_out);
+ fail5: usb_kill_urb(xpad->irq_in);
fail4: usb_free_urb(xpad->irq_in);
fail3: xpad_deinit_output(xpad);
fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
@@ -723,6 +887,11 @@ static void xpad_disconnect(struct usb_interface *intf)
xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
xpad_deinit_output(xpad);
+ if (xpad->xtype == XTYPE_XBOX360W) {
+ usb_kill_urb(xpad->bulk_out);
+ usb_free_urb(xpad->bulk_out);
+ usb_kill_urb(xpad->irq_in);
+ }
usb_free_urb(xpad->irq_in);
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
@@ -741,7 +910,7 @@ static int __init usb_xpad_init(void)
{
int result = usb_register(&xpad_driver);
if (result == 0)
- info(DRIVER_DESC ":" DRIVER_VERSION);
+ info(DRIVER_DESC);
return result;
}
diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c
new file mode 100644
index 000000000000..b5853125c898
--- /dev/null
+++ b/drivers/input/joystick/zhenhua.c
@@ -0,0 +1,243 @@
+/*
+ * derived from "twidjoy.c"
+ *
+ * Copyright (c) 2008 Martin Kebert
+ * Copyright (c) 2001 Arndt Schoenewald
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2000 Mark Fletcher
+ *
+ */
+
+/*
+ * Driver to use 4CH RC transmitter using Zhen Hua 5-byte protocol (Walkera Lama,
+ * EasyCopter etc.) as a joystick under Linux.
+ *
+ * RC transmitters using Zhen Hua 5-byte protocol are cheap four channels
+ * transmitters for control a RC planes or RC helicopters with possibility to
+ * connect on a serial port.
+ * Data coming from transmitter is in this order:
+ * 1. byte = synchronisation byte
+ * 2. byte = X axis
+ * 3. byte = Y axis
+ * 4. byte = RZ axis
+ * 5. byte = Z axis
+ * (and this is repeated)
+ *
+ * For questions or feedback regarding this driver module please contact:
+ * Martin Kebert <gkmarty@gmail.com> - but I am not a C-programmer nor kernel
+ * coder :-(
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "RC transmitter with 5-byte Zhen Hua protocol joystick driver"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Constants.
+ */
+
+#define ZHENHUA_MAX_LENGTH 5
+
+/*
+ * Zhen Hua data.
+ */
+
+struct zhenhua {
+ struct input_dev *dev;
+ int idx;
+ unsigned char data[ZHENHUA_MAX_LENGTH];
+ char phys[32];
+};
+
+
+/* bits in all incoming bytes needs to be "reversed" */
+static int zhenhua_bitreverse(int x)
+{
+ x = ((x & 0xaa) >> 1) | ((x & 0x55) << 1);
+ x = ((x & 0xcc) >> 2) | ((x & 0x33) << 2);
+ x = ((x & 0xf0) >> 4) | ((x & 0x0f) << 4);
+ return x;
+}
+
+/*
+ * zhenhua_process_packet() decodes packets the driver receives from the
+ * RC transmitter. It updates the data accordingly.
+ */
+
+static void zhenhua_process_packet(struct zhenhua *zhenhua)
+{
+ struct input_dev *dev = zhenhua->dev;
+ unsigned char *data = zhenhua->data;
+
+ input_report_abs(dev, ABS_Y, data[1]);
+ input_report_abs(dev, ABS_X, data[2]);
+ input_report_abs(dev, ABS_RZ, data[3]);
+ input_report_abs(dev, ABS_Z, data[4]);
+
+ input_sync(dev);
+}
+
+/*
+ * zhenhua_interrupt() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static irqreturn_t zhenhua_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct zhenhua *zhenhua = serio_get_drvdata(serio);
+
+ /* All Zhen Hua packets are 5 bytes. The fact that the first byte
+ * is allways 0xf7 and all others are in range 0x32 - 0xc8 (50-200)
+ * can be used to check and regain sync. */
+
+ if (data == 0xef)
+ zhenhua->idx = 0; /* this byte starts a new packet */
+ else if (zhenhua->idx == 0)
+ return IRQ_HANDLED; /* wrong MSB -- ignore this byte */
+
+ if (zhenhua->idx < ZHENHUA_MAX_LENGTH)
+ zhenhua->data[zhenhua->idx++] = zhenhua_bitreverse(data);
+
+ if (zhenhua->idx == ZHENHUA_MAX_LENGTH) {
+ zhenhua_process_packet(zhenhua);
+ zhenhua->idx = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * zhenhua_disconnect() is the opposite of zhenhua_connect()
+ */
+
+static void zhenhua_disconnect(struct serio *serio)
+{
+ struct zhenhua *zhenhua = serio_get_drvdata(serio);
+
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_unregister_device(zhenhua->dev);
+ kfree(zhenhua);
+}
+
+/*
+ * zhenhua_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Twiddler, and if found, registers
+ * it as an input device.
+ */
+
+static int zhenhua_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct zhenhua *zhenhua;
+ struct input_dev *input_dev;
+ int err = -ENOMEM;
+
+ zhenhua = kzalloc(sizeof(struct zhenhua), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!zhenhua || !input_dev)
+ goto fail1;
+
+ zhenhua->dev = input_dev;
+ snprintf(zhenhua->phys, sizeof(zhenhua->phys), "%s/input0", serio->phys);
+
+ input_dev->name = "Zhen Hua 5-byte device";
+ input_dev->phys = zhenhua->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_ZHENHUA;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
+
+ input_dev->evbit[0] = BIT(EV_ABS);
+ input_set_abs_params(input_dev, ABS_X, 50, 200, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 50, 200, 0, 0);
+ input_set_abs_params(input_dev, ABS_Z, 50, 200, 0, 0);
+ input_set_abs_params(input_dev, ABS_RZ, 50, 200, 0, 0);
+
+ serio_set_drvdata(serio, zhenhua);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(zhenhua->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(zhenhua);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id zhenhua_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_ZHENHUA,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, zhenhua_serio_ids);
+
+static struct serio_driver zhenhua_drv = {
+ .driver = {
+ .name = "zhenhua",
+ },
+ .description = DRIVER_DESC,
+ .id_table = zhenhua_serio_ids,
+ .interrupt = zhenhua_interrupt,
+ .connect = zhenhua_connect,
+ .disconnect = zhenhua_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init zhenhua_init(void)
+{
+ return serio_register_driver(&zhenhua_drv);
+}
+
+static void __exit zhenhua_exit(void)
+{
+ serio_unregister_driver(&zhenhua_drv);
+}
+
+module_init(zhenhua_init);
+module_exit(zhenhua_exit);
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
index 72abc196ce66..a293e8b3f508 100644
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ b/drivers/input/keyboard/aaed2000_kbd.c
@@ -156,11 +156,15 @@ static int __devexit aaedkbd_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:aaed2000-keyboard");
+
static struct platform_driver aaedkbd_driver = {
.probe = aaedkbd_probe,
.remove = __devexit_p(aaedkbd_remove),
.driver = {
.name = "aaed2000-keyboard",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index 05e3494cf8b8..54ed8e2e1c02 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -312,6 +312,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN);
+ device_init_wakeup(&pdev->dev, 1);
+
printk(KERN_ERR DRV_NAME
": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
@@ -354,12 +356,40 @@ static int __devexit bfin_kpad_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int bfin_kpad_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(bf54x_kpad->irq);
+
+ return 0;
+}
+
+static int bfin_kpad_resume(struct platform_device *pdev)
+{
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(bf54x_kpad->irq);
+
+ return 0;
+}
+#else
+# define bfin_kpad_suspend NULL
+# define bfin_kpad_resume NULL
+#endif
+
struct platform_driver bfin_kpad_device_driver = {
- .probe = bfin_kpad_probe,
- .remove = __devexit_p(bfin_kpad_remove),
.driver = {
.name = DRV_NAME,
- }
+ .owner = THIS_MODULE,
+ },
+ .probe = bfin_kpad_probe,
+ .remove = __devexit_p(bfin_kpad_remove),
+ .suspend = bfin_kpad_suspend,
+ .resume = bfin_kpad_resume,
};
static int __init bfin_kpad_init(void)
@@ -378,3 +408,4 @@ module_exit(bfin_kpad_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Keypad driver for BF54x Processors");
+MODULE_ALIAS("platform:bf54x-keys");
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 5d6cc7f1dc94..29fbec6218b9 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -393,6 +393,7 @@ static struct platform_driver corgikbd_driver = {
.resume = corgikbd_resume,
.driver = {
.name = "corgi-keyboard",
+ .owner = THIS_MODULE,
},
};
@@ -412,3 +413,4 @@ module_exit(corgikbd_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Corgi Keyboard Driver");
MODULE_LICENSE("GPLv2");
+MODULE_ALIAS("platform:corgi-keyboard");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 6a9ca4bdcb74..bbd00c3fe98c 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -43,10 +43,11 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
input_event(input, type, button->code, !!state);
input_sync(input);
+ return IRQ_HANDLED;
}
}
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
static int __devinit gpio_keys_probe(struct platform_device *pdev)
@@ -213,6 +214,7 @@ struct platform_driver gpio_keys_device_driver = {
.resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
+ .owner = THIS_MODULE,
}
};
@@ -232,3 +234,4 @@ module_exit(gpio_keys_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
+MODULE_ALIAS("platform:gpio-keys");
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
index a23633a2e1b4..9387da343f97 100644
--- a/drivers/input/keyboard/jornada680_kbd.c
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -254,6 +254,7 @@ static int __devexit jornada680kbd_remove(struct platform_device *pdev)
static struct platform_driver jornada680kbd_driver = {
.driver = {
.name = "jornada680_kbd",
+ .owner = THIS_MODULE,
},
.probe = jornada680kbd_probe,
.remove = __devexit_p(jornada680kbd_remove),
@@ -275,3 +276,4 @@ module_exit(jornada680kbd_exit);
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
MODULE_LICENSE("GPLv2");
+MODULE_ALIAS("platform:jornada680_kbd");
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index 986f93cfc6b8..a1164a0c7736 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -162,9 +162,13 @@ static int __devexit jornada720_kbd_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:jornada720_kbd");
+
static struct platform_driver jornada720_kbd_driver = {
.driver = {
.name = "jornada720_kbd",
+ .owner = THIS_MODULE,
},
.probe = jornada720_kbd_probe,
.remove = __devexit_p(jornada720_kbd_remove),
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 5a0ca18d6755..9caed30f3bbb 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -1,14 +1,12 @@
/*
- * Copyright (c) 2005 John Lenz
+ * LoCoMo keyboard driver for Linux-based ARM PDAs:
+ * - SHARP Zaurus Collie (SL-5500)
+ * - SHARP Zaurus Poodle (SL-5600)
*
+ * Copyright (c) 2005 John Lenz
* Based on from xtkbd.c
- */
-
-/*
- * LoCoMo keyboard driver for Linux/ARM
- */
-
-/*
+ *
+ *
* 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
@@ -47,7 +45,8 @@ MODULE_LICENSE("GPL");
#define KEY_CONTACT KEY_F18
#define KEY_CENTER KEY_F15
-static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
+static const unsigned char
+locomokbd_keycode[LOCOMOKBD_NUMKEYS] __devinitconst = {
0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */
0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */
@@ -67,22 +66,21 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
#define KB_COLS 8
#define KB_ROWMASK(r) (1 << (r))
#define SCANCODE(c,r) ( ((c)<<4) + (r) + 1 )
-#define NR_SCANCODES 128
#define KB_DELAY 8
#define SCAN_INTERVAL (HZ/10)
-#define LOCOMOKBD_PRESSED 1
struct locomokbd {
unsigned char keycode[LOCOMOKBD_NUMKEYS];
struct input_dev *input;
char phys[32];
- struct locomo_dev *ldev;
unsigned long base;
spinlock_t lock;
struct timer_list timer;
+ unsigned long suspend_jiffies;
+ unsigned int count_cancel;
};
/* helper functions for reading the keyboard matrix */
@@ -128,7 +126,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
/* Scan the hardware keyboard and push any changes up through the input layer */
static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
{
- unsigned int row, col, rowd, scancode;
+ unsigned int row, col, rowd;
unsigned long flags;
unsigned int num_pressed;
unsigned long membase = locomokbd->base;
@@ -145,13 +143,33 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
rowd = ~locomo_readl(membase + LOCOMO_KIB);
for (row = 0; row < KB_ROWS; row++) {
+ unsigned int scancode, pressed, key;
+
scancode = SCANCODE(col, row);
- if (rowd & KB_ROWMASK(row)) {
- num_pressed += 1;
- input_report_key(locomokbd->input, locomokbd->keycode[scancode], 1);
- } else {
- input_report_key(locomokbd->input, locomokbd->keycode[scancode], 0);
- }
+ pressed = rowd & KB_ROWMASK(row);
+ key = locomokbd->keycode[scancode];
+
+ input_report_key(locomokbd->input, key, pressed);
+ if (likely(!pressed))
+ continue;
+
+ num_pressed++;
+
+ /* The "Cancel/ESC" key is labeled "On/Off" on
+ * Collie and Poodle and should suspend the device
+ * if it was pressed for more than a second. */
+ if (unlikely(key == KEY_ESC)) {
+ if (!time_after(jiffies,
+ locomokbd->suspend_jiffies + HZ))
+ continue;
+ if (locomokbd->count_cancel++
+ != (HZ/SCAN_INTERVAL + 1))
+ continue;
+ input_event(locomokbd->input, EV_PWR,
+ KEY_SUSPEND, 1);
+ locomokbd->suspend_jiffies = jiffies;
+ } else
+ locomokbd->count_cancel = 0;
}
locomokbd_reset_col(membase, col);
}
@@ -162,6 +180,8 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
/* if any keys are pressed, enable the timer */
if (num_pressed)
mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
+ else
+ locomokbd->count_cancel = 0;
spin_unlock_irqrestore(&locomokbd->lock, flags);
}
@@ -186,10 +206,11 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
static void locomokbd_timer_callback(unsigned long data)
{
struct locomokbd *locomokbd = (struct locomokbd *) data;
+
locomokbd_scankeyboard(locomokbd);
}
-static int locomokbd_probe(struct locomo_dev *dev)
+static int __devinit locomokbd_probe(struct locomo_dev *dev)
{
struct locomokbd *locomokbd;
struct input_dev *input_dev;
@@ -211,7 +232,6 @@ static int locomokbd_probe(struct locomo_dev *dev)
goto err_free_mem;
}
- locomokbd->ldev = dev;
locomo_set_drvdata(dev, locomokbd);
locomokbd->base = (unsigned long) dev->mapbase;
@@ -222,6 +242,8 @@ static int locomokbd_probe(struct locomo_dev *dev)
locomokbd->timer.function = locomokbd_timer_callback;
locomokbd->timer.data = (unsigned long) locomokbd;
+ locomokbd->suspend_jiffies = jiffies;
+
locomokbd->input = input_dev;
strcpy(locomokbd->phys, "locomokbd/input0");
@@ -233,9 +255,10 @@ static int locomokbd_probe(struct locomo_dev *dev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &dev->dev;
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_PWR);
input_dev->keycode = locomokbd->keycode;
- input_dev->keycodesize = sizeof(unsigned char);
+ input_dev->keycodesize = sizeof(locomokbd_keycode[0]);
input_dev->keycodemax = ARRAY_SIZE(locomokbd_keycode);
memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
@@ -268,7 +291,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
return err;
}
-static int locomokbd_remove(struct locomo_dev *dev)
+static int __devexit locomokbd_remove(struct locomo_dev *dev)
{
struct locomokbd *locomokbd = locomo_get_drvdata(dev);
@@ -292,7 +315,7 @@ static struct locomo_driver keyboard_driver = {
},
.devid = LOCOMO_DEVID_KEYBOARD,
.probe = locomokbd_probe,
- .remove = locomokbd_remove,
+ .remove = __devexit_p(locomokbd_remove),
};
static int __init locomokbd_init(void)
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index babc913d5492..10afd2068068 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -352,6 +352,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
}
omap_set_gpio_direction(row_gpios[row_idx], 1);
}
+ } else {
+ col_idx = 0;
+ row_idx = 0;
}
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
@@ -415,10 +418,10 @@ err4:
err3:
device_remove_file(&pdev->dev, &dev_attr_enable);
err2:
- for (i = row_idx-1; i >=0; i--)
+ for (i = row_idx - 1; i >=0; i--)
omap_free_gpio(row_gpios[i]);
err1:
- for (i = col_idx-1; i >=0; i--)
+ for (i = col_idx - 1; i >=0; i--)
omap_free_gpio(col_gpios[i]);
kfree(omap_kp);
@@ -464,6 +467,7 @@ static struct platform_driver omap_kp_driver = {
.resume = omap_kp_resume,
.driver = {
.name = "omap-keypad",
+ .owner = THIS_MODULE,
},
};
@@ -484,3 +488,4 @@ module_exit(omap_kp_exit);
MODULE_AUTHOR("Timo Teräs");
MODULE_DESCRIPTION("OMAP Keypad Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-keypad");
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 4e651c11c1da..3dea0c5077a9 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -545,6 +545,9 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:pxa27x-keypad");
+
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = __devexit_p(pxa27x_keypad_remove),
@@ -552,6 +555,7 @@ static struct platform_driver pxa27x_keypad_driver = {
.resume = pxa27x_keypad_resume,
.driver = {
.name = "pxa27x-keypad",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 0be74bfc58fe..61e401bc9109 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -495,3 +495,4 @@ module_exit(spitzkbd_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Spitz Keyboard Driver");
MODULE_LICENSE("GPLv2");
+MODULE_ALIAS("platform:spitz-keyboard");
diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c
index 3884d1e3f070..94e444b4ee15 100644
--- a/drivers/input/keyboard/tosakbd.c
+++ b/drivers/input/keyboard/tosakbd.c
@@ -52,7 +52,7 @@ KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_
struct tosakbd {
unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)];
struct input_dev *input;
-
+ int suspended;
spinlock_t lock; /* protect kbd scanning */
struct timer_list timer;
};
@@ -133,6 +133,9 @@ static void tosakbd_scankeyboard(struct platform_device *dev)
spin_lock_irqsave(&tosakbd->lock, flags);
+ if (tosakbd->suspended)
+ goto out;
+
for (col = 0; col < TOSA_KEY_STROBE_NUM; col++) {
/*
* Discharge the output driver capacitatance
@@ -174,6 +177,7 @@ static void tosakbd_scankeyboard(struct platform_device *dev)
if (num_pressed)
mod_timer(&tosakbd->timer, jiffies + SCAN_INTERVAL);
+ out:
spin_unlock_irqrestore(&tosakbd->lock, flags);
}
@@ -200,6 +204,7 @@ static irqreturn_t tosakbd_interrupt(int irq, void *__dev)
static void tosakbd_timer_callback(unsigned long __dev)
{
struct platform_device *dev = (struct platform_device *)__dev;
+
tosakbd_scankeyboard(dev);
}
@@ -207,6 +212,13 @@ static void tosakbd_timer_callback(unsigned long __dev)
static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
{
struct tosakbd *tosakbd = platform_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tosakbd->lock, flags);
+ PGSR1 = (PGSR1 & ~TOSA_GPIO_LOW_STROBE_BIT);
+ PGSR2 = (PGSR2 & ~TOSA_GPIO_HIGH_STROBE_BIT);
+ tosakbd->suspended = 1;
+ spin_unlock_irqrestore(&tosakbd->lock, flags);
del_timer_sync(&tosakbd->timer);
@@ -215,6 +227,9 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
static int tosakbd_resume(struct platform_device *dev)
{
+ struct tosakbd *tosakbd = platform_get_drvdata(dev);
+
+ tosakbd->suspended = 0;
tosakbd_scankeyboard(dev);
return 0;
@@ -365,8 +380,8 @@ fail:
return error;
}
-static int __devexit tosakbd_remove(struct platform_device *dev) {
-
+static int __devexit tosakbd_remove(struct platform_device *dev)
+{
int i;
struct tosakbd *tosakbd = platform_get_drvdata(dev);
@@ -394,6 +409,7 @@ static struct platform_driver tosakbd_driver = {
.resume = tosakbd_resume,
.driver = {
.name = "tosa-keyboard",
+ .owner = THIS_MODULE,
},
};
@@ -413,3 +429,4 @@ module_exit(tosakbd_exit);
MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
MODULE_DESCRIPTION("Tosa Keyboard Driver");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tosa-keyboard");
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
index 5511ef006a66..6a1f48b76e32 100644
--- a/drivers/input/misc/cobalt_btns.c
+++ b/drivers/input/misc/cobalt_btns.c
@@ -148,6 +148,9 @@ static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:Cobalt buttons");
+
static struct platform_driver cobalt_buttons_driver = {
.probe = cobalt_buttons_probe,
.remove = __devexit_p(cobalt_buttons_remove),
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index fed3c375ccf3..d8765cc93d27 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -2,33 +2,69 @@
* Driver for PC-speaker like devices found on various Sparc systems.
*
* Copyright (c) 2002 Vojtech Pavlik
- * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
-#include <linux/platform_device.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/isa.h>
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
MODULE_LICENSE("GPL");
+struct grover_beep_info {
+ void __iomem *freq_regs;
+ void __iomem *enable_reg;
+};
+
+struct bbc_beep_info {
+ u32 clock_freq;
+ void __iomem *regs;
+};
+
struct sparcspkr_state {
const char *name;
- unsigned long iobase;
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
spinlock_t lock;
struct input_dev *input_dev;
+ union {
+ struct grover_beep_info grover;
+ struct bbc_beep_info bbc;
+ } u;
};
-static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
+{
+ u32 val, clock_freq = info->clock_freq;
+ int i;
+
+ if (!count)
+ return 0;
+
+ if (count <= clock_freq >> 20)
+ return 1 << 18;
+
+ if (count >= clock_freq >> 12)
+ return 1 << 10;
+
+ val = 1 << 18;
+ for (i = 19; i >= 11; i--) {
+ val >>= 1;
+ if (count <= clock_freq >> i)
+ break;
+ }
+
+ return val;
+}
+
+static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
+ struct bbc_beep_info *info = &state->u.bbc;
unsigned int count = 0;
unsigned long flags;
@@ -44,24 +80,29 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
if (value > 20 && value < 32767)
count = 1193182 / value;
+ count = bbc_count_to_reg(info, count);
+
spin_lock_irqsave(&state->lock, flags);
- /* EBUS speaker only has on/off state, the frequency does not
- * appear to be programmable.
- */
- if (state->iobase & 0x2UL)
- outb(!!count, state->iobase);
- else
- outl(!!count, state->iobase);
+ if (count) {
+ outb(0x01, info->regs + 0);
+ outb(0x00, info->regs + 2);
+ outb((count >> 16) & 0xff, info->regs + 3);
+ outb((count >> 8) & 0xff, info->regs + 4);
+ outb(0x00, info->regs + 5);
+ } else {
+ outb(0x00, info->regs + 0);
+ }
spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
-static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
+ struct grover_beep_info *info = &state->u.grover;
unsigned int count = 0;
unsigned long flags;
@@ -81,15 +122,15 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
if (count) {
/* enable counter 2 */
- outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61);
+ outb(inb(info->enable_reg) | 3, info->enable_reg);
/* set command for counter 2, 2 byte write */
- outb(0xB6, state->iobase + 0x43);
+ outb(0xB6, info->freq_regs + 1);
/* select desired HZ */
- outb(count & 0xff, state->iobase + 0x42);
- outb((count >> 8) & 0xff, state->iobase + 0x42);
+ outb(count & 0xff, info->freq_regs + 0);
+ outb((count >> 8) & 0xff, info->freq_regs + 0);
} else {
/* disable counter 2 */
- outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61);
+ outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg);
}
spin_unlock_irqrestore(&state->lock, flags);
@@ -131,7 +172,7 @@ static int __devinit sparcspkr_probe(struct device *dev)
return 0;
}
-static int __devexit sparcspkr_remove(struct of_device *dev)
+static int sparcspkr_shutdown(struct of_device *dev)
{
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
struct input_dev *input_dev = state->input_dev;
@@ -139,115 +180,180 @@ static int __devexit sparcspkr_remove(struct of_device *dev)
/* turn off the speaker */
state->event(input_dev, EV_SND, SND_BELL, 0);
- input_unregister_device(input_dev);
-
- dev_set_drvdata(&dev->dev, NULL);
- kfree(state);
-
return 0;
}
-static int sparcspkr_shutdown(struct of_device *dev)
+static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
- struct input_dev *input_dev = state->input_dev;
+ struct sparcspkr_state *state;
+ struct bbc_beep_info *info;
+ struct device_node *dp;
+ int err = -ENOMEM;
- /* turn off the speaker */
- state->event(input_dev, EV_SND, SND_BELL, 0);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ goto out_err;
+
+ state->name = "Sparc BBC Speaker";
+ state->event = bbc_spkr_event;
+ spin_lock_init(&state->lock);
+
+ dp = of_find_node_by_path("/");
+ err = -ENODEV;
+ if (!dp)
+ goto out_free;
+
+ info = &state->u.bbc;
+ info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
+ if (!info->clock_freq)
+ goto out_free;
+
+ info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
+ if (!info->regs)
+ goto out_free;
+
+ dev_set_drvdata(&op->dev, state);
+
+ err = sparcspkr_probe(&op->dev);
+ if (err)
+ goto out_clear_drvdata;
return 0;
+
+out_clear_drvdata:
+ dev_set_drvdata(&op->dev, NULL);
+ of_iounmap(&op->resource[0], info->regs, 6);
+
+out_free:
+ kfree(state);
+out_err:
+ return err;
}
-static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match)
+static int bbc_remove(struct of_device *op)
{
- struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
- struct sparcspkr_state *state;
- int err;
+ struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
+ struct input_dev *input_dev = state->input_dev;
+ struct bbc_beep_info *info = &state->u.bbc;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
+ /* turn off the speaker */
+ state->event(input_dev, EV_SND, SND_BELL, 0);
- state->name = "Sparc EBUS Speaker";
- state->iobase = edev->resource[0].start;
- state->event = ebus_spkr_event;
- spin_lock_init(&state->lock);
+ input_unregister_device(input_dev);
- dev_set_drvdata(&dev->dev, state);
+ of_iounmap(&op->resource[0], info->regs, 6);
- err = sparcspkr_probe(&dev->dev);
- if (err) {
- dev_set_drvdata(&dev->dev, NULL);
- kfree(state);
- }
+ dev_set_drvdata(&op->dev, NULL);
+ kfree(state);
return 0;
}
-static struct of_device_id ebus_beep_match[] = {
+static struct of_device_id bbc_beep_match[] = {
{
.name = "beep",
+ .compatible = "SUNW,bbc-beep",
},
{},
};
-static struct of_platform_driver ebus_beep_driver = {
- .name = "beep",
- .match_table = ebus_beep_match,
- .probe = ebus_beep_probe,
- .remove = __devexit_p(sparcspkr_remove),
+static struct of_platform_driver bbc_beep_driver = {
+ .name = "bbcbeep",
+ .match_table = bbc_beep_match,
+ .probe = bbc_beep_probe,
+ .remove = __devexit_p(bbc_remove),
.shutdown = sparcspkr_shutdown,
};
-static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sparc_isa_device *idev = to_isa_device(&dev->dev);
struct sparcspkr_state *state;
- int err;
+ struct grover_beep_info *info;
+ int err = -ENOMEM;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
- return -ENOMEM;
+ goto out_err;
- state->name = "Sparc ISA Speaker";
- state->iobase = idev->resource.start;
- state->event = isa_spkr_event;
+ state->name = "Sparc Grover Speaker";
+ state->event = grover_spkr_event;
spin_lock_init(&state->lock);
- dev_set_drvdata(&dev->dev, state);
+ info = &state->u.grover;
+ info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
+ if (!info->freq_regs)
+ goto out_free;
- err = sparcspkr_probe(&dev->dev);
- if (err) {
- dev_set_drvdata(&dev->dev, NULL);
- kfree(state);
- }
+ info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
+ if (!info->enable_reg)
+ goto out_unmap_freq_regs;
+
+ dev_set_drvdata(&op->dev, state);
+
+ err = sparcspkr_probe(&op->dev);
+ if (err)
+ goto out_clear_drvdata;
+
+ return 0;
+
+out_clear_drvdata:
+ dev_set_drvdata(&op->dev, NULL);
+ of_iounmap(&op->resource[3], info->enable_reg, 1);
+
+out_unmap_freq_regs:
+ of_iounmap(&op->resource[2], info->freq_regs, 2);
+out_free:
+ kfree(state);
+out_err:
+ return err;
+}
+
+static int grover_remove(struct of_device *op)
+{
+ struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
+ struct grover_beep_info *info = &state->u.grover;
+ struct input_dev *input_dev = state->input_dev;
+
+ /* turn off the speaker */
+ state->event(input_dev, EV_SND, SND_BELL, 0);
+
+ input_unregister_device(input_dev);
+
+ of_iounmap(&op->resource[3], info->enable_reg, 1);
+ of_iounmap(&op->resource[2], info->freq_regs, 2);
+
+ dev_set_drvdata(&op->dev, NULL);
+ kfree(state);
return 0;
}
-static struct of_device_id isa_beep_match[] = {
+static struct of_device_id grover_beep_match[] = {
{
- .name = "dma",
+ .name = "beep",
+ .compatible = "SUNW,smbus-beep",
},
{},
};
-static struct of_platform_driver isa_beep_driver = {
- .name = "beep",
- .match_table = isa_beep_match,
- .probe = isa_beep_probe,
- .remove = __devexit_p(sparcspkr_remove),
+static struct of_platform_driver grover_beep_driver = {
+ .name = "groverbeep",
+ .match_table = grover_beep_match,
+ .probe = grover_beep_probe,
+ .remove = __devexit_p(grover_remove),
.shutdown = sparcspkr_shutdown,
};
static int __init sparcspkr_init(void)
{
- int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type);
+ int err = of_register_driver(&bbc_beep_driver,
+ &of_platform_bus_type);
if (!err) {
- err = of_register_driver(&isa_beep_driver, &isa_bus_type);
+ err = of_register_driver(&grover_beep_driver,
+ &of_platform_bus_type);
if (err)
- of_unregister_driver(&ebus_beep_driver);
+ of_unregister_driver(&bbc_beep_driver);
}
return err;
@@ -255,8 +361,8 @@ static int __init sparcspkr_init(void)
static void __exit sparcspkr_exit(void)
{
- of_unregister_driver(&ebus_beep_driver);
- of_unregister_driver(&isa_beep_driver);
+ of_unregister_driver(&bbc_beep_driver);
+ of_unregister_driver(&grover_beep_driver);
}
module_init(sparcspkr_init);
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
index 0936d6ba015c..339290184871 100644
--- a/drivers/input/mouse/gpio_mouse.c
+++ b/drivers/input/mouse/gpio_mouse.c
@@ -171,10 +171,14 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:gpio_mouse");
+
struct platform_driver gpio_mouse_device_driver = {
.remove = __devexit_p(gpio_mouse_remove),
.driver = {
.name = "gpio_mouse",
+ .owner = THIS_MODULE,
}
};
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index b88569e21d60..ec4b6610f730 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -88,6 +88,16 @@ config SERIO_RPCKBD
To compile this driver as a module, choose M here: the
module will be called rpckbd.
+config SERIO_AT32PSIF
+ tristate "AVR32 PSIF PS/2 keyboard and mouse controller"
+ depends on AVR32
+ help
+ Say Y here if you want to use the PSIF peripheral on AVR32 devices
+ and connect a PS/2 keyboard and/or mouse to it.
+
+ To compile this driver as a module, choose M here: the module will
+ be called at32psif.
+
config SERIO_AMBAKMI
tristate "AMBA KMI keyboard controller"
depends on ARM_AMBA
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 4155197867a3..38b886887cbc 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o
+obj-$(CONFIG_SERIO_AT32PSIF) += at32psif.o
obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_HP_SDC) += hp_sdc.o
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c
new file mode 100644
index 000000000000..41fda8c67b1e
--- /dev/null
+++ b/drivers/input/serio/at32psif.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * Driver for the AT32AP700X PS/2 controller (PSIF).
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/* PSIF register offsets */
+#define PSIF_CR 0x00
+#define PSIF_RHR 0x04
+#define PSIF_THR 0x08
+#define PSIF_SR 0x10
+#define PSIF_IER 0x14
+#define PSIF_IDR 0x18
+#define PSIF_IMR 0x1c
+#define PSIF_PSR 0x24
+
+/* Bitfields in control register. */
+#define PSIF_CR_RXDIS_OFFSET 1
+#define PSIF_CR_RXDIS_SIZE 1
+#define PSIF_CR_RXEN_OFFSET 0
+#define PSIF_CR_RXEN_SIZE 1
+#define PSIF_CR_SWRST_OFFSET 15
+#define PSIF_CR_SWRST_SIZE 1
+#define PSIF_CR_TXDIS_OFFSET 9
+#define PSIF_CR_TXDIS_SIZE 1
+#define PSIF_CR_TXEN_OFFSET 8
+#define PSIF_CR_TXEN_SIZE 1
+
+/* Bitfields in interrupt disable, enable, mask and status register. */
+#define PSIF_NACK_OFFSET 8
+#define PSIF_NACK_SIZE 1
+#define PSIF_OVRUN_OFFSET 5
+#define PSIF_OVRUN_SIZE 1
+#define PSIF_PARITY_OFFSET 9
+#define PSIF_PARITY_SIZE 1
+#define PSIF_RXRDY_OFFSET 4
+#define PSIF_RXRDY_SIZE 1
+#define PSIF_TXEMPTY_OFFSET 1
+#define PSIF_TXEMPTY_SIZE 1
+#define PSIF_TXRDY_OFFSET 0
+#define PSIF_TXRDY_SIZE 1
+
+/* Bitfields in prescale register. */
+#define PSIF_PSR_PRSCV_OFFSET 0
+#define PSIF_PSR_PRSCV_SIZE 12
+
+/* Bitfields in receive hold register. */
+#define PSIF_RHR_RXDATA_OFFSET 0
+#define PSIF_RHR_RXDATA_SIZE 8
+
+/* Bitfields in transmit hold register. */
+#define PSIF_THR_TXDATA_OFFSET 0
+#define PSIF_THR_TXDATA_SIZE 8
+
+/* Bit manipulation macros */
+#define PSIF_BIT(name) \
+ (1 << PSIF_##name##_OFFSET)
+
+#define PSIF_BF(name, value) \
+ (((value) & ((1 << PSIF_##name##_SIZE) - 1)) \
+ << PSIF_##name##_OFFSET)
+
+#define PSIF_BFEXT(name, value) \
+ (((value) >> PSIF_##name##_OFFSET) \
+ & ((1 << PSIF_##name##_SIZE) - 1))
+
+#define PSIF_BFINS(name, value, old) \
+ (((old) & ~(((1 << PSIF_##name##_SIZE) - 1) \
+ << PSIF_##name##_OFFSET)) \
+ | PSIF_BF(name, value))
+
+/* Register access macros */
+#define psif_readl(port, reg) \
+ __raw_readl((port)->regs + PSIF_##reg)
+
+#define psif_writel(port, reg, value) \
+ __raw_writel((value), (port)->regs + PSIF_##reg)
+
+struct psif {
+ struct platform_device *pdev;
+ struct clk *pclk;
+ struct serio *io;
+ void __iomem *regs;
+ unsigned int irq;
+ unsigned int open;
+ /* Prevent concurrent writes to PSIF THR. */
+ spinlock_t lock;
+};
+
+static irqreturn_t psif_interrupt(int irq, void *_ptr)
+{
+ struct psif *psif = _ptr;
+ int retval = IRQ_NONE;
+ unsigned int io_flags = 0;
+ unsigned long status;
+
+ status = psif_readl(psif, SR);
+
+ if (status & PSIF_BIT(RXRDY)) {
+ unsigned char val = (unsigned char) psif_readl(psif, RHR);
+
+ if (status & PSIF_BIT(PARITY))
+ io_flags |= SERIO_PARITY;
+ if (status & PSIF_BIT(OVRUN))
+ dev_err(&psif->pdev->dev, "overrun read error\n");
+
+ serio_interrupt(psif->io, val, io_flags);
+
+ retval = IRQ_HANDLED;
+ }
+
+ return retval;
+}
+
+static int psif_write(struct serio *io, unsigned char val)
+{
+ struct psif *psif = io->port_data;
+ unsigned long flags;
+ int timeout = 10;
+ int retval = 0;
+
+ spin_lock_irqsave(&psif->lock, flags);
+
+ while (!(psif_readl(psif, SR) & PSIF_BIT(TXEMPTY)) && timeout--)
+ msleep(10);
+
+ if (timeout >= 0) {
+ psif_writel(psif, THR, val);
+ } else {
+ dev_dbg(&psif->pdev->dev, "timeout writing to THR\n");
+ retval = -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&psif->lock, flags);
+
+ return retval;
+}
+
+static int psif_open(struct serio *io)
+{
+ struct psif *psif = io->port_data;
+ int retval;
+
+ retval = clk_enable(psif->pclk);
+ if (retval)
+ goto out;
+
+ psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
+ psif_writel(psif, IER, PSIF_BIT(RXRDY));
+
+ psif->open = 1;
+out:
+ return retval;
+}
+
+static void psif_close(struct serio *io)
+{
+ struct psif *psif = io->port_data;
+
+ psif->open = 0;
+
+ psif_writel(psif, IDR, ~0UL);
+ psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
+
+ clk_disable(psif->pclk);
+}
+
+static void psif_set_prescaler(struct psif *psif)
+{
+ unsigned long prscv;
+ unsigned long rate = clk_get_rate(psif->pclk);
+
+ /* PRSCV = Pulse length (100 us) * PSIF module frequency. */
+ prscv = 100 * (rate / 1000000UL);
+
+ if (prscv > ((1<<PSIF_PSR_PRSCV_SIZE) - 1)) {
+ prscv = (1<<PSIF_PSR_PRSCV_SIZE) - 1;
+ dev_dbg(&psif->pdev->dev, "pclk too fast, "
+ "prescaler set to max\n");
+ }
+
+ clk_enable(psif->pclk);
+ psif_writel(psif, PSR, prscv);
+ clk_disable(psif->pclk);
+}
+
+static int __init psif_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct psif *psif;
+ struct serio *io;
+ struct clk *pclk;
+ int irq;
+ int ret;
+
+ psif = kzalloc(sizeof(struct psif), GFP_KERNEL);
+ if (!psif) {
+ dev_dbg(&pdev->dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ psif->pdev = pdev;
+
+ io = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!io) {
+ dev_dbg(&pdev->dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto out_free_psif;
+ }
+ psif->io = io;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_dbg(&pdev->dev, "no mmio resources defined\n");
+ ret = -ENOMEM;
+ goto out_free_io;
+ }
+
+ psif->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!psif->regs) {
+ ret = -ENOMEM;
+ dev_dbg(&pdev->dev, "could not map I/O memory\n");
+ goto out_free_io;
+ }
+
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(pclk)) {
+ dev_dbg(&pdev->dev, "could not get peripheral clock\n");
+ ret = PTR_ERR(pclk);
+ goto out_iounmap;
+ }
+ psif->pclk = pclk;
+
+ /* Reset the PSIF to enter at a known state. */
+ ret = clk_enable(pclk);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not enable pclk\n");
+ goto out_put_clk;
+ }
+ psif_writel(psif, CR, PSIF_BIT(CR_SWRST));
+ clk_disable(pclk);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_dbg(&pdev->dev, "could not get irq\n");
+ ret = -ENXIO;
+ goto out_put_clk;
+ }
+ ret = request_irq(irq, psif_interrupt, IRQF_SHARED, "at32psif", psif);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
+ goto out_put_clk;
+ }
+ psif->irq = irq;
+
+ io->id.type = SERIO_8042;
+ io->write = psif_write;
+ io->open = psif_open;
+ io->close = psif_close;
+ snprintf(io->name, sizeof(io->name), "AVR32 PS/2 port%d", pdev->id);
+ snprintf(io->phys, sizeof(io->phys), "at32psif/serio%d", pdev->id);
+ io->port_data = psif;
+ io->dev.parent = &pdev->dev;
+
+ psif_set_prescaler(psif);
+
+ spin_lock_init(&psif->lock);
+ serio_register_port(psif->io);
+ platform_set_drvdata(pdev, psif);
+
+ dev_info(&pdev->dev, "Atmel AVR32 PSIF PS/2 driver on 0x%08x irq %d\n",
+ (int)psif->regs, psif->irq);
+
+ return 0;
+
+out_put_clk:
+ clk_put(psif->pclk);
+out_iounmap:
+ iounmap(psif->regs);
+out_free_io:
+ kfree(io);
+out_free_psif:
+ kfree(psif);
+out:
+ return ret;
+}
+
+static int __exit psif_remove(struct platform_device *pdev)
+{
+ struct psif *psif = platform_get_drvdata(pdev);
+
+ psif_writel(psif, IDR, ~0UL);
+ psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
+
+ serio_unregister_port(psif->io);
+ iounmap(psif->regs);
+ free_irq(psif->irq, psif);
+ clk_put(psif->pclk);
+ kfree(psif);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int psif_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct psif *psif = platform_get_drvdata(pdev);
+
+ if (psif->open) {
+ psif_writel(psif, CR, PSIF_BIT(CR_RXDIS) | PSIF_BIT(CR_TXDIS));
+ clk_disable(psif->pclk);
+ }
+
+ return 0;
+}
+
+static int psif_resume(struct platform_device *pdev)
+{
+ struct psif *psif = platform_get_drvdata(pdev);
+
+ if (psif->open) {
+ clk_enable(psif->pclk);
+ psif_set_prescaler(psif);
+ psif_writel(psif, CR, PSIF_BIT(CR_RXEN) | PSIF_BIT(CR_TXEN));
+ }
+
+ return 0;
+}
+#else
+#define psif_suspend NULL
+#define psif_resume NULL
+#endif
+
+static struct platform_driver psif_driver = {
+ .remove = __exit_p(psif_remove),
+ .driver = {
+ .name = "atmel_psif",
+ },
+ .suspend = psif_suspend,
+ .resume = psif_resume,
+};
+
+static int __init psif_init(void)
+{
+ return platform_driver_probe(&psif_driver, psif_probe);
+}
+
+static void __exit psif_exit(void)
+{
+ platform_driver_unregister(&psif_driver);
+}
+
+module_init(psif_init);
+module_exit(psif_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
+MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 60931aceb828..5ece9f56babc 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -370,10 +370,10 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *
if (pnp_irq_valid(dev,0))
i8042_pnp_kbd_irq = pnp_irq(dev, 0);
- strncpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name));
+ strlcpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name));
if (strlen(pnp_dev_name(dev))) {
- strncat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name));
- strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
+ strlcat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name));
+ strlcat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
}
i8042_pnp_kbd_devices++;
@@ -391,10 +391,10 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *
if (pnp_irq_valid(dev, 0))
i8042_pnp_aux_irq = pnp_irq(dev, 0);
- strncpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name));
+ strlcpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name));
if (strlen(pnp_dev_name(dev))) {
- strncat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name));
- strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));
+ strlcat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name));
+ strlcat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));
}
i8042_pnp_aux_devices++;
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 49f84315cb32..34c59d9c6205 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -45,6 +45,7 @@
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kart");
static int rpckbd_write(struct serio *port, unsigned char val)
{
@@ -140,6 +141,7 @@ static struct platform_driver rpckbd_driver = {
.remove = __devexit_p(rpckbd_remove),
.driver = {
.name = "kart",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index d371c0bdc0bd..effb49ea24aa 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -25,14 +25,14 @@ config TABLET_USB_ACECAD
module will be called acecad.
config TABLET_USB_AIPTEK
- tristate "Aiptek 6000U/8000U tablet support (USB)"
+ tristate "Aiptek 6000U/8000U and Genius G_PEN tablet support (USB)"
depends on USB_ARCH_HAS_HCD
select USB
help
- Say Y here if you want to use the USB version of the Aiptek 6000U
- or Aiptek 8000U tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
+ Say Y here if you want to use the USB version of the Aiptek 6000U,
+ Aiptek 8000U or Genius G-PEN 560 tablet. Make sure to say Y to
+ "Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or "Event interface
+ support" (CONFIG_INPUT_EVDEV) as well.
To compile this driver as a module, choose M here: the
module will be called aiptek.
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 94683f58c9e1..1d759f6f8076 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -184,6 +184,7 @@
*/
#define USB_VENDOR_ID_AIPTEK 0x08ca
+#define USB_VENDOR_ID_KYE 0x0458
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
@@ -832,6 +833,7 @@ static const struct usb_device_id aiptek_ids[] = {
{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)},
{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)},
{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)},
+ {USB_DEVICE(USB_VENDOR_ID_KYE, 0x5003)},
{}
};
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index d2c6da264722..f66ca215cdec 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -897,7 +897,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
dbg("Extra descriptor success: type:%d len:%d",
hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
- report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
+ report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL);
if (!report) {
err("No more memory for report");
error = -ENOMEM;
@@ -913,16 +913,16 @@ static int gtco_probe(struct usb_interface *usbinterface,
REPORT_DEVICE_TYPE << 8,
0, /* interface */
report,
- hid_desc->wDescriptorLength,
+ le16_to_cpu(hid_desc->wDescriptorLength),
5000); /* 5 secs */
- if (result == hid_desc->wDescriptorLength)
+ if (result == le16_to_cpu(hid_desc->wDescriptorLength))
break;
}
/* If we didn't get the report, fail */
dbg("usb_control_msg result: :%d", result);
- if (result != hid_desc->wDescriptorLength) {
+ if (result != le16_to_cpu(hid_desc->wDescriptorLength)) {
err("Failed to get HID Report Descriptor of size: %d",
hid_desc->wDescriptorLength);
error = -EIO;
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index acf9830698cb..706619d06f71 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -101,8 +101,11 @@ struct wacom {
dma_addr_t data_dma;
struct input_dev *dev;
struct usb_device *usbdev;
+ struct usb_interface *intf;
struct urb *irq;
struct wacom_wac * wacom_wac;
+ struct mutex lock;
+ int open:1;
char phys[32];
};
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 41caaef8e2d7..71cc0c140790 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -70,6 +70,7 @@ static void wacom_sys_irq(struct urb *urb)
input_sync(get_input_dev(&wcombo));
exit:
+ usb_mark_last_busy(wacom->usbdev);
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
@@ -124,10 +125,25 @@ static int wacom_open(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
+ mutex_lock(&wacom->lock);
+
wacom->irq->dev = wacom->usbdev;
- if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+
+ if (usb_autopm_get_interface(wacom->intf) < 0) {
+ mutex_unlock(&wacom->lock);
return -EIO;
+ }
+
+ if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
+ usb_autopm_put_interface(wacom->intf);
+ mutex_unlock(&wacom->lock);
+ return -EIO;
+ }
+
+ wacom->open = 1;
+ wacom->intf->needs_remote_wakeup = 1;
+ mutex_unlock(&wacom->lock);
return 0;
}
@@ -135,7 +151,11 @@ static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
+ mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq);
+ wacom->open = 0;
+ wacom->intf->needs_remote_wakeup = 0;
+ mutex_unlock(&wacom->lock);
}
void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -243,6 +263,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->usbdev = dev;
wacom->dev = input_dev;
+ wacom->intf = intf;
+ mutex_init(&wacom->lock);
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
@@ -304,23 +326,57 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
static void wacom_disconnect(struct usb_interface *intf)
{
- struct wacom *wacom = usb_get_intfdata (intf);
+ struct wacom *wacom = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
- if (wacom) {
- usb_kill_urb(wacom->irq);
- input_unregister_device(wacom->dev);
- usb_free_urb(wacom->irq);
- usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
- kfree(wacom->wacom_wac);
- kfree(wacom);
- }
+
+ usb_kill_urb(wacom->irq);
+ input_unregister_device(wacom->dev);
+ usb_free_urb(wacom->irq);
+ usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
+ kfree(wacom->wacom_wac);
+ kfree(wacom);
+}
+
+static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct wacom *wacom = usb_get_intfdata(intf);
+
+ mutex_lock(&wacom->lock);
+ usb_kill_urb(wacom->irq);
+ mutex_unlock(&wacom->lock);
+
+ return 0;
+}
+
+static int wacom_resume(struct usb_interface *intf)
+{
+ struct wacom *wacom = usb_get_intfdata(intf);
+ int rv;
+
+ mutex_lock(&wacom->lock);
+ if (wacom->open)
+ rv = usb_submit_urb(wacom->irq, GFP_NOIO);
+ else
+ rv = 0;
+ mutex_unlock(&wacom->lock);
+
+ return rv;
+}
+
+static int wacom_reset_resume(struct usb_interface *intf)
+{
+ return wacom_resume(intf);
}
static struct usb_driver wacom_driver = {
.name = "wacom",
.probe = wacom_probe,
.disconnect = wacom_disconnect,
+ .suspend = wacom_suspend,
+ .resume = wacom_resume,
+ .reset_resume = wacom_reset_resume,
+ .supports_autosuspend = 1,
};
static int __init wacom_init(void)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index ffe33842143f..192513e1f04c 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -649,6 +649,7 @@ static struct wacom_features wacom_features[] = {
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S },
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
+ { "Wacom Cintiq 20WSX", 10, 86680, 54180, 1023, 63, WACOM_BEE },
{ "Wacom Cintiq 12WX", 10, 53020, 33440, 1023, 63, WACOM_BEE },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
{ }
@@ -702,6 +703,7 @@ static struct usb_device_id wacom_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
{ }
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 90e8e92dfe47..565ec711c2ee 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -185,6 +185,59 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
+config TOUCHSCREEN_WM97XX
+ tristate "Support for WM97xx AC97 touchscreen controllers"
+ depends on AC97_BUS
+ help
+ Say Y here if you have a Wolfson Microelectronics WM97xx
+ touchscreen connected to your system. Note that this option
+ only enables core driver, you will also need to select
+ support for appropriate chip below.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm97xx-ts.
+
+config TOUCHSCREEN_WM9705
+ bool "WM9705 Touchscreen interface support"
+ depends on TOUCHSCREEN_WM97XX
+ help
+ Say Y here if you have a Wolfson Microelectronics WM9705
+ touchscreen controller connected to your system.
+
+ If unsure, say N.
+
+config TOUCHSCREEN_WM9712
+ bool "WM9712 Touchscreen interface support"
+ depends on TOUCHSCREEN_WM97XX
+ help
+ Say Y here if you have a Wolfson Microelectronics WM9712
+ touchscreen controller connected to your system.
+
+ If unsure, say N.
+
+config TOUCHSCREEN_WM9713
+ bool "WM9713 Touchscreen interface support"
+ depends on TOUCHSCREEN_WM97XX
+ help
+ Say Y here if you have a Wolfson Microelectronics WM9713 touchscreen
+ controller connected to your system.
+
+ If unsure, say N.
+
+config TOUCHSCREEN_WM97XX_MAINSTONE
+ tristate "WM97xx Mainstone accelerated touch"
+ depends on TOUCHSCREEN_WM97XX && ARCH_PXA
+ help
+ Say Y here for support for streaming mode with WM97xx touchscreens
+ on Mainstone systems.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mainstone-wm97xx.
+
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 35d4097df35a..3c096d75651d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -4,6 +4,8 @@
# Each configuration option enables a list of files.
+wm97xx-ts-y := wm97xx-core.o
+
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
@@ -19,3 +21,8 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 39573b91c8de..907a45fe9d40 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -80,6 +80,7 @@ struct ads7846 {
#endif
u16 model;
+ u16 vref_mv;
u16 vref_delay_usecs;
u16 x_plate_ohms;
u16 pressure_max;
@@ -177,9 +178,6 @@ struct ads7846 {
* The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
* ads7846 lets that pin be unconnected, to use internal vREF.
*/
-static unsigned vREF_mV;
-module_param(vREF_mV, uint, 0);
-MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts");
struct ser_req {
u8 ref_on;
@@ -206,7 +204,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
struct ads7846 *ts = dev_get_drvdata(dev);
struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
int status;
- int uninitialized_var(sample);
int use_internal;
if (!req)
@@ -263,13 +260,13 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
if (status == 0) {
/* on-wire is a must-ignore bit, a BE12 value, then padding */
- sample = be16_to_cpu(req->sample);
- sample = sample >> 3;
- sample &= 0x0fff;
+ status = be16_to_cpu(req->sample);
+ status = status >> 3;
+ status &= 0x0fff;
}
kfree(req);
- return status ? status : sample;
+ return status;
}
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
@@ -310,7 +307,7 @@ static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
unsigned retval = v;
/* external resistors may scale vAUX into 0..vREF */
- retval *= vREF_mV;
+ retval *= ts->vref_mv;
retval = retval >> 12;
return retval;
}
@@ -368,14 +365,14 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
/* hwmon sensors need a reference voltage */
switch (ts->model) {
case 7846:
- if (!vREF_mV) {
+ if (!ts->vref_mv) {
dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
- vREF_mV = 2500;
+ ts->vref_mv = 2500;
}
break;
case 7845:
case 7843:
- if (!vREF_mV) {
+ if (!ts->vref_mv) {
dev_warn(&spi->dev,
"external vREF for ADS%d not specified\n",
ts->model);
@@ -868,6 +865,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->spi = spi;
ts->input = input_dev;
+ ts->vref_mv = pdata->vref_mv;
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index a22576779acd..4e9d8eece2e0 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -362,6 +362,7 @@ static struct platform_driver corgits_driver = {
.resume = corgits_resume,
.driver = {
.name = "corgi-ts",
+ .owner = THIS_MODULE,
},
};
@@ -381,3 +382,4 @@ module_exit(corgits_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Corgi TouchScreen Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:corgi-ts");
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index 42a1c9a1940e..742242111bf1 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -160,11 +160,15 @@ static int __devexit jornada720_ts_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:jornada_ts");
+
static struct platform_driver jornada720_ts_driver = {
.probe = jornada720_ts_probe,
.remove = __devexit_p(jornada720_ts_remove),
.driver = {
.name = "jornada_ts",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
new file mode 100644
index 000000000000..a79f029b91c0
--- /dev/null
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -0,0 +1,302 @@
+/*
+ * mainstone-wm97xx.c -- Mainstone Continuous Touch screen driver for
+ * Wolfson WM97xx AC97 Codecs.
+ *
+ * Copyright 2004, 2007 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ * Andrew Zabolotny <zap@homelink.ru>
+ *
+ * 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.
+ *
+ * Notes:
+ * This is a wm97xx extended touch driver to capture touch
+ * data in a continuous manner on the Intel XScale archictecture
+ *
+ * Features:
+ * - codecs supported:- WM9705, WM9712, WM9713
+ * - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/wm97xx.h>
+#include <linux/io.h>
+#include <asm/arch/pxa-regs.h>
+
+#define VERSION "0.13"
+
+struct continuous {
+ u16 id; /* codec id */
+ u8 code; /* continuous code */
+ u8 reads; /* number of coord reads per read cycle */
+ u32 speed; /* number of coords per second */
+};
+
+#define WM_READS(sp) ((sp / HZ) + 1)
+
+static const struct continuous cinfo[] = {
+ {WM9705_ID2, 0, WM_READS(94), 94},
+ {WM9705_ID2, 1, WM_READS(188), 188},
+ {WM9705_ID2, 2, WM_READS(375), 375},
+ {WM9705_ID2, 3, WM_READS(750), 750},
+ {WM9712_ID2, 0, WM_READS(94), 94},
+ {WM9712_ID2, 1, WM_READS(188), 188},
+ {WM9712_ID2, 2, WM_READS(375), 375},
+ {WM9712_ID2, 3, WM_READS(750), 750},
+ {WM9713_ID2, 0, WM_READS(94), 94},
+ {WM9713_ID2, 1, WM_READS(120), 120},
+ {WM9713_ID2, 2, WM_READS(154), 154},
+ {WM9713_ID2, 3, WM_READS(188), 188},
+};
+
+/* continuous speed index */
+static int sp_idx;
+static u16 last, tries;
+
+/*
+ * Pen sampling frequency (Hz) in continuous mode.
+ */
+static int cont_rate = 200;
+module_param(cont_rate, int, 0);
+MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
+
+/*
+ * Pen down detection.
+ *
+ * This driver can either poll or use an interrupt to indicate a pen down
+ * event. If the irq request fails then it will fall back to polling mode.
+ */
+static int pen_int;
+module_param(pen_int, int, 0);
+MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
+
+/*
+ * Pressure readback.
+ *
+ * Set to 1 to read back pen down pressure
+ */
+static int pressure;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
+
+/*
+ * AC97 touch data slot.
+ *
+ * Touch screen readback data ac97 slot
+ */
+static int ac97_touch_slot = 5;
+module_param(ac97_touch_slot, int, 0);
+MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
+
+
+/* flush AC97 slot 5 FIFO on pxa machines */
+#ifdef CONFIG_PXA27x
+static void wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+ schedule_timeout_uninterruptible(1);
+
+ while (MISR & (1 << 2))
+ MODR;
+}
+#else
+static void wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+ int count = 16;
+ schedule_timeout_uninterruptible(1);
+
+ while (count < 16) {
+ MODR;
+ count--;
+ }
+}
+#endif
+
+static int wm97xx_acc_pen_down(struct wm97xx *wm)
+{
+ u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
+ int reads = 0;
+
+ /* When the AC97 queue has been drained we need to allow time
+ * to buffer up samples otherwise we end up spinning polling
+ * for samples. The controller can't have a suitably low
+ * threashold set to use the notifications it gives.
+ */
+ schedule_timeout_uninterruptible(1);
+
+ if (tries > 5) {
+ tries = 0;
+ return RC_PENUP;
+ }
+
+ x = MODR;
+ if (x == last) {
+ tries++;
+ return RC_AGAIN;
+ }
+ last = x;
+ do {
+ if (reads)
+ x = MODR;
+ y = MODR;
+ if (pressure)
+ p = MODR;
+
+ /* are samples valid */
+ if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
+ (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
+ (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES)
+ goto up;
+
+ /* coordinate is good */
+ tries = 0;
+ input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
+ input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
+ input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
+ input_sync(wm->input_dev);
+ reads++;
+ } while (reads < cinfo[sp_idx].reads);
+up:
+ return RC_PENDOWN | RC_AGAIN;
+}
+
+static int wm97xx_acc_startup(struct wm97xx *wm)
+{
+ int idx = 0;
+
+ /* check we have a codec */
+ if (wm->ac97 == NULL)
+ return -ENODEV;
+
+ /* Go you big red fire engine */
+ for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
+ if (wm->id != cinfo[idx].id)
+ continue;
+ sp_idx = idx;
+ if (cont_rate <= cinfo[idx].speed)
+ break;
+ }
+ wm->acc_rate = cinfo[sp_idx].code;
+ wm->acc_slot = ac97_touch_slot;
+ dev_info(wm->dev,
+ "mainstone accelerated touchscreen driver, %d samples/sec\n",
+ cinfo[sp_idx].speed);
+
+ /* codec specific irq config */
+ if (pen_int) {
+ switch (wm->id) {
+ case WM9705_ID2:
+ wm->pen_irq = IRQ_GPIO(4);
+ set_irq_type(IRQ_GPIO(4), IRQT_BOTHEDGE);
+ break;
+ case WM9712_ID2:
+ case WM9713_ID2:
+ /* enable pen down interrupt */
+ /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
+ wm->pen_irq = MAINSTONE_AC97_IRQ;
+ wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
+ WM97XX_GPIO_POL_HIGH,
+ WM97XX_GPIO_STICKY,
+ WM97XX_GPIO_WAKE);
+ wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
+ WM97XX_GPIO_POL_HIGH,
+ WM97XX_GPIO_NOTSTICKY,
+ WM97XX_GPIO_NOWAKE);
+ break;
+ default:
+ dev_err(wm->dev,
+ "pen down irq not supported on this device\n");
+ pen_int = 0;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void wm97xx_acc_shutdown(struct wm97xx *wm)
+{
+ /* codec specific deconfig */
+ if (pen_int) {
+ switch (wm->id & 0xffff) {
+ case WM9705_ID2:
+ wm->pen_irq = 0;
+ break;
+ case WM9712_ID2:
+ case WM9713_ID2:
+ /* disable interrupt */
+ wm->pen_irq = 0;
+ break;
+ }
+ }
+}
+
+static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
+{
+ if (enable)
+ enable_irq(wm->pen_irq);
+ else
+ disable_irq(wm->pen_irq);
+}
+
+static struct wm97xx_mach_ops mainstone_mach_ops = {
+ .acc_enabled = 1,
+ .acc_pen_up = wm97xx_acc_pen_up,
+ .acc_pen_down = wm97xx_acc_pen_down,
+ .acc_startup = wm97xx_acc_startup,
+ .acc_shutdown = wm97xx_acc_shutdown,
+ .irq_enable = wm97xx_irq_enable,
+ .irq_gpio = WM97XX_GPIO_2,
+};
+
+static int mainstone_wm97xx_probe(struct platform_device *pdev)
+{
+ struct wm97xx *wm = platform_get_drvdata(pdev);
+
+ return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
+}
+
+static int mainstone_wm97xx_remove(struct platform_device *pdev)
+{
+ struct wm97xx *wm = platform_get_drvdata(pdev);
+
+ wm97xx_unregister_mach_ops(wm);
+ return 0;
+}
+
+static struct platform_driver mainstone_wm97xx_driver = {
+ .probe = mainstone_wm97xx_probe,
+ .remove = mainstone_wm97xx_remove,
+ .driver = {
+ .name = "wm97xx-touch",
+ },
+};
+
+static int __init mainstone_wm97xx_init(void)
+{
+ return platform_driver_register(&mainstone_wm97xx_driver);
+}
+
+static void __exit mainstone_wm97xx_exit(void)
+{
+ platform_driver_unregister(&mainstone_wm97xx_driver);
+}
+
+module_init(mainstone_wm97xx_init);
+module_exit(mainstone_wm97xx_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 607f9933aa1f..bce018e45bce 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -427,10 +427,6 @@ static int ucb1400_detect_irq(struct ucb1400 *ucb)
unsigned long mask, timeout;
mask = probe_irq_on();
- if (!mask) {
- probe_irq_off(mask);
- return -EBUSY;
- }
/* Enable the ADC interrupt. */
ucb1400_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 63f9664a066f..3a0a8ca57076 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -396,9 +396,12 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
{
struct usb_device *dev = usbtouch->udev;
- int ret;
- unsigned char buf[2];
+ int ret = -ENOMEM;
+ unsigned char *buf;
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ goto err_nobuf;
/* reset */
buf[0] = buf[1] = 0xFF;
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
@@ -406,9 +409,11 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
- return ret;
- if (buf[0] != 0x06 || buf[1] != 0x00)
- return -ENODEV;
+ goto err_out;
+ if (buf[0] != 0x06 || buf[1] != 0x00) {
+ ret = -ENODEV;
+ goto err_out;
+ }
/* set coordinate output rate */
buf[0] = buf[1] = 0xFF;
@@ -417,20 +422,22 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
- return ret;
+ goto err_out;
if ((buf[0] != 0x06 || buf[1] != 0x00) &&
- (buf[0] != 0x15 || buf[1] != 0x01))
- return -ENODEV;
+ (buf[0] != 0x15 || buf[1] != 0x01)) {
+ ret = -ENODEV;
+ goto err_out;
+ }
/* start sending data */
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
TSC10_CMD_DATA1,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
- if (ret < 0)
- return ret;
-
- return 0;
+err_out:
+ kfree(buf);
+err_nobuf:
+ return ret;
}
diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
new file mode 100644
index 000000000000..978e1a13ffc7
--- /dev/null
+++ b/drivers/input/touchscreen/wm9705.c
@@ -0,0 +1,353 @@
+/*
+ * wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ * Andrew Zabolotny <zap@homelink.ru>
+ * Russell King <rmk@arm.linux.org.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
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wm97xx.h>
+
+#define TS_NAME "wm97xx"
+#define WM9705_VERSION "1.00"
+#define DEFAULT_PRESSURE 0xb0c0
+
+/*
+ * Module parameters
+ */
+
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA
+ * pil = 1 to use 200uA and
+ * pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure.
+ */
+static int pil;
+module_param(pil, int, 0);
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+
+/*
+ * Set threshold for pressure measurement.
+ *
+ * Pen down pressure below threshold is ignored.
+ */
+static int pressure = DEFAULT_PRESSURE & 0xfff;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
+
+/*
+ * Set adc sample delay.
+ *
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+static int delay = 4;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+
+/*
+ * Pen detect comparator threshold.
+ *
+ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
+ * i.e. 1 = Vmid/15 threshold
+ * 15 = Vmid/1 threshold
+ *
+ * Adjust this value if you are having problems with pen detect not
+ * detecting any down events.
+ */
+static int pdd = 8;
+module_param(pdd, int, 0);
+MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
+
+/*
+ * Set adc mask function.
+ *
+ * Sources of glitch noise, such as signals driving an LCD display, may feed
+ * through to the touch screen plates and affect measurement accuracy. In
+ * order to minimise this, a signal may be applied to the MASK pin to delay or
+ * synchronise the sampling.
+ *
+ * 0 = No delay or sync
+ * 1 = High on pin stops conversions
+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
+ * 3 = Edge triggered, edge on pin starts conversion after delay param
+ */
+static int mask;
+module_param(mask, int, 0);
+MODULE_PARM_DESC(mask, "Set adc mask function.");
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[] = {
+ 21, /* 1 AC97 Link frames */
+ 42, /* 2 */
+ 84, /* 4 */
+ 167, /* 8 */
+ 333, /* 16 */
+ 667, /* 32 */
+ 1000, /* 48 */
+ 1333, /* 64 */
+ 2000, /* 96 */
+ 2667, /* 128 */
+ 3333, /* 160 */
+ 4000, /* 192 */
+ 4667, /* 224 */
+ 5333, /* 256 */
+ 6000, /* 288 */
+ 0 /* No delay, switch matrix always on */
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+static inline void poll_delay(int d)
+{
+ udelay(3 * AC97_LINK_FRAME + delay_table[d]);
+}
+
+/*
+ * set up the physical settings of the WM9705
+ */
+static void wm9705_phy_init(struct wm97xx *wm)
+{
+ u16 dig1 = 0, dig2 = WM97XX_RPR;
+
+ /*
+ * mute VIDEO and AUX as they share X and Y touchscreen
+ * inputs on the WM9705
+ */
+ wm97xx_reg_write(wm, AC97_AUX, 0x8000);
+ wm97xx_reg_write(wm, AC97_VIDEO, 0x8000);
+
+ /* touchpanel pressure current*/
+ if (pil == 2) {
+ dig2 |= WM9705_PIL;
+ dev_dbg(wm->dev,
+ "setting pressure measurement current to 400uA.");
+ } else if (pil)
+ dev_dbg(wm->dev,
+ "setting pressure measurement current to 200uA.");
+ if (!pil)
+ pressure = 0;
+
+ /* polling mode sample settling delay */
+ if (delay != 4) {
+ if (delay < 0 || delay > 15) {
+ dev_dbg(wm->dev, "supplied delay out of range.");
+ delay = 4;
+ }
+ }
+ dig1 &= 0xff0f;
+ dig1 |= WM97XX_DELAY(delay);
+ dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
+ delay_table[delay]);
+
+ /* WM9705 pdd */
+ dig2 |= (pdd & 0x000f);
+ dev_dbg(wm->dev, "setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
+
+ /* mask */
+ dig2 |= ((mask & 0x3) << 4);
+
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+}
+
+static void wm9705_dig_enable(struct wm97xx *wm, int enable)
+{
+ if (enable) {
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+ wm->dig[2] | WM97XX_PRP_DET_DIG);
+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
+ } else
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+ wm->dig[2] & ~WM97XX_PRP_DET_DIG);
+}
+
+static void wm9705_aux_prepare(struct wm97xx *wm)
+{
+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
+}
+
+static void wm9705_dig_restore(struct wm97xx *wm)
+{
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
+}
+
+static inline int is_pden(struct wm97xx *wm)
+{
+ return wm->dig[2] & WM9705_PDEN;
+}
+
+/*
+ * Read a sample from the WM9705 adc in polling mode.
+ */
+static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
+{
+ int timeout = 5 * delay;
+
+ if (!wm->pen_probably_down) {
+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (!(data & WM97XX_PEN_DOWN))
+ return RC_PENUP;
+ wm->pen_probably_down = 1;
+ }
+
+ /* set up digitiser */
+ if (adcsel & 0x8000)
+ adcsel = ((adcsel & 0x7fff) + 3) << 12;
+
+ if (wm->mach_ops && wm->mach_ops->pre_sample)
+ wm->mach_ops->pre_sample(adcsel);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
+ adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
+
+ /* wait 3 AC97 time slots + delay for conversion */
+ poll_delay(delay);
+
+ /* wait for POLL to go low */
+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
+ && timeout) {
+ udelay(AC97_LINK_FRAME);
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ /* If PDEN is set, we can get a timeout when pen goes up */
+ if (is_pden(wm))
+ wm->pen_probably_down = 0;
+ else
+ dev_dbg(wm->dev, "adc sample timeout");
+ return RC_PENUP;
+ }
+
+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (wm->mach_ops && wm->mach_ops->post_sample)
+ wm->mach_ops->post_sample(adcsel);
+
+ /* check we have correct sample */
+ if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
+ dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
+ *sample & WM97XX_ADCSEL_MASK);
+ return RC_PENUP;
+ }
+
+ if (!(*sample & WM97XX_PEN_DOWN)) {
+ wm->pen_probably_down = 0;
+ return RC_PENUP;
+ }
+
+ return RC_VALID;
+}
+
+/*
+ * Sample the WM9705 touchscreen in polling mode
+ */
+static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
+{
+ int rc;
+
+ rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
+ if (rc != RC_VALID)
+ return rc;
+ rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
+ if (rc != RC_VALID)
+ return rc;
+ if (pil) {
+ rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p);
+ if (rc != RC_VALID)
+ return rc;
+ } else
+ data->p = DEFAULT_PRESSURE;
+
+ return RC_VALID;
+}
+
+/*
+ * Enable WM9705 continuous mode, i.e. touch data is streamed across
+ * an AC97 slot
+ */
+static int wm9705_acc_enable(struct wm97xx *wm, int enable)
+{
+ u16 dig1, dig2;
+ int ret = 0;
+
+ dig1 = wm->dig[1];
+ dig2 = wm->dig[2];
+
+ if (enable) {
+ /* continous mode */
+ if (wm->mach_ops->acc_startup &&
+ (ret = wm->mach_ops->acc_startup(wm)) < 0)
+ return ret;
+ dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
+ WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
+ dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
+ WM97XX_DELAY(delay) |
+ WM97XX_SLT(wm->acc_slot) |
+ WM97XX_RATE(wm->acc_rate);
+ if (pil)
+ dig1 |= WM97XX_ADCSEL_PRES;
+ dig2 |= WM9705_PDEN;
+ } else {
+ dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
+ dig2 &= ~WM9705_PDEN;
+ if (wm->mach_ops->acc_shutdown)
+ wm->mach_ops->acc_shutdown(wm);
+ }
+
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+
+ return ret;
+}
+
+struct wm97xx_codec_drv wm9705_codec = {
+ .id = WM9705_ID2,
+ .name = "wm9705",
+ .poll_sample = wm9705_poll_sample,
+ .poll_touch = wm9705_poll_touch,
+ .acc_enable = wm9705_acc_enable,
+ .phy_init = wm9705_phy_init,
+ .dig_enable = wm9705_dig_enable,
+ .dig_restore = wm9705_dig_restore,
+ .aux_prepare = wm9705_aux_prepare,
+};
+EXPORT_SYMBOL_GPL(wm9705_codec);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
new file mode 100644
index 000000000000..0b6e4cfa6a21
--- /dev/null
+++ b/drivers/input/touchscreen/wm9712.c
@@ -0,0 +1,462 @@
+/*
+ * wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ * Andrew Zabolotny <zap@homelink.ru>
+ * Russell King <rmk@arm.linux.org.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
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wm97xx.h>
+
+#define TS_NAME "wm97xx"
+#define WM9712_VERSION "1.00"
+#define DEFAULT_PRESSURE 0xb0c0
+
+/*
+ * Module parameters
+ */
+
+/*
+ * Set internal pull up for pen detect.
+ *
+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+ * i.e. pull up resistance = 64k Ohms / rpu.
+ *
+ * Adjust this value if you are having problems with pen detect not
+ * detecting any down event.
+ */
+static int rpu = 8;
+module_param(rpu, int, 0);
+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
+
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA
+ * pil = 1 to use 200uA and
+ * pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure.
+ */
+static int pil;
+module_param(pil, int, 0);
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+
+/*
+ * Set threshold for pressure measurement.
+ *
+ * Pen down pressure below threshold is ignored.
+ */
+static int pressure = DEFAULT_PRESSURE & 0xfff;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
+
+/*
+ * Set adc sample delay.
+ *
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+static int delay = 3;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+
+/*
+ * Set five_wire = 1 to use a 5 wire touchscreen.
+ *
+ * NOTE: Five wire mode does not allow for readback of pressure.
+ */
+static int five_wire;
+module_param(five_wire, int, 0);
+MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
+
+/*
+ * Set adc mask function.
+ *
+ * Sources of glitch noise, such as signals driving an LCD display, may feed
+ * through to the touch screen plates and affect measurement accuracy. In
+ * order to minimise this, a signal may be applied to the MASK pin to delay or
+ * synchronise the sampling.
+ *
+ * 0 = No delay or sync
+ * 1 = High on pin stops conversions
+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
+ * 3 = Edge triggered, edge on pin starts conversion after delay param
+ */
+static int mask;
+module_param(mask, int, 0);
+MODULE_PARM_DESC(mask, "Set adc mask function.");
+
+/*
+ * Coordinate Polling Enable.
+ *
+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
+ * for every poll.
+ */
+static int coord;
+module_param(coord, int, 0);
+MODULE_PARM_DESC(coord, "Polling coordinate mode");
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[] = {
+ 21, /* 1 AC97 Link frames */
+ 42, /* 2 */
+ 84, /* 4 */
+ 167, /* 8 */
+ 333, /* 16 */
+ 667, /* 32 */
+ 1000, /* 48 */
+ 1333, /* 64 */
+ 2000, /* 96 */
+ 2667, /* 128 */
+ 3333, /* 160 */
+ 4000, /* 192 */
+ 4667, /* 224 */
+ 5333, /* 256 */
+ 6000, /* 288 */
+ 0 /* No delay, switch matrix always on */
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+static inline void poll_delay(int d)
+{
+ udelay(3 * AC97_LINK_FRAME + delay_table[d]);
+}
+
+/*
+ * set up the physical settings of the WM9712
+ */
+static void wm9712_phy_init(struct wm97xx *wm)
+{
+ u16 dig1 = 0;
+ u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
+
+ /* WM9712 rpu */
+ if (rpu) {
+ dig2 &= 0xffc0;
+ dig2 |= WM9712_RPU(rpu);
+ dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
+ 64000 / rpu);
+ }
+
+ /* touchpanel pressure current*/
+ if (pil == 2) {
+ dig2 |= WM9712_PIL;
+ dev_dbg(wm->dev,
+ "setting pressure measurement current to 400uA.");
+ } else if (pil)
+ dev_dbg(wm->dev,
+ "setting pressure measurement current to 200uA.");
+ if (!pil)
+ pressure = 0;
+
+ /* WM9712 five wire */
+ if (five_wire) {
+ dig2 |= WM9712_45W;
+ dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
+ }
+
+ /* polling mode sample settling delay */
+ if (delay < 0 || delay > 15) {
+ dev_dbg(wm->dev, "supplied delay out of range.");
+ delay = 4;
+ }
+ dig1 &= 0xff0f;
+ dig1 |= WM97XX_DELAY(delay);
+ dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
+ delay_table[delay]);
+
+ /* mask */
+ dig2 |= ((mask & 0x3) << 6);
+ if (mask) {
+ u16 reg;
+ /* Set GPIO4 as Mask Pin*/
+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
+ wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
+ reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+ wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
+ }
+
+ /* wait - coord mode */
+ if (coord)
+ dig2 |= WM9712_WAIT;
+
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+}
+
+static void wm9712_dig_enable(struct wm97xx *wm, int enable)
+{
+ u16 dig2 = wm->dig[2];
+
+ if (enable) {
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+ dig2 | WM97XX_PRP_DET_DIG);
+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
+ } else
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+ dig2 & ~WM97XX_PRP_DET_DIG);
+}
+
+static void wm9712_aux_prepare(struct wm97xx *wm)
+{
+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
+}
+
+static void wm9712_dig_restore(struct wm97xx *wm)
+{
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
+}
+
+static inline int is_pden(struct wm97xx *wm)
+{
+ return wm->dig[2] & WM9712_PDEN;
+}
+
+/*
+ * Read a sample from the WM9712 adc in polling mode.
+ */
+static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
+{
+ int timeout = 5 * delay;
+
+ if (!wm->pen_probably_down) {
+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (!(data & WM97XX_PEN_DOWN))
+ return RC_PENUP;
+ wm->pen_probably_down = 1;
+ }
+
+ /* set up digitiser */
+ if (adcsel & 0x8000)
+ adcsel = ((adcsel & 0x7fff) + 3) << 12;
+
+ if (wm->mach_ops && wm->mach_ops->pre_sample)
+ wm->mach_ops->pre_sample(adcsel);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
+ adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
+
+ /* wait 3 AC97 time slots + delay for conversion */
+ poll_delay(delay);
+
+ /* wait for POLL to go low */
+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
+ && timeout) {
+ udelay(AC97_LINK_FRAME);
+ timeout--;
+ }
+
+ if (timeout <= 0) {
+ /* If PDEN is set, we can get a timeout when pen goes up */
+ if (is_pden(wm))
+ wm->pen_probably_down = 0;
+ else
+ dev_dbg(wm->dev, "adc sample timeout");
+ return RC_PENUP;
+ }
+
+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (wm->mach_ops && wm->mach_ops->post_sample)
+ wm->mach_ops->post_sample(adcsel);
+
+ /* check we have correct sample */
+ if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
+ dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
+ *sample & WM97XX_ADCSEL_MASK);
+ return RC_PENUP;
+ }
+
+ if (!(*sample & WM97XX_PEN_DOWN)) {
+ wm->pen_probably_down = 0;
+ return RC_PENUP;
+ }
+
+ return RC_VALID;
+}
+
+/*
+ * Read a coord from the WM9712 adc in polling mode.
+ */
+static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
+{
+ int timeout = 5 * delay;
+
+ if (!wm->pen_probably_down) {
+ u16 data_rd = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (!(data_rd & WM97XX_PEN_DOWN))
+ return RC_PENUP;
+ wm->pen_probably_down = 1;
+ }
+
+ /* set up digitiser */
+ if (wm->mach_ops && wm->mach_ops->pre_sample)
+ wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
+ WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
+
+ /* wait 3 AC97 time slots + delay for conversion and read x */
+ poll_delay(delay);
+ data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ /* wait for POLL to go low */
+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
+ && timeout) {
+ udelay(AC97_LINK_FRAME);
+ timeout--;
+ }
+
+ if (timeout <= 0) {
+ /* If PDEN is set, we can get a timeout when pen goes up */
+ if (is_pden(wm))
+ wm->pen_probably_down = 0;
+ else
+ dev_dbg(wm->dev, "adc sample timeout");
+ return RC_PENUP;
+ }
+
+ /* read back y data */
+ data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (pil)
+ data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ else
+ data->p = DEFAULT_PRESSURE;
+
+ if (wm->mach_ops && wm->mach_ops->post_sample)
+ wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+
+ /* check we have correct sample */
+ if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
+ goto err;
+ if (pil && !(data->p & WM97XX_ADCSEL_PRES))
+ goto err;
+
+ if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
+ wm->pen_probably_down = 0;
+ return RC_PENUP;
+ }
+ return RC_VALID;
+err:
+ return 0;
+}
+
+/*
+ * Sample the WM9712 touchscreen in polling mode
+ */
+static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
+{
+ int rc;
+
+ if (coord) {
+ rc = wm9712_poll_coord(wm, data);
+ if (rc != RC_VALID)
+ return rc;
+ } else {
+ rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
+ if (rc != RC_VALID)
+ return rc;
+
+ rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
+ if (rc != RC_VALID)
+ return rc;
+
+ if (pil && !five_wire) {
+ rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
+ &data->p);
+ if (rc != RC_VALID)
+ return rc;
+ } else
+ data->p = DEFAULT_PRESSURE;
+ }
+ return RC_VALID;
+}
+
+/*
+ * Enable WM9712 continuous mode, i.e. touch data is streamed across
+ * an AC97 slot
+ */
+static int wm9712_acc_enable(struct wm97xx *wm, int enable)
+{
+ u16 dig1, dig2;
+ int ret = 0;
+
+ dig1 = wm->dig[1];
+ dig2 = wm->dig[2];
+
+ if (enable) {
+ /* continous mode */
+ if (wm->mach_ops->acc_startup) {
+ ret = wm->mach_ops->acc_startup(wm);
+ if (ret < 0)
+ return ret;
+ }
+ dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
+ WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
+ dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
+ WM97XX_DELAY(delay) |
+ WM97XX_SLT(wm->acc_slot) |
+ WM97XX_RATE(wm->acc_rate);
+ if (pil)
+ dig1 |= WM97XX_ADCSEL_PRES;
+ dig2 |= WM9712_PDEN;
+ } else {
+ dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
+ dig2 &= ~WM9712_PDEN;
+ if (wm->mach_ops->acc_shutdown)
+ wm->mach_ops->acc_shutdown(wm);
+ }
+
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+
+ return 0;
+}
+
+struct wm97xx_codec_drv wm9712_codec = {
+ .id = WM9712_ID2,
+ .name = "wm9712",
+ .poll_sample = wm9712_poll_sample,
+ .poll_touch = wm9712_poll_touch,
+ .acc_enable = wm9712_acc_enable,
+ .phy_init = wm9712_phy_init,
+ .dig_enable = wm9712_dig_enable,
+ .dig_restore = wm9712_dig_restore,
+ .aux_prepare = wm9712_aux_prepare,
+};
+EXPORT_SYMBOL_GPL(wm9712_codec);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
new file mode 100644
index 000000000000..01278bd7e65c
--- /dev/null
+++ b/drivers/input/touchscreen/wm9713.c
@@ -0,0 +1,460 @@
+/*
+ * wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ * Andrew Zabolotny <zap@homelink.ru>
+ * Russell King <rmk@arm.linux.org.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
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wm97xx.h>
+
+#define TS_NAME "wm97xx"
+#define WM9713_VERSION "1.00"
+#define DEFAULT_PRESSURE 0xb0c0
+
+/*
+ * Module parameters
+ */
+
+/*
+ * Set internal pull up for pen detect.
+ *
+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+ * i.e. pull up resistance = 64k Ohms / rpu.
+ *
+ * Adjust this value if you are having problems with pen detect not
+ * detecting any down event.
+ */
+static int rpu = 8;
+module_param(rpu, int, 0);
+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
+
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA
+ * pil = 1 to use 200uA and
+ * pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure.
+ */
+static int pil;
+module_param(pil, int, 0);
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+
+/*
+ * Set threshold for pressure measurement.
+ *
+ * Pen down pressure below threshold is ignored.
+ */
+static int pressure = DEFAULT_PRESSURE & 0xfff;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
+
+/*
+ * Set adc sample delay.
+ *
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+static int delay = 4;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+
+/*
+ * Set adc mask function.
+ *
+ * Sources of glitch noise, such as signals driving an LCD display, may feed
+ * through to the touch screen plates and affect measurement accuracy. In
+ * order to minimise this, a signal may be applied to the MASK pin to delay or
+ * synchronise the sampling.
+ *
+ * 0 = No delay or sync
+ * 1 = High on pin stops conversions
+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
+ * 3 = Edge triggered, edge on pin starts conversion after delay param
+ */
+static int mask;
+module_param(mask, int, 0);
+MODULE_PARM_DESC(mask, "Set adc mask function.");
+
+/*
+ * Coordinate Polling Enable.
+ *
+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
+ * for every poll.
+ */
+static int coord;
+module_param(coord, int, 0);
+MODULE_PARM_DESC(coord, "Polling coordinate mode");
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[] = {
+ 21, /* 1 AC97 Link frames */
+ 42, /* 2 */
+ 84, /* 4 */
+ 167, /* 8 */
+ 333, /* 16 */
+ 667, /* 32 */
+ 1000, /* 48 */
+ 1333, /* 64 */
+ 2000, /* 96 */
+ 2667, /* 128 */
+ 3333, /* 160 */
+ 4000, /* 192 */
+ 4667, /* 224 */
+ 5333, /* 256 */
+ 6000, /* 288 */
+ 0 /* No delay, switch matrix always on */
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+static inline void poll_delay(int d)
+{
+ udelay(3 * AC97_LINK_FRAME + delay_table[d]);
+}
+
+/*
+ * set up the physical settings of the WM9713
+ */
+static void wm9713_phy_init(struct wm97xx *wm)
+{
+ u16 dig1 = 0, dig2, dig3;
+
+ /* default values */
+ dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
+ dig3 = WM9712_RPU(1);
+
+ /* rpu */
+ if (rpu) {
+ dig3 &= 0xffc0;
+ dig3 |= WM9712_RPU(rpu);
+ dev_info(wm->dev, "setting pen detect pull-up to %d Ohms\n",
+ 64000 / rpu);
+ }
+
+ /* touchpanel pressure */
+ if (pil == 2) {
+ dig3 |= WM9712_PIL;
+ dev_info(wm->dev,
+ "setting pressure measurement current to 400uA.");
+ } else if (pil)
+ dev_info(wm->dev,
+ "setting pressure measurement current to 200uA.");
+ if (!pil)
+ pressure = 0;
+
+ /* sample settling delay */
+ if (delay < 0 || delay > 15) {
+ dev_info(wm->dev, "supplied delay out of range.");
+ delay = 4;
+ dev_info(wm->dev, "setting adc sample delay to %d u Secs.",
+ delay_table[delay]);
+ }
+ dig2 &= 0xff0f;
+ dig2 |= WM97XX_DELAY(delay);
+
+ /* mask */
+ dig3 |= ((mask & 0x3) << 4);
+ if (coord)
+ dig3 |= WM9713_WAIT;
+
+ wm->misc = wm97xx_reg_read(wm, 0x5a);
+
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
+}
+
+static void wm9713_dig_enable(struct wm97xx *wm, int enable)
+{
+ u16 val;
+
+ if (enable) {
+ val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] |
+ WM97XX_PRP_DET_DIG);
+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
+ } else {
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] &
+ ~WM97XX_PRP_DET_DIG);
+ val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
+ }
+}
+
+static void wm9713_dig_restore(struct wm97xx *wm)
+{
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
+}
+
+static void wm9713_aux_prepare(struct wm97xx *wm)
+{
+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
+}
+
+static inline int is_pden(struct wm97xx *wm)
+{
+ return wm->dig[2] & WM9713_PDEN;
+}
+
+/*
+ * Read a sample from the WM9713 adc in polling mode.
+ */
+static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
+{
+ u16 dig1;
+ int timeout = 5 * delay;
+
+ if (!wm->pen_probably_down) {
+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (!(data & WM97XX_PEN_DOWN))
+ return RC_PENUP;
+ wm->pen_probably_down = 1;
+ }
+
+ /* set up digitiser */
+ if (adcsel & 0x8000)
+ adcsel = 1 << ((adcsel & 0x7fff) + 3);
+
+ dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
+ dig1 &= ~WM9713_ADCSEL_MASK;
+
+ if (wm->mach_ops && wm->mach_ops->pre_sample)
+ wm->mach_ops->pre_sample(adcsel);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel | WM9713_POLL);
+
+ /* wait 3 AC97 time slots + delay for conversion */
+ poll_delay(delay);
+
+ /* wait for POLL to go low */
+ while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) &&
+ timeout) {
+ udelay(AC97_LINK_FRAME);
+ timeout--;
+ }
+
+ if (timeout <= 0) {
+ /* If PDEN is set, we can get a timeout when pen goes up */
+ if (is_pden(wm))
+ wm->pen_probably_down = 0;
+ else
+ dev_dbg(wm->dev, "adc sample timeout");
+ return RC_PENUP;
+ }
+
+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (wm->mach_ops && wm->mach_ops->post_sample)
+ wm->mach_ops->post_sample(adcsel);
+
+ /* check we have correct sample */
+ if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
+ dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
+ *sample & WM97XX_ADCSRC_MASK);
+ return RC_PENUP;
+ }
+
+ if (!(*sample & WM97XX_PEN_DOWN)) {
+ wm->pen_probably_down = 0;
+ return RC_PENUP;
+ }
+
+ return RC_VALID;
+}
+
+/*
+ * Read a coordinate from the WM9713 adc in polling mode.
+ */
+static int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
+{
+ u16 dig1;
+ int timeout = 5 * delay;
+
+ if (!wm->pen_probably_down) {
+ u16 val = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (!(val & WM97XX_PEN_DOWN))
+ return RC_PENUP;
+ wm->pen_probably_down = 1;
+ }
+
+ /* set up digitiser */
+ dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
+ dig1 &= ~WM9713_ADCSEL_MASK;
+ if (pil)
+ dig1 |= WM9713_ADCSEL_PRES;
+
+ if (wm->mach_ops && wm->mach_ops->pre_sample)
+ wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1,
+ dig1 | WM9713_POLL | WM9713_COO);
+
+ /* wait 3 AC97 time slots + delay for conversion */
+ poll_delay(delay);
+ data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ /* wait for POLL to go low */
+ while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL)
+ && timeout) {
+ udelay(AC97_LINK_FRAME);
+ timeout--;
+ }
+
+ if (timeout <= 0) {
+ /* If PDEN is set, we can get a timeout when pen goes up */
+ if (is_pden(wm))
+ wm->pen_probably_down = 0;
+ else
+ dev_dbg(wm->dev, "adc sample timeout");
+ return RC_PENUP;
+ }
+
+ /* read back data */
+ data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (pil)
+ data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ else
+ data->p = DEFAULT_PRESSURE;
+
+ if (wm->mach_ops && wm->mach_ops->post_sample)
+ wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+
+ /* check we have correct sample */
+ if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
+ goto err;
+ if (pil && !(data->p & WM97XX_ADCSEL_PRES))
+ goto err;
+
+ if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
+ wm->pen_probably_down = 0;
+ return RC_PENUP;
+ }
+ return RC_VALID;
+err:
+ return 0;
+}
+
+/*
+ * Sample the WM9713 touchscreen in polling mode
+ */
+static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
+{
+ int rc;
+
+ if (coord) {
+ rc = wm9713_poll_coord(wm, data);
+ if (rc != RC_VALID)
+ return rc;
+ } else {
+ rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x);
+ if (rc != RC_VALID)
+ return rc;
+ rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y);
+ if (rc != RC_VALID)
+ return rc;
+ if (pil) {
+ rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES,
+ &data->p);
+ if (rc != RC_VALID)
+ return rc;
+ } else
+ data->p = DEFAULT_PRESSURE;
+ }
+ return RC_VALID;
+}
+
+/*
+ * Enable WM9713 continuous mode, i.e. touch data is streamed across
+ * an AC97 slot
+ */
+static int wm9713_acc_enable(struct wm97xx *wm, int enable)
+{
+ u16 dig1, dig2, dig3;
+ int ret = 0;
+
+ dig1 = wm->dig[0];
+ dig2 = wm->dig[1];
+ dig3 = wm->dig[2];
+
+ if (enable) {
+ /* continous mode */
+ if (wm->mach_ops->acc_startup &&
+ (ret = wm->mach_ops->acc_startup(wm)) < 0)
+ return ret;
+
+ dig1 &= ~WM9713_ADCSEL_MASK;
+ dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X |
+ WM9713_ADCSEL_Y;
+ if (pil)
+ dig1 |= WM9713_ADCSEL_PRES;
+ dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK |
+ WM97XX_CM_RATE_MASK);
+ dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) |
+ WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate);
+ dig3 |= WM9713_PDEN;
+ } else {
+ dig1 &= ~(WM9713_CTC | WM9713_COO);
+ dig2 &= ~WM97XX_SLEN;
+ dig3 &= ~WM9713_PDEN;
+ if (wm->mach_ops->acc_shutdown)
+ wm->mach_ops->acc_shutdown(wm);
+ }
+
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
+
+ return ret;
+}
+
+struct wm97xx_codec_drv wm9713_codec = {
+ .id = WM9713_ID2,
+ .name = "wm9713",
+ .poll_sample = wm9713_poll_sample,
+ .poll_touch = wm9713_poll_touch,
+ .acc_enable = wm9713_acc_enable,
+ .phy_init = wm9713_phy_init,
+ .dig_enable = wm9713_dig_enable,
+ .dig_restore = wm9713_dig_restore,
+ .aux_prepare = wm9713_aux_prepare,
+};
+EXPORT_SYMBOL_GPL(wm9713_codec);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
new file mode 100644
index 000000000000..e9c7ea46b6e3
--- /dev/null
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -0,0 +1,829 @@
+/*
+ * wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712
+ * and WM9713 AC97 Codecs.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ * Andrew Zabolotny <zap@homelink.ru>
+ * Russell King <rmk@arm.linux.org.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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Notes:
+ *
+ * Features:
+ * - supports WM9705, WM9712, WM9713
+ * - polling mode
+ * - continuous mode (arch-dependent)
+ * - adjustable rpu/dpp settings
+ * - adjustable pressure current
+ * - adjustable sample settle delay
+ * - 4 and 5 wire touchscreens (5 wire is WM9712 only)
+ * - pen down detection
+ * - battery monitor
+ * - sample AUX adcs
+ * - power management
+ * - codec GPIO
+ * - codec event notification
+ * Todo
+ * - Support for async sampling control for noisy LCDs.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+#include <linux/wm97xx.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#define TS_NAME "wm97xx"
+#define WM_CORE_VERSION "1.00"
+#define DEFAULT_PRESSURE 0xb0c0
+
+
+/*
+ * Touchscreen absolute values
+ *
+ * These parameters are used to help the input layer discard out of
+ * range readings and reduce jitter etc.
+ *
+ * o min, max:- indicate the min and max values your touch screen returns
+ * o fuzz:- use a higher number to reduce jitter
+ *
+ * The default values correspond to Mainstone II in QVGA mode
+ *
+ * Please read
+ * Documentation/input/input-programming.txt for more details.
+ */
+
+static int abs_x[3] = {350, 3900, 5};
+module_param_array(abs_x, int, NULL, 0);
+MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
+
+static int abs_y[3] = {320, 3750, 40};
+module_param_array(abs_y, int, NULL, 0);
+MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
+
+static int abs_p[3] = {0, 150, 4};
+module_param_array(abs_p, int, NULL, 0);
+MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz");
+
+/*
+ * wm97xx IO access, all IO locking done by AC97 layer
+ */
+int wm97xx_reg_read(struct wm97xx *wm, u16 reg)
+{
+ if (wm->ac97)
+ return wm->ac97->bus->ops->read(wm->ac97, reg);
+ else
+ return -1;
+}
+EXPORT_SYMBOL_GPL(wm97xx_reg_read);
+
+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val)
+{
+ /* cache digitiser registers */
+ if (reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3)
+ wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val;
+
+ /* cache gpio regs */
+ if (reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE)
+ wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val;
+
+ /* wm9713 irq reg */
+ if (reg == 0x5a)
+ wm->misc = val;
+
+ if (wm->ac97)
+ wm->ac97->bus->ops->write(wm->ac97, reg, val);
+}
+EXPORT_SYMBOL_GPL(wm97xx_reg_write);
+
+/**
+ * wm97xx_read_aux_adc - Read the aux adc.
+ * @wm: wm97xx device.
+ * @adcsel: codec ADC to be read
+ *
+ * Reads the selected AUX ADC.
+ */
+
+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
+{
+ int power_adc = 0, auxval;
+ u16 power = 0;
+
+ /* get codec */
+ mutex_lock(&wm->codec_mutex);
+
+ /* When the touchscreen is not in use, we may have to power up
+ * the AUX ADC before we can use sample the AUX inputs->
+ */
+ if (wm->id == WM9713_ID2 &&
+ (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) {
+ power_adc = 1;
+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff);
+ }
+
+ /* Prepare the codec for AUX reading */
+ wm->codec->aux_prepare(wm);
+
+ /* Turn polling mode on to read AUX ADC */
+ wm->pen_probably_down = 1;
+ wm->codec->poll_sample(wm, adcsel, &auxval);
+
+ if (power_adc)
+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
+
+ wm->codec->dig_restore(wm);
+
+ wm->pen_probably_down = 0;
+
+ mutex_unlock(&wm->codec_mutex);
+ return auxval & 0xfff;
+}
+EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
+
+/**
+ * wm97xx_get_gpio - Get the status of a codec GPIO.
+ * @wm: wm97xx device.
+ * @gpio: gpio
+ *
+ * Get the status of a codec GPIO pin
+ */
+
+enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio)
+{
+ u16 status;
+ enum wm97xx_gpio_status ret;
+
+ mutex_lock(&wm->codec_mutex);
+ status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+
+ if (status & gpio)
+ ret = WM97XX_GPIO_HIGH;
+ else
+ ret = WM97XX_GPIO_LOW;
+
+ mutex_unlock(&wm->codec_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
+
+/**
+ * wm97xx_set_gpio - Set the status of a codec GPIO.
+ * @wm: wm97xx device.
+ * @gpio: gpio
+ *
+ *
+ * Set the status of a codec GPIO pin
+ */
+
+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
+ enum wm97xx_gpio_status status)
+{
+ u16 reg;
+
+ mutex_lock(&wm->codec_mutex);
+ reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+
+ if (status & WM97XX_GPIO_HIGH)
+ reg |= gpio;
+ else
+ reg &= ~gpio;
+
+ if (wm->id == WM9712_ID2)
+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
+ else
+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
+ mutex_unlock(&wm->codec_mutex);
+}
+EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
+
+/*
+ * Codec GPIO pin configuration, this sets pin direction, polarity,
+ * stickyness and wake up.
+ */
+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
+ enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky,
+ enum wm97xx_gpio_wake wake)
+{
+ u16 reg;
+
+ mutex_lock(&wm->codec_mutex);
+ reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+
+ if (pol == WM97XX_GPIO_POL_HIGH)
+ reg |= gpio;
+ else
+ reg &= ~gpio;
+
+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg);
+ reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
+
+ if (sticky == WM97XX_GPIO_STICKY)
+ reg |= gpio;
+ else
+ reg &= ~gpio;
+
+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg);
+ reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
+
+ if (wake == WM97XX_GPIO_WAKE)
+ reg |= gpio;
+ else
+ reg &= ~gpio;
+
+ wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg);
+ reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+
+ if (dir == WM97XX_GPIO_IN)
+ reg |= gpio;
+ else
+ reg &= ~gpio;
+
+ wm97xx_reg_write(wm, AC97_GPIO_CFG, reg);
+ mutex_unlock(&wm->codec_mutex);
+}
+EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
+
+/*
+ * Configure the WM97XX_PRP value to use while system is suspended.
+ * If a value other than 0 is set then WM97xx pen detection will be
+ * left enabled in the configured mode while the system is in suspend,
+ * the device has users and suspend has not been disabled via the
+ * wakeup sysfs entries.
+ *
+ * @wm: WM97xx device to configure
+ * @mode: WM97XX_PRP value to configure while suspended
+ */
+void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode)
+{
+ wm->suspend_mode = mode;
+ device_init_wakeup(&wm->input_dev->dev, mode != 0);
+}
+EXPORT_SYMBOL_GPL(wm97xx_set_suspend_mode);
+
+/*
+ * Handle a pen down interrupt.
+ */
+static void wm97xx_pen_irq_worker(struct work_struct *work)
+{
+ struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work);
+ int pen_was_down = wm->pen_is_down;
+
+ /* do we need to enable the touch panel reader */
+ if (wm->id == WM9705_ID2) {
+ if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) &
+ WM97XX_PEN_DOWN)
+ wm->pen_is_down = 1;
+ else
+ wm->pen_is_down = 0;
+ } else {
+ u16 status, pol;
+ mutex_lock(&wm->codec_mutex);
+ status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+ pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+
+ if (WM97XX_GPIO_13 & pol & status) {
+ wm->pen_is_down = 1;
+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol &
+ ~WM97XX_GPIO_13);
+ } else {
+ wm->pen_is_down = 0;
+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol |
+ WM97XX_GPIO_13);
+ }
+
+ if (wm->id == WM9712_ID2)
+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
+ ~WM97XX_GPIO_13) << 1);
+ else
+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, status &
+ ~WM97XX_GPIO_13);
+ mutex_unlock(&wm->codec_mutex);
+ }
+
+ /* If the system is not using continuous mode or it provides a
+ * pen down operation then we need to schedule polls while the
+ * pen is down. Otherwise the machine driver is responsible
+ * for scheduling reads.
+ */
+ if (!wm->mach_ops->acc_enabled || wm->mach_ops->acc_pen_down) {
+ if (wm->pen_is_down && !pen_was_down) {
+ /* Data is not availiable immediately on pen down */
+ queue_delayed_work(wm->ts_workq, &wm->ts_reader, 1);
+ }
+
+ /* Let ts_reader report the pen up for debounce. */
+ if (!wm->pen_is_down && pen_was_down)
+ wm->pen_is_down = 1;
+ }
+
+ if (!wm->pen_is_down && wm->mach_ops->acc_enabled)
+ wm->mach_ops->acc_pen_up(wm);
+
+ wm->mach_ops->irq_enable(wm, 1);
+}
+
+/*
+ * Codec PENDOWN irq handler
+ *
+ * We have to disable the codec interrupt in the handler because it
+ * can take upto 1ms to clear the interrupt source. We schedule a task
+ * in a work queue to do the actual interaction with the chip. The
+ * interrupt is then enabled again in the slow handler when the source
+ * has been cleared.
+ */
+static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
+{
+ struct wm97xx *wm = dev_id;
+
+ if (!work_pending(&wm->pen_event_work)) {
+ wm->mach_ops->irq_enable(wm, 0);
+ queue_work(wm->ts_workq, &wm->pen_event_work);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * initialise pen IRQ handler and workqueue
+ */
+static int wm97xx_init_pen_irq(struct wm97xx *wm)
+{
+ u16 reg;
+
+ /* If an interrupt is supplied an IRQ enable operation must also be
+ * provided. */
+ BUG_ON(!wm->mach_ops->irq_enable);
+
+ if (request_irq(wm->pen_irq, wm97xx_pen_interrupt,
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ "wm97xx-pen", wm)) {
+ dev_err(wm->dev,
+ "Failed to register pen down interrupt, polling");
+ wm->pen_irq = 0;
+ return -EINVAL;
+ }
+
+ /* Configure GPIO as interrupt source on WM971x */
+ if (wm->id != WM9705_ID2) {
+ BUG_ON(!wm->mach_ops->irq_gpio);
+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
+ wm97xx_reg_write(wm, AC97_MISC_AFE,
+ reg & ~(wm->mach_ops->irq_gpio));
+ reg = wm97xx_reg_read(wm, 0x5a);
+ wm97xx_reg_write(wm, 0x5a, reg & ~0x0001);
+ }
+
+ return 0;
+}
+
+static int wm97xx_read_samples(struct wm97xx *wm)
+{
+ struct wm97xx_data data;
+ int rc;
+
+ mutex_lock(&wm->codec_mutex);
+
+ if (wm->mach_ops && wm->mach_ops->acc_enabled)
+ rc = wm->mach_ops->acc_pen_down(wm);
+ else
+ rc = wm->codec->poll_touch(wm, &data);
+
+ if (rc & RC_PENUP) {
+ if (wm->pen_is_down) {
+ wm->pen_is_down = 0;
+ dev_dbg(wm->dev, "pen up\n");
+ input_report_abs(wm->input_dev, ABS_PRESSURE, 0);
+ input_sync(wm->input_dev);
+ } else if (!(rc & RC_AGAIN)) {
+ /* We need high frequency updates only while
+ * pen is down, the user never will be able to
+ * touch screen faster than a few times per
+ * second... On the other hand, when the user
+ * is actively working with the touchscreen we
+ * don't want to lose the quick response. So we
+ * will slowly increase sleep time after the
+ * pen is up and quicky restore it to ~one task
+ * switch when pen is down again.
+ */
+ if (wm->ts_reader_interval < HZ / 10)
+ wm->ts_reader_interval++;
+ }
+
+ } else if (rc & RC_VALID) {
+ dev_dbg(wm->dev,
+ "pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
+ data.x >> 12, data.x & 0xfff, data.y >> 12,
+ data.y & 0xfff, data.p >> 12, data.p & 0xfff);
+ input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
+ input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
+ input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
+ input_sync(wm->input_dev);
+ wm->pen_is_down = 1;
+ wm->ts_reader_interval = wm->ts_reader_min_interval;
+ } else if (rc & RC_PENDOWN) {
+ dev_dbg(wm->dev, "pen down\n");
+ wm->pen_is_down = 1;
+ wm->ts_reader_interval = wm->ts_reader_min_interval;
+ }
+
+ mutex_unlock(&wm->codec_mutex);
+ return rc;
+}
+
+/*
+* The touchscreen sample reader.
+*/
+static void wm97xx_ts_reader(struct work_struct *work)
+{
+ int rc;
+ struct wm97xx *wm = container_of(work, struct wm97xx, ts_reader.work);
+
+ BUG_ON(!wm->codec);
+
+ do {
+ rc = wm97xx_read_samples(wm);
+ } while (rc & RC_AGAIN);
+
+ if (wm->pen_is_down || !wm->pen_irq)
+ queue_delayed_work(wm->ts_workq, &wm->ts_reader,
+ wm->ts_reader_interval);
+}
+
+/**
+ * wm97xx_ts_input_open - Open the touch screen input device.
+ * @idev: Input device to be opened.
+ *
+ * Called by the input sub system to open a wm97xx touchscreen device.
+ * Starts the touchscreen thread and touch digitiser.
+ */
+static int wm97xx_ts_input_open(struct input_dev *idev)
+{
+ struct wm97xx *wm = input_get_drvdata(idev);
+
+ wm->ts_workq = create_singlethread_workqueue("kwm97xx");
+ if (wm->ts_workq == NULL) {
+ dev_err(wm->dev,
+ "Failed to create workqueue\n");
+ return -EINVAL;
+ }
+
+ /* start digitiser */
+ if (wm->mach_ops && wm->mach_ops->acc_enabled)
+ wm->codec->acc_enable(wm, 1);
+ wm->codec->dig_enable(wm, 1);
+
+ INIT_DELAYED_WORK(&wm->ts_reader, wm97xx_ts_reader);
+ INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker);
+
+ wm->ts_reader_min_interval = HZ >= 100 ? HZ / 100 : 1;
+ if (wm->ts_reader_min_interval < 1)
+ wm->ts_reader_min_interval = 1;
+ wm->ts_reader_interval = wm->ts_reader_min_interval;
+
+ wm->pen_is_down = 0;
+ if (wm->pen_irq)
+ wm97xx_init_pen_irq(wm);
+ else
+ dev_err(wm->dev, "No IRQ specified\n");
+
+ /* If we either don't have an interrupt for pen down events or
+ * failed to acquire it then we need to poll.
+ */
+ if (wm->pen_irq == 0)
+ queue_delayed_work(wm->ts_workq, &wm->ts_reader,
+ wm->ts_reader_interval);
+
+ return 0;
+}
+
+/**
+ * wm97xx_ts_input_close - Close the touch screen input device.
+ * @idev: Input device to be closed.
+ *
+ * Called by the input sub system to close a wm97xx touchscreen
+ * device. Kills the touchscreen thread and stops the touch
+ * digitiser.
+ */
+
+static void wm97xx_ts_input_close(struct input_dev *idev)
+{
+ struct wm97xx *wm = input_get_drvdata(idev);
+ u16 reg;
+
+ if (wm->pen_irq) {
+ /* Return the interrupt to GPIO usage (disabling it) */
+ if (wm->id != WM9705_ID2) {
+ BUG_ON(!wm->mach_ops->irq_gpio);
+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
+ wm97xx_reg_write(wm, AC97_MISC_AFE,
+ reg | wm->mach_ops->irq_gpio);
+ }
+
+ free_irq(wm->pen_irq, wm);
+ }
+
+ wm->pen_is_down = 0;
+
+ /* Balance out interrupt disables/enables */
+ if (cancel_work_sync(&wm->pen_event_work))
+ wm->mach_ops->irq_enable(wm, 1);
+
+ /* ts_reader rearms itself so we need to explicitly stop it
+ * before we destroy the workqueue.
+ */
+ cancel_delayed_work_sync(&wm->ts_reader);
+
+ destroy_workqueue(wm->ts_workq);
+
+ /* stop digitiser */
+ wm->codec->dig_enable(wm, 0);
+ if (wm->mach_ops && wm->mach_ops->acc_enabled)
+ wm->codec->acc_enable(wm, 0);
+}
+
+static int wm97xx_probe(struct device *dev)
+{
+ struct wm97xx *wm;
+ int ret = 0, id = 0;
+
+ wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL);
+ if (!wm)
+ return -ENOMEM;
+ mutex_init(&wm->codec_mutex);
+
+ wm->dev = dev;
+ dev->driver_data = wm;
+ wm->ac97 = to_ac97_t(dev);
+
+ /* check that we have a supported codec */
+ id = wm97xx_reg_read(wm, AC97_VENDOR_ID1);
+ if (id != WM97XX_ID1) {
+ dev_err(dev, "Device with vendor %04x is not a wm97xx\n", id);
+ ret = -ENODEV;
+ goto alloc_err;
+ }
+
+ wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
+
+ dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff);
+
+ switch (wm->id & 0xff) {
+#ifdef CONFIG_TOUCHSCREEN_WM9705
+ case 0x05:
+ wm->codec = &wm9705_codec;
+ break;
+#endif
+#ifdef CONFIG_TOUCHSCREEN_WM9712
+ case 0x12:
+ wm->codec = &wm9712_codec;
+ break;
+#endif
+#ifdef CONFIG_TOUCHSCREEN_WM9713
+ case 0x13:
+ wm->codec = &wm9713_codec;
+ break;
+#endif
+ default:
+ dev_err(wm->dev, "Support for wm97%02x not compiled in.\n",
+ wm->id & 0xff);
+ ret = -ENODEV;
+ goto alloc_err;
+ }
+
+ wm->input_dev = input_allocate_device();
+ if (wm->input_dev == NULL) {
+ ret = -ENOMEM;
+ goto alloc_err;
+ }
+
+ /* set up touch configuration */
+ wm->input_dev->name = "wm97xx touchscreen";
+ wm->input_dev->open = wm97xx_ts_input_open;
+ wm->input_dev->close = wm97xx_ts_input_close;
+ set_bit(EV_ABS, wm->input_dev->evbit);
+ set_bit(ABS_X, wm->input_dev->absbit);
+ set_bit(ABS_Y, wm->input_dev->absbit);
+ set_bit(ABS_PRESSURE, wm->input_dev->absbit);
+ input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1],
+ abs_x[2], 0);
+ input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1],
+ abs_y[2], 0);
+ input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1],
+ abs_p[2], 0);
+ input_set_drvdata(wm->input_dev, wm);
+ wm->input_dev->dev.parent = dev;
+ ret = input_register_device(wm->input_dev);
+ if (ret < 0)
+ goto dev_alloc_err;
+
+ /* set up physical characteristics */
+ wm->codec->phy_init(wm);
+
+ /* load gpio cache */
+ wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+ wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+ wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
+ wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
+ wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+ wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
+
+ /* register our battery device */
+ wm->battery_dev = platform_device_alloc("wm97xx-battery", -1);
+ if (!wm->battery_dev) {
+ ret = -ENOMEM;
+ goto batt_err;
+ }
+ platform_set_drvdata(wm->battery_dev, wm);
+ wm->battery_dev->dev.parent = dev;
+ ret = platform_device_add(wm->battery_dev);
+ if (ret < 0)
+ goto batt_reg_err;
+
+ /* register our extended touch device (for machine specific
+ * extensions) */
+ wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
+ if (!wm->touch_dev) {
+ ret = -ENOMEM;
+ goto touch_err;
+ }
+ platform_set_drvdata(wm->touch_dev, wm);
+ wm->touch_dev->dev.parent = dev;
+ ret = platform_device_add(wm->touch_dev);
+ if (ret < 0)
+ goto touch_reg_err;
+
+ return ret;
+
+ touch_reg_err:
+ platform_device_put(wm->touch_dev);
+ touch_err:
+ platform_device_unregister(wm->battery_dev);
+ wm->battery_dev = NULL;
+ batt_reg_err:
+ platform_device_put(wm->battery_dev);
+ batt_err:
+ input_unregister_device(wm->input_dev);
+ wm->input_dev = NULL;
+ dev_alloc_err:
+ input_free_device(wm->input_dev);
+ alloc_err:
+ kfree(wm);
+
+ return ret;
+}
+
+static int wm97xx_remove(struct device *dev)
+{
+ struct wm97xx *wm = dev_get_drvdata(dev);
+
+ platform_device_unregister(wm->battery_dev);
+ platform_device_unregister(wm->touch_dev);
+ input_unregister_device(wm->input_dev);
+ kfree(wm);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm97xx_suspend(struct device *dev, pm_message_t state)
+{
+ struct wm97xx *wm = dev_get_drvdata(dev);
+ u16 reg;
+ int suspend_mode;
+
+ if (device_may_wakeup(&wm->input_dev->dev))
+ suspend_mode = wm->suspend_mode;
+ else
+ suspend_mode = 0;
+
+ if (wm->input_dev->users)
+ cancel_delayed_work_sync(&wm->ts_reader);
+
+ /* Power down the digitiser (bypassing the cache for resume) */
+ reg = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER2);
+ reg &= ~WM97XX_PRP_DET_DIG;
+ if (wm->input_dev->users)
+ reg |= suspend_mode;
+ wm->ac97->bus->ops->write(wm->ac97, AC97_WM97XX_DIGITISER2, reg);
+
+ /* WM9713 has an additional power bit - turn it off if there
+ * are no users or if suspend mode is zero. */
+ if (wm->id == WM9713_ID2 &&
+ (!wm->input_dev->users || !suspend_mode)) {
+ reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000;
+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
+ }
+
+ return 0;
+}
+
+static int wm97xx_resume(struct device *dev)
+{
+ struct wm97xx *wm = dev_get_drvdata(dev);
+
+ /* restore digitiser and gpios */
+ if (wm->id == WM9713_ID2) {
+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
+ wm97xx_reg_write(wm, 0x5a, wm->misc);
+ if (wm->input_dev->users) {
+ u16 reg;
+ reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff;
+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
+ }
+ }
+
+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]);
+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]);
+
+ wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]);
+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]);
+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]);
+ wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]);
+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]);
+ wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]);
+
+ if (wm->input_dev->users && !wm->pen_irq) {
+ wm->ts_reader_interval = wm->ts_reader_min_interval;
+ queue_delayed_work(wm->ts_workq, &wm->ts_reader,
+ wm->ts_reader_interval);
+ }
+
+ return 0;
+}
+
+#else
+#define wm97xx_suspend NULL
+#define wm97xx_resume NULL
+#endif
+
+/*
+ * Machine specific operations
+ */
+int wm97xx_register_mach_ops(struct wm97xx *wm,
+ struct wm97xx_mach_ops *mach_ops)
+{
+ mutex_lock(&wm->codec_mutex);
+ if (wm->mach_ops) {
+ mutex_unlock(&wm->codec_mutex);
+ return -EINVAL;
+ }
+ wm->mach_ops = mach_ops;
+ mutex_unlock(&wm->codec_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops);
+
+void wm97xx_unregister_mach_ops(struct wm97xx *wm)
+{
+ mutex_lock(&wm->codec_mutex);
+ wm->mach_ops = NULL;
+ mutex_unlock(&wm->codec_mutex);
+}
+EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
+
+static struct device_driver wm97xx_driver = {
+ .name = "ac97",
+ .bus = &ac97_bus_type,
+ .owner = THIS_MODULE,
+ .probe = wm97xx_probe,
+ .remove = wm97xx_remove,
+ .suspend = wm97xx_suspend,
+ .resume = wm97xx_resume,
+};
+
+static int __init wm97xx_init(void)
+{
+ return driver_register(&wm97xx_driver);
+}
+
+static void __exit wm97xx_exit(void)
+{
+ driver_unregister(&wm97xx_driver);
+}
+
+module_init(wm97xx_init);
+module_exit(wm97xx_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
new file mode 100644
index 000000000000..0f47f4697cdf
--- /dev/null
+++ b/drivers/input/xen-kbdfront.c
@@ -0,0 +1,340 @@
+/*
+ * Xen para-virtual input device
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * Based on linux/drivers/input/mouse/sermouse.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+/*
+ * TODO:
+ *
+ * Switch to grant tables together with xen-fbfront.c.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/interface/io/kbdif.h>
+#include <xen/xenbus.h>
+
+struct xenkbd_info {
+ struct input_dev *kbd;
+ struct input_dev *ptr;
+ struct xenkbd_page *page;
+ int irq;
+ struct xenbus_device *xbdev;
+ char phys[32];
+};
+
+static int xenkbd_remove(struct xenbus_device *);
+static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
+static void xenkbd_disconnect_backend(struct xenkbd_info *);
+
+/*
+ * Note: if you need to send out events, see xenfb_do_update() for how
+ * to do that.
+ */
+
+static irqreturn_t input_handler(int rq, void *dev_id)
+{
+ struct xenkbd_info *info = dev_id;
+ struct xenkbd_page *page = info->page;
+ __u32 cons, prod;
+
+ prod = page->in_prod;
+ if (prod == page->in_cons)
+ return IRQ_HANDLED;
+ rmb(); /* ensure we see ring contents up to prod */
+ for (cons = page->in_cons; cons != prod; cons++) {
+ union xenkbd_in_event *event;
+ struct input_dev *dev;
+ event = &XENKBD_IN_RING_REF(page, cons);
+
+ dev = info->ptr;
+ switch (event->type) {
+ case XENKBD_TYPE_MOTION:
+ input_report_rel(dev, REL_X, event->motion.rel_x);
+ input_report_rel(dev, REL_Y, event->motion.rel_y);
+ break;
+ case XENKBD_TYPE_KEY:
+ dev = NULL;
+ if (test_bit(event->key.keycode, info->kbd->keybit))
+ dev = info->kbd;
+ if (test_bit(event->key.keycode, info->ptr->keybit))
+ dev = info->ptr;
+ if (dev)
+ input_report_key(dev, event->key.keycode,
+ event->key.pressed);
+ else
+ printk(KERN_WARNING
+ "xenkbd: unhandled keycode 0x%x\n",
+ event->key.keycode);
+ break;
+ case XENKBD_TYPE_POS:
+ input_report_abs(dev, ABS_X, event->pos.abs_x);
+ input_report_abs(dev, ABS_Y, event->pos.abs_y);
+ break;
+ }
+ if (dev)
+ input_sync(dev);
+ }
+ mb(); /* ensure we got ring contents */
+ page->in_cons = cons;
+ notify_remote_via_irq(info->irq);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit xenkbd_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int ret, i;
+ struct xenkbd_info *info;
+ struct input_dev *kbd, *ptr;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+ return -ENOMEM;
+ }
+ dev->dev.driver_data = info;
+ info->xbdev = dev;
+ info->irq = -1;
+ snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
+
+ info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+ if (!info->page)
+ goto error_nomem;
+
+ /* keyboard */
+ kbd = input_allocate_device();
+ if (!kbd)
+ goto error_nomem;
+ kbd->name = "Xen Virtual Keyboard";
+ kbd->phys = info->phys;
+ kbd->id.bustype = BUS_PCI;
+ kbd->id.vendor = 0x5853;
+ kbd->id.product = 0xffff;
+ kbd->evbit[0] = BIT(EV_KEY);
+ for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
+ set_bit(i, kbd->keybit);
+ for (i = KEY_OK; i < KEY_MAX; i++)
+ set_bit(i, kbd->keybit);
+
+ ret = input_register_device(kbd);
+ if (ret) {
+ input_free_device(kbd);
+ xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
+ goto error;
+ }
+ info->kbd = kbd;
+
+ /* pointing device */
+ ptr = input_allocate_device();
+ if (!ptr)
+ goto error_nomem;
+ ptr->name = "Xen Virtual Pointer";
+ ptr->phys = info->phys;
+ ptr->id.bustype = BUS_PCI;
+ ptr->id.vendor = 0x5853;
+ ptr->id.product = 0xfffe;
+ ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
+ for (i = BTN_LEFT; i <= BTN_TASK; i++)
+ set_bit(i, ptr->keybit);
+ ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
+ input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
+
+ ret = input_register_device(ptr);
+ if (ret) {
+ input_free_device(ptr);
+ xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
+ goto error;
+ }
+ info->ptr = ptr;
+
+ ret = xenkbd_connect_backend(dev, info);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+ error_nomem:
+ ret = -ENOMEM;
+ xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+ xenkbd_remove(dev);
+ return ret;
+}
+
+static int xenkbd_resume(struct xenbus_device *dev)
+{
+ struct xenkbd_info *info = dev->dev.driver_data;
+
+ xenkbd_disconnect_backend(info);
+ memset(info->page, 0, PAGE_SIZE);
+ return xenkbd_connect_backend(dev, info);
+}
+
+static int xenkbd_remove(struct xenbus_device *dev)
+{
+ struct xenkbd_info *info = dev->dev.driver_data;
+
+ xenkbd_disconnect_backend(info);
+ if (info->kbd)
+ input_unregister_device(info->kbd);
+ if (info->ptr)
+ input_unregister_device(info->ptr);
+ free_page((unsigned long)info->page);
+ kfree(info);
+ return 0;
+}
+
+static int xenkbd_connect_backend(struct xenbus_device *dev,
+ struct xenkbd_info *info)
+{
+ int ret, evtchn;
+ struct xenbus_transaction xbt;
+
+ ret = xenbus_alloc_evtchn(dev, &evtchn);
+ if (ret)
+ return ret;
+ ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
+ 0, dev->devicetype, info);
+ if (ret < 0) {
+ xenbus_free_evtchn(dev, evtchn);
+ xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+ return ret;
+ }
+ info->irq = ret;
+
+ again:
+ ret = xenbus_transaction_start(&xbt);
+ if (ret) {
+ xenbus_dev_fatal(dev, ret, "starting transaction");
+ return ret;
+ }
+ ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+ virt_to_mfn(info->page));
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+ evtchn);
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_transaction_end(xbt, 0);
+ if (ret) {
+ if (ret == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, ret, "completing transaction");
+ return ret;
+ }
+
+ xenbus_switch_state(dev, XenbusStateInitialised);
+ return 0;
+
+ error_xenbus:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(dev, ret, "writing xenstore");
+ return ret;
+}
+
+static void xenkbd_disconnect_backend(struct xenkbd_info *info)
+{
+ if (info->irq >= 0)
+ unbind_from_irqhandler(info->irq, info);
+ info->irq = -1;
+}
+
+static void xenkbd_backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct xenkbd_info *info = dev->dev.driver_data;
+ int ret, val;
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitialised:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateInitWait:
+InitWait:
+ ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+ "feature-abs-pointer", "%d", &val);
+ if (ret < 0)
+ val = 0;
+ if (val) {
+ ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
+ "request-abs-pointer", "1");
+ if (ret)
+ printk(KERN_WARNING
+ "xenkbd: can't request abs-pointer");
+ }
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateConnected:
+ /*
+ * Work around xenbus race condition: If backend goes
+ * through InitWait to Connected fast enough, we can
+ * get Connected twice here.
+ */
+ if (dev->state != XenbusStateConnected)
+ goto InitWait; /* no InitWait seen yet, fudge it */
+ break;
+
+ case XenbusStateClosing:
+ xenbus_frontend_closed(dev);
+ break;
+ }
+}
+
+static struct xenbus_device_id xenkbd_ids[] = {
+ { "vkbd" },
+ { "" }
+};
+
+static struct xenbus_driver xenkbd = {
+ .name = "vkbd",
+ .owner = THIS_MODULE,
+ .ids = xenkbd_ids,
+ .probe = xenkbd_probe,
+ .remove = xenkbd_remove,
+ .resume = xenkbd_resume,
+ .otherend_changed = xenkbd_backend_changed,
+};
+
+static int __init xenkbd_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ /* Nothing to do if running in dom0. */
+ if (is_initial_xendomain())
+ return -ENODEV;
+
+ return xenbus_register_frontend(&xenkbd);
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+ xenbus_unregister_driver(&xenkbd);
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 23ae66c76d47..24c6b7ca62be 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -350,7 +350,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci)
if (ncci == 0xffffffff || np->ncci == ncci) {
*pp = (*pp)->next;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- if ((mp = np->minorp) != 0) {
+ if ((mp = np->minorp) != NULL) {
#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
capifs_free_ncci(mp->minor);
#endif
@@ -366,7 +366,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci)
}
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
kfree(np);
- if (*pp == 0) return;
+ if (*pp == NULL) return;
} else {
pp = &(*pp)->next;
}
@@ -483,7 +483,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
#endif
goto bad;
}
- if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+ if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
goto bad;
}
@@ -512,7 +512,7 @@ bad:
static void handle_minor_recv(struct capiminor *mp)
{
struct sk_buff *skb;
- while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
+ while ((skb = skb_dequeue(&mp->inqueue)) != NULL) {
unsigned int len = skb->len;
mp->inbytes -= len;
if (handle_recv_skb(mp, skb) < 0) {
@@ -538,7 +538,7 @@ static int handle_minor_send(struct capiminor *mp)
return 0;
}
- while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
+ while ((skb = skb_dequeue(&mp->outqueue)) != NULL) {
datahandle = mp->datahandle;
len = (u16)skb->len;
skb_push(skb, CAPI_DATA_B3_REQ_LEN);
@@ -689,19 +689,19 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (!cdev->ap.applid)
return -ENODEV;
- if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
+ if ((skb = skb_dequeue(&cdev->recvqueue)) == NULL) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
for (;;) {
interruptible_sleep_on(&cdev->recvwait);
- if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
+ if ((skb = skb_dequeue(&cdev->recvqueue)) != NULL)
break;
if (signal_pending(current))
break;
}
- if (skb == 0)
+ if (skb == NULL)
return -ERESTARTNOHAND;
}
if (skb->len > count) {
@@ -940,12 +940,12 @@ capi_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
mutex_lock(&cdev->ncci_list_mtx);
- if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) {
+ if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) {
mutex_unlock(&cdev->ncci_list_mtx);
return 0;
}
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- if ((mp = nccip->minorp) != 0) {
+ if ((mp = nccip->minorp) != NULL) {
count += atomic_read(&mp->ttyopencount);
}
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -966,7 +966,7 @@ capi_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
mutex_lock(&cdev->ncci_list_mtx);
nccip = capincci_find(cdev, (u32) ncci);
- if (!nccip || (mp = nccip->minorp) == 0) {
+ if (!nccip || (mp = nccip->minorp) == NULL) {
mutex_unlock(&cdev->ncci_list_mtx);
return -ESRCH;
}
@@ -986,7 +986,7 @@ capi_open(struct inode *inode, struct file *file)
if (file->private_data)
return -EEXIST;
- if ((file->private_data = capidev_alloc()) == 0)
+ if ((file->private_data = capidev_alloc()) == NULL)
return -ENOMEM;
return nonseekable_open(inode, file);
@@ -1023,9 +1023,9 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
struct capiminor *mp;
unsigned long flags;
- if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
+ if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == NULL)
return -ENXIO;
- if (mp->nccip == 0)
+ if (mp->nccip == NULL)
return -ENXIO;
tty->driver_data = (void *)mp;
@@ -1058,7 +1058,7 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file)
#ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
#endif
- if (mp->nccip == 0)
+ if (mp->nccip == NULL)
capiminor_free(mp);
}
@@ -1526,9 +1526,9 @@ static int __init capi_init(void)
char *compileinfo;
int major_ret;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index cb42b690b45e..d5b4cc357a3c 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -335,7 +335,7 @@ static capidrv_plci *new_plci(capidrv_contr * card, int chan)
plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
- if (plcip == 0)
+ if (plcip == NULL)
return NULL;
plcip->state = ST_PLCI_NONE;
@@ -404,7 +404,7 @@ static inline capidrv_ncci *new_ncci(capidrv_contr * card,
nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
- if (nccip == 0)
+ if (nccip == NULL)
return NULL;
nccip->ncci = ncci;
@@ -426,7 +426,7 @@ static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci)
capidrv_plci *plcip;
capidrv_ncci *p;
- if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
+ if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
return NULL;
for (p = plcip->ncci_list; p; p = p->next)
@@ -441,7 +441,7 @@ static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
capidrv_plci *plcip;
capidrv_ncci *p;
- if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
+ if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
return NULL;
for (p = plcip->ncci_list; p; p = p->next)
@@ -755,7 +755,7 @@ static inline int new_bchan(capidrv_contr * card)
{
int i;
for (i = 0; i < card->nbchan; i++) {
- if (card->bchans[i].plcip == 0) {
+ if (card->bchans[i].plcip == NULL) {
card->bchans[i].disconnecting = 0;
return i;
}
@@ -877,7 +877,7 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
return;
}
bchan = &card->bchans[chan];
- if ((plcip = new_plci(card, chan)) == 0) {
+ if ((plcip = new_plci(card, chan)) == NULL) {
printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
return;
}
@@ -1388,12 +1388,12 @@ static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
_cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
if (cdb) {
- printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__,
+ printk(KERN_DEBUG "%s: applid=%d %s\n", __func__,
ap->applid, cdb->buf);
cdebbuf_free(cdb);
} else
printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
- __FUNCTION__, ap->applid,
+ __func__, ap->applid,
capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
}
if (s_cmsg.Command == CAPI_DATA_B3
@@ -1661,7 +1661,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
NULL, /* Useruserdata */
NULL /* Facilitydataarray */
);
- if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
+ if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) {
cmd.command = ISDN_STAT_DHUP;
cmd.driver = card->myid;
cmd.arg = (c->arg % card->nbchan);
@@ -1966,7 +1966,7 @@ static void enable_dchannel_trace(capidrv_contr *card)
card->name, errcode);
return;
}
- if (strstr(manufacturer, "AVM") == 0) {
+ if (strstr(manufacturer, "AVM") == NULL) {
printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
card->name, manufacturer);
return;
@@ -2291,10 +2291,10 @@ static int __init capidrv_init(void)
u32 ncontr, contr;
u16 errcode;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strncpy(rev, p + 2, sizeof(rev));
rev[sizeof(rev)-1] = 0;
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
@@ -2335,10 +2335,10 @@ static void __exit capidrv_exit(void)
char rev[32];
char *p;
- if ((p = strchr(revision, ':')) != 0) {
+ if ((p = strchr(revision, ':')) != NULL) {
strncpy(rev, p + 1, sizeof(rev));
rev[sizeof(rev)-1] = 0;
- if ((p = strchr(rev, '$')) != 0)
+ if ((p = strchr(rev, '$')) != NULL)
*p = 0;
} else {
strcpy(rev, " ??? ");
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 6d7c47ec0367..550e80f390a6 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -69,6 +69,7 @@ static int capifs_remount(struct super_block *s, int *flags, char *data)
} else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
mode = n & ~S_IFMT;
else {
+ kfree(new_opt);
printk("capifs: called with bogus options\n");
return -EINVAL;
}
@@ -189,9 +190,9 @@ static int __init capifs_init(void)
char *p;
int err;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c
index 68409d971e73..fcaa1241ee77 100644
--- a/drivers/isdn/capi/capilib.c
+++ b/drivers/isdn/capi/capilib.c
@@ -4,7 +4,7 @@
#include <linux/isdn/capilli.h>
#define DBG(format, arg...) do { \
-printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
} while (0)
struct capilib_msgidqueue {
@@ -44,7 +44,7 @@ static inline void mq_init(struct capilib_ncci * np)
static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid)
{
struct capilib_msgidqueue *mq;
- if ((mq = np->msgidfree) == 0)
+ if ((mq = np->msgidfree) == NULL)
return 0;
np->msgidfree = mq->next;
mq->msgid = msgid;
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index 22379b94e88f..ebef4ce1b00c 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -450,7 +450,7 @@ static void pars_2_message(_cmsg * cmsg)
cmsg->l += 4;
break;
case _CSTRUCT:
- if (*(u8 **) OFF == 0) {
+ if (*(u8 **) OFF == NULL) {
*(cmsg->m + cmsg->l) = '\0';
cmsg->l++;
} else if (**(_cstruct *) OFF != 0xff) {
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index f55531869313..75726ea0fbbd 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -10,7 +10,7 @@
*
*/
-#define CONFIG_AVMB1_COMPAT
+#define AVMB1_COMPAT
#include "kcapi.h"
#include <linux/module.h>
@@ -29,7 +29,7 @@
#include <asm/uaccess.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
-#ifdef CONFIG_AVMB1_COMPAT
+#ifdef AVMB1_COMPAT
#include <linux/b1lli.h>
#endif
#include <linux/mutex.h>
@@ -154,7 +154,7 @@ static void register_appl(struct capi_ctr *card, u16 applid, capi_register_param
if (card)
card->register_appl(card, applid, rparam);
else
- printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: cannot get card resources\n", __func__);
}
@@ -178,7 +178,7 @@ static void notify_up(u32 contr)
printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
}
if (!card) {
- printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr);
+ printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
return;
}
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
@@ -740,7 +740,7 @@ u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
EXPORT_SYMBOL(capi20_get_profile);
-#ifdef CONFIG_AVMB1_COMPAT
+#ifdef AVMB1_COMPAT
static int old_capi_manufacturer(unsigned int cmd, void __user *data)
{
avmb1_loadandconfigdef ldef;
@@ -826,7 +826,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
card = capi_ctr_get(card);
if (!card)
return -ESRCH;
- if (card->load_firmware == 0) {
+ if (card->load_firmware == NULL) {
printk(KERN_DEBUG "kcapi: load: no load function\n");
return -ESRCH;
}
@@ -835,7 +835,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
return -EINVAL;
}
- if (ldef.t4file.data == 0) {
+ if (ldef.t4file.data == NULL) {
printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
return -EINVAL;
}
@@ -904,7 +904,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
struct capi_ctr *card;
switch (cmd) {
-#ifdef CONFIG_AVMB1_COMPAT
+#ifdef AVMB1_COMPAT
case AVMB1_LOAD:
case AVMB1_LOAD_AND_CONFIG:
case AVMB1_RESETCARD:
@@ -951,7 +951,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
if (strcmp(driver->name, cdef.driver) == 0)
break;
}
- if (driver == 0) {
+ if (driver == NULL) {
printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
cdef.driver);
return -ESRCH;
@@ -1004,9 +1004,9 @@ static int __init kcapi_init(void)
return ret;
kcapi_proc_init();
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h
index 1cb2c40f9921..244711f7f838 100644
--- a/drivers/isdn/capi/kcapi.h
+++ b/drivers/isdn/capi/kcapi.h
@@ -17,7 +17,7 @@
#ifdef KCAPI_DEBUG
#define DBG(format, arg...) do { \
-printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
} while (0)
#else
#define DBG(format, arg...) /* */
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
index 4484a6417235..abf05ec31760 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -661,11 +661,11 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
len += sprintf(page+len, "%-16s %s\n", "type", s);
if (card->cardtype == avm_t1isa)
len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
- if ((s = cinfo->version[VER_DRIVER]) != 0)
+ if ((s = cinfo->version[VER_DRIVER]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
- if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
- if ((s = cinfo->version[VER_SERIAL]) != 0)
+ if ((s = cinfo->version[VER_SERIAL]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
@@ -788,9 +788,9 @@ static int __init b1_init(void)
char *p;
char rev[32];
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index 669f6f67449c..da34b98e3de7 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -883,11 +883,11 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
default: s = "???"; break;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
- if ((s = cinfo->version[VER_DRIVER]) != 0)
+ if ((s = cinfo->version[VER_DRIVER]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
- if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
- if ((s = cinfo->version[VER_SERIAL]) != 0)
+ if ((s = cinfo->version[VER_SERIAL]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
@@ -970,9 +970,9 @@ static int __init b1dma_init(void)
char *p;
char rev[32];
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
index 80fb488848b8..1e288eeb5e2a 100644
--- a/drivers/isdn/hardware/avm/b1isa.c
+++ b/drivers/isdn/hardware/avm/b1isa.c
@@ -203,9 +203,9 @@ static int __init b1isa_init(void)
char rev[32];
int i;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
index 90e2e6643d19..5b314a2c4049 100644
--- a/drivers/isdn/hardware/avm/b1pci.c
+++ b/drivers/isdn/hardware/avm/b1pci.c
@@ -382,9 +382,9 @@ static int __init b1pci_init(void)
char rev[32];
int err;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
index e479c0aef38d..7740403b40e1 100644
--- a/drivers/isdn/hardware/avm/b1pcmcia.c
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c
@@ -201,9 +201,9 @@ static int __init b1pcmcia_init(void)
char *p;
char rev[32];
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index 4bbbbe688077..9df1d3f66c87 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -1088,11 +1088,11 @@ static int c4_read_proc(char *page, char **start, off_t off,
default: s = "???"; break;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
- if ((s = cinfo->version[VER_DRIVER]) != 0)
+ if ((s = cinfo->version[VER_DRIVER]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
- if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
- if ((s = cinfo->version[VER_SERIAL]) != 0)
+ if ((s = cinfo->version[VER_SERIAL]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
@@ -1167,7 +1167,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
}
card->mbase = ioremap(card->membase, 128);
- if (card->mbase == 0) {
+ if (card->mbase == NULL) {
printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n",
card->membase);
retval = -EIO;
@@ -1291,9 +1291,9 @@ static int __init c4_init(void)
char rev[32];
int err;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
index 6130724e46e7..e7724493738c 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -551,9 +551,9 @@ static int __init t1isa_init(void)
char *p;
int i;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
index d1e253c94db4..e6d298d75146 100644
--- a/drivers/isdn/hardware/avm/t1pci.c
+++ b/drivers/isdn/hardware/avm/t1pci.c
@@ -233,9 +233,9 @@ static int __init t1pci_init(void)
char rev[32];
int err;
- if ((p = strchr(revision, ':')) != 0 && p[1]) {
+ if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
- if ((p = strchr(rev, '$')) != 0 && p > rev)
+ if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index 6d39f9360766..5fcbdccd7a53 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -393,7 +393,7 @@ void diva_free_dma_map(void *hdev, struct _diva_dma_map_entry *pmap)
dma_addr_t dma_handle;
void *addr_handle;
- for (i = 0; (pmap != 0); i++) {
+ for (i = 0; (pmap != NULL); i++) {
diva_get_dma_map_entry(pmap, i, &cpu_addr, &phys_addr);
if (!cpu_addr) {
break;
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 1ff98e7eb794..599fed88222d 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -742,7 +742,7 @@ static void start_internal_command (dword Id, PLCI *plci, t_std_internal_comma
else
{
i = 1;
- while (plci->internal_command_queue[i] != 0)
+ while (plci->internal_command_queue[i] != NULL)
i++;
plci->internal_command_queue[i] = command_function;
}
@@ -758,7 +758,7 @@ static void next_internal_command (dword Id, PLCI *plci)
plci->internal_command = 0;
plci->internal_command_queue[0] = NULL;
- while (plci->internal_command_queue[1] != 0)
+ while (plci->internal_command_queue[1] != NULL)
{
for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++)
plci->internal_command_queue[i] = plci->internal_command_queue[i+1];
@@ -9119,7 +9119,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho
dbug(1,dprintf("AdvSigPlci=0x%x",a->AdvSignalPLCI));
return 0x2001; /* codec in use by another application */
}
- if(plci!=0)
+ if(plci!=NULL)
{
a->AdvSignalPLCI = plci;
plci->tel=ADV_VOICE;
@@ -9144,7 +9144,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho
}
/* indicate D-ch connect if */
} /* codec is connected OK */
- if(plci!=0)
+ if(plci!=NULL)
{
a->AdvSignalPLCI = plci;
plci->tel=ADV_VOICE;
@@ -9170,7 +9170,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho
{
if(hook_listen) return 0x300B; /* Facility not supported */
/* no hook with SCOM */
- if(plci!=0) plci->tel = CODEC;
+ if(plci!=NULL) plci->tel = CODEC;
dbug(1,dprintf("S/SCOM codec"));
/* first time we use the scom-s codec we must shut down the internal */
/* handset application of the card. This can be done by an assign with */
@@ -14604,7 +14604,7 @@ static void channel_xmit_extended_xon (PLCI * plci) {
int max_ch = ARRAY_SIZE(a->ch_flow_control);
int i, one_requested = 0;
- if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) {
+ if ((!plci) || (!plci->Id) || ((a = plci->adapter) == NULL)) {
return;
}
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index b96f3184c2e5..1f879b500d83 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -344,7 +344,7 @@ setup_asuscom(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 0f1db1f669b2..7cabc5a19492 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -797,7 +797,7 @@ static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
err = pnp_activate_dev(pnp_avm_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
cs->hw.avm.cfg_reg =
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 2d670856d141..018bd293e580 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1088,7 +1088,7 @@ static int __devinit setup_diva_isapnp(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 2c3691fda300..aa29d1cf16af 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -937,7 +937,7 @@ setup_elsa_isapnp(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index f4a213877e35..d92e8d6c2ae2 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1417,7 +1417,7 @@ setup_hfcsx(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 98b0149bca68..8df889b0c1a9 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -905,7 +905,7 @@ rx_int_complete(struct urb *urb)
if (status) {
printk(KERN_INFO
"HFC-S USB: %s error resubmitting URB fifo(%d)\n",
- __FUNCTION__, fifon);
+ __func__, fifon);
}
}
@@ -1543,14 +1543,14 @@ hfc_usb_disconnect(struct usb_interface *intf)
stop_isoc_chain(&context->fifos[i]);
DBG(HFCUSB_DBG_INIT,
"HFC-S USB: %s stopping ISOC chain Fifo(%i)",
- __FUNCTION__, i);
+ __func__, i);
}
} else {
if (context->fifos[i].active > 0) {
context->fifos[i].active = 0;
DBG(HFCUSB_DBG_INIT,
"HFC-S USB: %s unlinking URB for Fifo(%i)",
- __FUNCTION__, i);
+ __func__, i);
}
usb_kill_urb(context->fifos[i].urb);
usb_free_urb(context->fifos[i].urb);
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 909d6709ec16..cf082665cc8b 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -193,7 +193,7 @@ setup_hfcs(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h
index ceafecdb1037..5ed3b1c44184 100644
--- a/drivers/isdn/hisax/hisax_debug.h
+++ b/drivers/isdn/hisax/hisax_debug.h
@@ -27,14 +27,14 @@
#define DBG(level, format, arg...) do { \
if (level & __debug_variable) \
-printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
+printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
} while (0)
#define DBG_PACKET(level,data,count) \
- if (level & __debug_variable) dump_packet(__FUNCTION__,data,count)
+ if (level & __debug_variable) dump_packet(__func__,data,count)
#define DBG_SKB(level,skb) \
- if ((level & __debug_variable) && skb) dump_packet(__FUNCTION__,skb->data,skb->len)
+ if ((level & __debug_variable) && skb) dump_packet(__func__,skb->data,skb->len)
static void __attribute__((unused))
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index 76043dedba5b..c0b4db2f8364 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -68,7 +68,7 @@ static struct pci_device_id fcpci_ids[] = {
MODULE_DEVICE_TABLE(pci, fcpci_ids);
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
static struct pnp_device_id fcpnp_ids[] __devinitdata = {
{
.id = "AVM0900",
@@ -914,7 +914,7 @@ static int __devinit fcpci_probe(struct pci_dev *pdev,
return retval;
}
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
{
struct fritz_adapter *adapter;
@@ -935,7 +935,7 @@ static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_i
pnp_disable_dev(pdev);
retval = pnp_activate_dev(pdev);
if (retval < 0) {
- printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
+ printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__,
(char *)dev_id->driver_data, retval);
goto err_free;
}
@@ -974,6 +974,8 @@ static struct pnp_driver fcpnp_driver = {
.remove = __devexit_p(fcpnp_remove),
.id_table = fcpnp_ids,
};
+#else
+static struct pnp_driver fcpnp_driver;
#endif
static void __devexit fcpci_remove(struct pci_dev *pdev)
@@ -1001,7 +1003,7 @@ static int __init hisax_fcpcipnp_init(void)
retval = pci_register_driver(&fcpci_driver);
if (retval)
return retval;
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
retval = pnp_register_driver(&fcpnp_driver);
if (retval < 0) {
pci_unregister_driver(&fcpci_driver);
@@ -1013,7 +1015,7 @@ static int __init hisax_fcpcipnp_init(void)
static void __exit hisax_fcpcipnp_exit(void)
{
-#ifdef __ISAPNP__
+#ifdef CONFIG_PNP
pnp_unregister_driver(&fcpnp_driver);
#endif
pci_unregister_driver(&fcpci_driver);
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index 2d18d4f1e57e..a92bf0d2cab2 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -252,7 +252,7 @@ setup_ix1micro(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 421b8e6763d7..ef00633e1d2a 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -255,7 +255,7 @@ int __devinit setup_niccy(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev "
- "ret(%d)\n", __FUNCTION__, err);
+ "ret(%d)\n", __func__, err);
return 0;
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 95425f3d2220..a10dfa82c734 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -555,7 +555,7 @@ setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index 04416bad611d..2044e7173ab4 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -218,13 +218,13 @@ enum {
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
#define ERR(format, arg...) \
-printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
+printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#define WARN(format, arg...) \
-printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
+printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#define INFO(format, arg...) \
-printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
+printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#include "isdnhdlc.h"
#include "fsm.h"
@@ -406,7 +406,7 @@ struct st5481_adapter {
/*
* Submit an URB with error reporting. This is a macro so
- * the __FUNCTION__ returns the caller function name.
+ * the __func__ returns the caller function name.
*/
#define SUBMIT_URB(urb, mem_flags) \
({ \
@@ -470,7 +470,7 @@ extern int st5481_debug;
#ifdef CONFIG_HISAX_DEBUG
#define DBG_ISO_PACKET(level,urb) \
- if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
+ if (level & __debug_variable) dump_iso_packet(__func__,urb)
static void __attribute__((unused))
dump_iso_packet(const char *name, struct urb *urb)
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index 4ada66b8b679..427a8b0520f5 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -342,7 +342,7 @@ void st5481_release_usb(struct st5481_adapter *adapter)
usb_kill_urb(intr->urb);
kfree(intr->urb->transfer_buffer);
usb_free_urb(intr->urb);
- ctrl->urb = NULL;
+ intr->urb = NULL;
}
/*
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index 6a5e379e0774..5dc9f1a43629 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -301,7 +301,7 @@ setup_teles3(struct IsdnCard *card)
err = pnp_activate_dev(pnp_d);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
+ __func__, err);
return(0);
}
card->para[3] = pnp_port_start(pnp_d, 2);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index d4ad6992f776..0f3c66de69bc 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1924,7 +1924,7 @@ isdn_free_channel(int di, int ch, int usage)
if ((di < 0) || (ch < 0)) {
printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n",
- __FUNCTION__, di, ch);
+ __func__, di, ch);
return;
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
index bc2f0dd962ea..be4949715d55 100644
--- a/drivers/isdn/i4l/isdn_net.h
+++ b/drivers/isdn/i4l/isdn_net.h
@@ -108,7 +108,7 @@ static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *
lp = nd->queue;
// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
-// __FUNCTION__, lp->name, lp, nlp->name, nlp, lp->last);
+// __func__, lp->name, lp, nlp->name, nlp, lp->last);
nlp->last = lp->last;
lp->last->next = nlp;
lp->last = nlp;
@@ -129,7 +129,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
master_lp = (isdn_net_local *) lp->master->priv;
// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
-// __FUNCTION__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
+// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
lp->last->next = lp->next;
lp->next->last = lp->last;
@@ -141,7 +141,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
}
lp->next = lp->last = lp; /* (re)set own pointers */
// printk(KERN_DEBUG "%s: mndq(%p)\n",
-// __FUNCTION__, master_lp->netdev->queue);
+// __func__, master_lp->netdev->queue);
spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 9f5fe372f83d..127cfdad68e7 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -110,7 +110,7 @@ isdn_ppp_free(isdn_net_local * lp)
if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
return 0;
}
@@ -127,7 +127,7 @@ isdn_ppp_free(isdn_net_local * lp)
#endif /* CONFIG_ISDN_MPP */
if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
return 0;
}
is = ippp_table[lp->ppp_slot];
@@ -226,7 +226,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp)
{
if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
return;
}
ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
@@ -245,7 +245,7 @@ isdn_ppp_closewait(int slot)
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
- __FUNCTION__, slot);
+ __func__, slot);
return 0;
}
is = ippp_table[slot];
@@ -343,7 +343,7 @@ isdn_ppp_release(int min, struct file *file)
is = file->private_data;
if (!is) {
- printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__);
+ printk(KERN_ERR "%s: no file->private_data\n", __func__);
return;
}
if (is->debug & 0x1)
@@ -353,7 +353,7 @@ isdn_ppp_release(int min, struct file *file)
isdn_net_dev *p = is->lp->netdev;
if (!p) {
- printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__);
+ printk(KERN_ERR "%s: no lp->netdev\n", __func__);
return;
}
is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
@@ -1080,7 +1080,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (net_dev->local->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __FUNCTION__, net_dev->local->ppp_slot);
+ __func__, net_dev->local->ppp_slot);
goto drop_packet;
}
if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
@@ -1107,7 +1107,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
skb_old->len);
if (net_dev->local->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __FUNCTION__, net_dev->local->ppp_slot);
+ __func__, net_dev->local->ppp_slot);
goto drop_packet;
}
pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
@@ -1553,7 +1553,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
if (lp->ppp_slot < 0) {
printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
return(-EINVAL);
}
@@ -1604,7 +1604,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
slot = lp->ppp_slot;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
stats->frame_drops++;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&mp->lock, flags);
@@ -1641,7 +1641,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
slot = lpq->ppp_slot;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
- __FUNCTION__, lpq->ppp_slot);
+ __func__, lpq->ppp_slot);
} else {
u32 lls = ippp_table[slot]->last_link_seqno;
if (MP_LT(lls, minseq))
@@ -1875,7 +1875,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
return;
}
if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
@@ -2655,7 +2655,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
lp->ppp_slot);
if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __FUNCTION__, lp->ppp_slot);
+ __func__, lp->ppp_slot);
return;
}
is = ippp_table[lp->ppp_slot];
@@ -2665,7 +2665,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
- __FUNCTION__, slot);
+ __func__, slot);
return;
}
mis = ippp_table[slot];
@@ -2829,7 +2829,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
return;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __FUNCTION__, slot);
+ __func__, slot);
return;
}
is = ippp_table[slot];
@@ -2852,7 +2852,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
- __FUNCTION__, slot);
+ __func__, slot);
return;
}
mis = ippp_table[slot];
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 133eb18e65cc..8af0df1d5b8c 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1347,7 +1347,7 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
modem_info *info = (modem_info *) tty->driver_data;
u_char control, status;
- if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__))
+ if (isdn_tty_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1372,7 +1372,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
{
modem_info *info = (modem_info *) tty->driver_data;
- if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__))
+ if (isdn_tty_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1608,7 +1608,7 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp)
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
return -ENODEV;
if (!try_module_get(info->owner)) {
- printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
return -ENODEV;
}
#ifdef ISDN_DEBUG_MODEM_OPEN
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index eb97c4113d78..86a369bc57d6 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -65,6 +65,12 @@ config LEDS_NET48XX
This option enables support for the Soekris net4801 and net4826 error
LED.
+config LEDS_FSG
+ tristate "LED Support for the Freecom FSG-3"
+ depends on LEDS_CLASS && MACH_FSG
+ help
+ This option enables support for the LEDs on the Freecom FSG-3.
+
config LEDS_WRAP
tristate "LED Support for the WRAP series LEDs"
depends on LEDS_CLASS && SCx200_GPIO
@@ -127,6 +133,7 @@ config LEDS_CLEVO_MAIL
This module can drive the mail LED for the following notebooks:
+ Clevo D400P
Clevo D410J
Clevo D410V
Clevo D400V/D470V (not tested, but might work)
@@ -134,6 +141,9 @@ config LEDS_CLEVO_MAIL
Clevo M5x0N (not tested, but might work)
Positivo Mobile (Clevo M5x0V)
+ If your model is not listed here you can try the "nodetect"
+ module paramter.
+
To compile this driver as a module, choose M here: the
module will be called leds-clevo-mail.
@@ -173,4 +183,11 @@ config LEDS_TRIGGER_HEARTBEAT
load average.
If unsure, say Y.
+config LEDS_TRIGGER_DEFAULT_ON
+ tristate "LED Default ON Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows LEDs to be initialised in the ON state.
+ If unsure, say Y.
+
endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e54f42da21a2..973d626f5f4a 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -20,8 +20,10 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
+obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
+obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 63aad90247c4..ac05a928f764 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -24,6 +24,12 @@
static struct class *leds_class;
+static void led_update_brightness(struct led_classdev *led_cdev)
+{
+ if (led_cdev->brightness_get)
+ led_cdev->brightness = led_cdev->brightness_get(led_cdev);
+}
+
static ssize_t led_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -31,6 +37,7 @@ static ssize_t led_brightness_show(struct device *dev,
ssize_t ret = 0;
/* no lock needed for this */
+ led_update_brightness(led_cdev);
sprintf(buf, "%u\n", led_cdev->brightness);
ret = strlen(buf) + 1;
@@ -51,6 +58,9 @@ static ssize_t led_brightness_store(struct device *dev,
if (count == size) {
ret = count;
+
+ if (state == LED_OFF)
+ led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state);
}
@@ -110,6 +120,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
list_add_tail(&led_cdev->node, &leds_list);
up_write(&leds_list_lock);
+ led_update_brightness(led_cdev);
+
#ifdef CONFIG_LEDS_TRIGGERS
init_rwsem(&led_cdev->trigger_lock);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 5d1ca10524b6..016d19f5486f 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -19,7 +19,7 @@
#include "leds.h"
DECLARE_RWSEM(leds_list_lock);
-LIST_HEAD(leds_list);
+EXPORT_SYMBOL_GPL(leds_list_lock);
+LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
-EXPORT_SYMBOL_GPL(leds_list_lock);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 13c9026d68af..0f242b3f09b6 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -29,6 +29,8 @@
static DECLARE_RWSEM(triggers_list_lock);
static LIST_HEAD(trigger_list);
+ /* Used by LED Class */
+
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -45,9 +47,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
trigger_name[len - 1] = '\0';
if (!strcmp(trigger_name, "none")) {
- down_write(&led_cdev->trigger_lock);
- led_trigger_set(led_cdev, NULL);
- up_write(&led_cdev->trigger_lock);
+ led_trigger_remove(led_cdev);
return count;
}
@@ -66,7 +66,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
-
+EXPORT_SYMBOL_GPL(led_trigger_store);
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -96,24 +96,7 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
len += sprintf(len+buf, "\n");
return len;
}
-
-void led_trigger_event(struct led_trigger *trigger,
- enum led_brightness brightness)
-{
- struct list_head *entry;
-
- if (!trigger)
- return;
-
- read_lock(&trigger->leddev_list_lock);
- list_for_each(entry, &trigger->led_cdevs) {
- struct led_classdev *led_cdev;
-
- led_cdev = list_entry(entry, struct led_classdev, trig_list);
- led_set_brightness(led_cdev, brightness);
- }
- read_unlock(&trigger->leddev_list_lock);
-}
+EXPORT_SYMBOL_GPL(led_trigger_show);
/* Caller must ensure led_cdev->trigger_lock held */
void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
@@ -124,7 +107,8 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
if (led_cdev->trigger) {
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
list_del(&led_cdev->trig_list);
- write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
+ write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
+ flags);
if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev);
led_set_brightness(led_cdev, LED_OFF);
@@ -138,6 +122,15 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
}
led_cdev->trigger = trigger;
}
+EXPORT_SYMBOL_GPL(led_trigger_set);
+
+void led_trigger_remove(struct led_classdev *led_cdev)
+{
+ down_write(&led_cdev->trigger_lock);
+ led_trigger_set(led_cdev, NULL);
+ up_write(&led_cdev->trigger_lock);
+}
+EXPORT_SYMBOL_GPL(led_trigger_remove);
void led_trigger_set_default(struct led_classdev *led_cdev)
{
@@ -155,6 +148,9 @@ void led_trigger_set_default(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
up_read(&triggers_list_lock);
}
+EXPORT_SYMBOL_GPL(led_trigger_set_default);
+
+/* LED Trigger Interface */
int led_trigger_register(struct led_trigger *trigger)
{
@@ -181,26 +177,7 @@ int led_trigger_register(struct led_trigger *trigger)
return 0;
}
-
-void led_trigger_register_simple(const char *name, struct led_trigger **tp)
-{
- struct led_trigger *trigger;
- int err;
-
- trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-
- if (trigger) {
- trigger->name = name;
- err = led_trigger_register(trigger);
- if (err < 0)
- printk(KERN_WARNING "LED trigger %s failed to register"
- " (%d)\n", name, err);
- } else
- printk(KERN_WARNING "LED trigger %s failed to register"
- " (no memory)\n", name);
-
- *tp = trigger;
-}
+EXPORT_SYMBOL_GPL(led_trigger_register);
void led_trigger_unregister(struct led_trigger *trigger)
{
@@ -221,6 +198,49 @@ void led_trigger_unregister(struct led_trigger *trigger)
}
up_read(&leds_list_lock);
}
+EXPORT_SYMBOL_GPL(led_trigger_unregister);
+
+/* Simple LED Tigger Interface */
+
+void led_trigger_event(struct led_trigger *trigger,
+ enum led_brightness brightness)
+{
+ struct list_head *entry;
+
+ if (!trigger)
+ return;
+
+ read_lock(&trigger->leddev_list_lock);
+ list_for_each(entry, &trigger->led_cdevs) {
+ struct led_classdev *led_cdev;
+
+ led_cdev = list_entry(entry, struct led_classdev, trig_list);
+ led_set_brightness(led_cdev, brightness);
+ }
+ read_unlock(&trigger->leddev_list_lock);
+}
+EXPORT_SYMBOL_GPL(led_trigger_event);
+
+void led_trigger_register_simple(const char *name, struct led_trigger **tp)
+{
+ struct led_trigger *trigger;
+ int err;
+
+ trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+
+ if (trigger) {
+ trigger->name = name;
+ err = led_trigger_register(trigger);
+ if (err < 0)
+ printk(KERN_WARNING "LED trigger %s failed to register"
+ " (%d)\n", name, err);
+ } else
+ printk(KERN_WARNING "LED trigger %s failed to register"
+ " (no memory)\n", name);
+
+ *tp = trigger;
+}
+EXPORT_SYMBOL_GPL(led_trigger_register_simple);
void led_trigger_unregister_simple(struct led_trigger *trigger)
{
@@ -228,21 +248,7 @@ void led_trigger_unregister_simple(struct led_trigger *trigger)
led_trigger_unregister(trigger);
kfree(trigger);
}
-
-/* Used by LED Class */
-EXPORT_SYMBOL_GPL(led_trigger_set);
-EXPORT_SYMBOL_GPL(led_trigger_set_default);
-EXPORT_SYMBOL_GPL(led_trigger_show);
-EXPORT_SYMBOL_GPL(led_trigger_store);
-
-/* LED Trigger Interface */
-EXPORT_SYMBOL_GPL(led_trigger_register);
-EXPORT_SYMBOL_GPL(led_trigger_unregister);
-
-/* Simple LED Tigger Interface */
-EXPORT_SYMBOL_GPL(led_trigger_register_simple);
EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
-EXPORT_SYMBOL_GPL(led_trigger_event);
MODULE_AUTHOR("Richard Purdie");
MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index 5750b08b601f..eb3415e88f43 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -14,7 +14,7 @@
#define CLEVO_MAIL_LED_BLINK_1HZ 0x008A
#define CLEVO_MAIL_LED_BLINK_0_5HZ 0x0083
-MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
+MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
MODULE_DESCRIPTION("Clevo mail LED driver");
MODULE_LICENSE("GPL");
@@ -69,6 +69,16 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
},
{
.callback = clevo_mail_led_dmi_callback,
+ .ident = "Clevo D400P",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Clevo"),
+ DMI_MATCH(DMI_BOARD_NAME, "D400P"),
+ DMI_MATCH(DMI_BOARD_VERSION, "Rev.A"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0106")
+ }
+ },
+ {
+ .callback = clevo_mail_led_dmi_callback,
.ident = "Clevo D410V",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Clevo, Co."),
@@ -93,8 +103,8 @@ static void clevo_mail_led_set(struct led_classdev *led_cdev,
}
static int clevo_mail_led_blink(struct led_classdev *led_cdev,
- unsigned long* delay_on,
- unsigned long* delay_off)
+ unsigned long *delay_on,
+ unsigned long *delay_off)
{
int status = -EINVAL;
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
index 096881a11b1a..059aa2924b1c 100644
--- a/drivers/leds/leds-cobalt-qube.c
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -18,7 +18,7 @@ static void __iomem *led_port;
static u8 led_value;
static void qube_front_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+ enum led_brightness brightness)
{
if (brightness)
led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
index 6ebfff341e6c..ff0e8c3fbf9b 100644
--- a/drivers/leds/leds-cobalt-raq.c
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/init.h>
#include <linux/io.h>
@@ -33,7 +33,7 @@ static u8 led_value;
static DEFINE_SPINLOCK(led_value_lock);
static void raq_web_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+ enum led_brightness brightness)
{
unsigned long flags;
@@ -54,7 +54,7 @@ static struct led_classdev raq_web_led = {
};
static void raq_power_off_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+ enum led_brightness brightness)
{
unsigned long flags;
diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c
index 29e931f89f9c..a709704b9f93 100644
--- a/drivers/leds/leds-corgi.c
+++ b/drivers/leds/leds-corgi.c
@@ -21,7 +21,8 @@
#include <asm/arch/pxa-regs.h>
#include <asm/hardware/scoop.h>
-static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
+static void corgiled_amber_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
if (value)
GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
@@ -29,7 +30,8 @@ static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightnes
GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
}
-static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+static void corgiled_green_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
if (value)
set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
@@ -53,7 +55,8 @@ static struct led_classdev corgi_green_led = {
static int corgiled_suspend(struct platform_device *dev, pm_message_t state)
{
#ifdef CONFIG_LEDS_TRIGGERS
- if (corgi_amber_led.trigger && strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
+ if (corgi_amber_led.trigger &&
+ strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
#endif
led_classdev_suspend(&corgi_amber_led);
led_classdev_suspend(&corgi_green_led);
@@ -110,7 +113,7 @@ static int __init corgiled_init(void)
static void __exit corgiled_exit(void)
{
- platform_driver_unregister(&corgiled_driver);
+ platform_driver_unregister(&corgiled_driver);
}
module_init(corgiled_init);
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
new file mode 100644
index 000000000000..a7421b8c47d8
--- /dev/null
+++ b/drivers/leds/leds-fsg.c
@@ -0,0 +1,261 @@
+/*
+ * LED Driver for the Freecom FSG-3
+ *
+ * Copyright (c) 2008 Rod Whitby <rod@whitby.id.au>
+ *
+ * Author: Rod Whitby <rod@whitby.id.au>
+ *
+ * Based on leds-spitz.c
+ * Copyright 2005-2006 Openedhand Ltd.
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+
+static short __iomem *latch_address;
+static unsigned short latch_value;
+
+
+static void fsg_led_wlan_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value) {
+ latch_value &= ~(1 << FSG_LED_WLAN_BIT);
+ *latch_address = latch_value;
+ } else {
+ latch_value |= (1 << FSG_LED_WLAN_BIT);
+ *latch_address = latch_value;
+ }
+}
+
+static void fsg_led_wan_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value) {
+ latch_value &= ~(1 << FSG_LED_WAN_BIT);
+ *latch_address = latch_value;
+ } else {
+ latch_value |= (1 << FSG_LED_WAN_BIT);
+ *latch_address = latch_value;
+ }
+}
+
+static void fsg_led_sata_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value) {
+ latch_value &= ~(1 << FSG_LED_SATA_BIT);
+ *latch_address = latch_value;
+ } else {
+ latch_value |= (1 << FSG_LED_SATA_BIT);
+ *latch_address = latch_value;
+ }
+}
+
+static void fsg_led_usb_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value) {
+ latch_value &= ~(1 << FSG_LED_USB_BIT);
+ *latch_address = latch_value;
+ } else {
+ latch_value |= (1 << FSG_LED_USB_BIT);
+ *latch_address = latch_value;
+ }
+}
+
+static void fsg_led_sync_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value) {
+ latch_value &= ~(1 << FSG_LED_SYNC_BIT);
+ *latch_address = latch_value;
+ } else {
+ latch_value |= (1 << FSG_LED_SYNC_BIT);
+ *latch_address = latch_value;
+ }
+}
+
+static void fsg_led_ring_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value) {
+ latch_value &= ~(1 << FSG_LED_RING_BIT);
+ *latch_address = latch_value;
+ } else {
+ latch_value |= (1 << FSG_LED_RING_BIT);
+ *latch_address = latch_value;
+ }
+}
+
+
+
+static struct led_classdev fsg_wlan_led = {
+ .name = "fsg:blue:wlan",
+ .brightness_set = fsg_led_wlan_set,
+};
+
+static struct led_classdev fsg_wan_led = {
+ .name = "fsg:blue:wan",
+ .brightness_set = fsg_led_wan_set,
+};
+
+static struct led_classdev fsg_sata_led = {
+ .name = "fsg:blue:sata",
+ .brightness_set = fsg_led_sata_set,
+};
+
+static struct led_classdev fsg_usb_led = {
+ .name = "fsg:blue:usb",
+ .brightness_set = fsg_led_usb_set,
+};
+
+static struct led_classdev fsg_sync_led = {
+ .name = "fsg:blue:sync",
+ .brightness_set = fsg_led_sync_set,
+};
+
+static struct led_classdev fsg_ring_led = {
+ .name = "fsg:blue:ring",
+ .brightness_set = fsg_led_ring_set,
+};
+
+
+
+#ifdef CONFIG_PM
+static int fsg_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ led_classdev_suspend(&fsg_wlan_led);
+ led_classdev_suspend(&fsg_wan_led);
+ led_classdev_suspend(&fsg_sata_led);
+ led_classdev_suspend(&fsg_usb_led);
+ led_classdev_suspend(&fsg_sync_led);
+ led_classdev_suspend(&fsg_ring_led);
+ return 0;
+}
+
+static int fsg_led_resume(struct platform_device *dev)
+{
+ led_classdev_resume(&fsg_wlan_led);
+ led_classdev_resume(&fsg_wan_led);
+ led_classdev_resume(&fsg_sata_led);
+ led_classdev_resume(&fsg_usb_led);
+ led_classdev_resume(&fsg_sync_led);
+ led_classdev_resume(&fsg_ring_led);
+ return 0;
+}
+#endif
+
+
+static int fsg_led_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
+ if (ret < 0)
+ goto failwlan;
+
+ ret = led_classdev_register(&pdev->dev, &fsg_wan_led);
+ if (ret < 0)
+ goto failwan;
+
+ ret = led_classdev_register(&pdev->dev, &fsg_sata_led);
+ if (ret < 0)
+ goto failsata;
+
+ ret = led_classdev_register(&pdev->dev, &fsg_usb_led);
+ if (ret < 0)
+ goto failusb;
+
+ ret = led_classdev_register(&pdev->dev, &fsg_sync_led);
+ if (ret < 0)
+ goto failsync;
+
+ ret = led_classdev_register(&pdev->dev, &fsg_ring_led);
+ if (ret < 0)
+ goto failring;
+
+ /* Map the LED chip select address space */
+ latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
+ if (!latch_address) {
+ ret = -ENOMEM;
+ goto failremap;
+ }
+
+ latch_value = 0xffff;
+ *latch_address = latch_value;
+
+ return ret;
+
+ failremap:
+ led_classdev_unregister(&fsg_ring_led);
+ failring:
+ led_classdev_unregister(&fsg_sync_led);
+ failsync:
+ led_classdev_unregister(&fsg_usb_led);
+ failusb:
+ led_classdev_unregister(&fsg_sata_led);
+ failsata:
+ led_classdev_unregister(&fsg_wan_led);
+ failwan:
+ led_classdev_unregister(&fsg_wlan_led);
+ failwlan:
+
+ return ret;
+}
+
+static int fsg_led_remove(struct platform_device *pdev)
+{
+ iounmap(latch_address);
+
+ led_classdev_unregister(&fsg_wlan_led);
+ led_classdev_unregister(&fsg_wan_led);
+ led_classdev_unregister(&fsg_sata_led);
+ led_classdev_unregister(&fsg_usb_led);
+ led_classdev_unregister(&fsg_sync_led);
+ led_classdev_unregister(&fsg_ring_led);
+
+ return 0;
+}
+
+
+static struct platform_driver fsg_led_driver = {
+ .probe = fsg_led_probe,
+ .remove = fsg_led_remove,
+#ifdef CONFIG_PM
+ .suspend = fsg_led_suspend,
+ .resume = fsg_led_resume,
+#endif
+ .driver = {
+ .name = "fsg-led",
+ },
+};
+
+
+static int __init fsg_led_init(void)
+{
+ return platform_driver_register(&fsg_led_driver);
+}
+
+static void __exit fsg_led_exit(void)
+{
+ platform_driver_unregister(&fsg_led_driver);
+}
+
+
+module_init(fsg_led_init);
+module_exit(fsg_led_exit);
+
+MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
+MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 1aae8b332134..b13bd2950e95 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -24,6 +24,8 @@ struct gpio_led_data {
u8 new_level;
u8 can_sleep;
u8 active_low;
+ int (*platform_gpio_blink_set)(unsigned gpio,
+ unsigned long *delay_on, unsigned long *delay_off);
};
static void gpio_led_work(struct work_struct *work)
@@ -60,6 +62,15 @@ static void gpio_led_set(struct led_classdev *led_cdev,
gpio_set_value(led_dat->gpio, level);
}
+static int gpio_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on, unsigned long *delay_off)
+{
+ struct gpio_led_data *led_dat =
+ container_of(led_cdev, struct gpio_led_data, cdev);
+
+ return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
+}
+
static int gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
@@ -88,6 +99,10 @@ static int gpio_led_probe(struct platform_device *pdev)
led_dat->gpio = cur_led->gpio;
led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
led_dat->active_low = cur_led->active_low;
+ if (pdata->gpio_blink_set) {
+ led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
+ led_dat->cdev.blink_set = gpio_blink_set;
+ }
led_dat->cdev.brightness_set = gpio_led_set;
led_dat->cdev.brightness = LED_OFF;
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index 6e51c9b61027..bcec42230389 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -26,20 +26,20 @@
void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value)
{
switch (value) {
- case LED_HALF:
- h1940_latch_control(0,H1940_LATCH_LED_FLASH);
- s3c2410_gpio_setpin(S3C2410_GPA7,1);
- break;
- case LED_FULL:
- h1940_latch_control(0,H1940_LATCH_LED_GREEN);
- s3c2410_gpio_setpin(S3C2410_GPA7,1);
- break;
- default:
- case LED_OFF:
- h1940_latch_control(H1940_LATCH_LED_FLASH,0);
- h1940_latch_control(H1940_LATCH_LED_GREEN,0);
- s3c2410_gpio_setpin(S3C2410_GPA7,0);
- break;
+ case LED_HALF:
+ h1940_latch_control(0, H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA7, 1);
+ break;
+ case LED_FULL:
+ h1940_latch_control(0, H1940_LATCH_LED_GREEN);
+ s3c2410_gpio_setpin(S3C2410_GPA7, 1);
+ break;
+ default:
+ case LED_OFF:
+ h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
+ h1940_latch_control(H1940_LATCH_LED_GREEN, 0);
+ s3c2410_gpio_setpin(S3C2410_GPA7, 0);
+ break;
}
}
@@ -55,20 +55,20 @@ static struct led_classdev h1940_greenled = {
void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value)
{
switch (value) {
- case LED_HALF:
- h1940_latch_control(0,H1940_LATCH_LED_FLASH);
- s3c2410_gpio_setpin(S3C2410_GPA1,1);
- break;
- case LED_FULL:
- h1940_latch_control(0,H1940_LATCH_LED_RED);
- s3c2410_gpio_setpin(S3C2410_GPA1,1);
- break;
- default:
- case LED_OFF:
- h1940_latch_control(H1940_LATCH_LED_FLASH,0);
- h1940_latch_control(H1940_LATCH_LED_RED,0);
- s3c2410_gpio_setpin(S3C2410_GPA1,0);
- break;
+ case LED_HALF:
+ h1940_latch_control(0, H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA1, 1);
+ break;
+ case LED_FULL:
+ h1940_latch_control(0, H1940_LATCH_LED_RED);
+ s3c2410_gpio_setpin(S3C2410_GPA1, 1);
+ break;
+ default:
+ case LED_OFF:
+ h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
+ h1940_latch_control(H1940_LATCH_LED_RED, 0);
+ s3c2410_gpio_setpin(S3C2410_GPA1, 0);
+ break;
}
}
@@ -86,11 +86,11 @@ void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value)
{
if (value) {
/* flashing Blue */
- h1940_latch_control(0,H1940_LATCH_LED_FLASH);
- s3c2410_gpio_setpin(S3C2410_GPA3,1);
+ h1940_latch_control(0, H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA3, 1);
} else {
- h1940_latch_control(H1940_LATCH_LED_FLASH,0);
- s3c2410_gpio_setpin(S3C2410_GPA3,0);
+ h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
+ s3c2410_gpio_setpin(S3C2410_GPA3, 0);
}
}
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index 870f5a3789e8..844d5979c904 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -17,7 +17,8 @@
#include <asm/hd64461.h>
#include <asm/hp6xx.h>
-static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+static void hp6xxled_green_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
u8 v8;
@@ -28,7 +29,8 @@ static void hp6xxled_green_set(struct led_classdev *led_cdev, enum led_brightnes
outb(v8 | PKDR_LED_GREEN, PKDR);
}
-static void hp6xxled_red_set(struct led_classdev *led_cdev, enum led_brightness value)
+static void hp6xxled_red_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
u16 v16;
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 0d10e119d8f5..d4f5021dccbf 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -51,7 +51,7 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev,
if (pd->flags & S3C24XX_LEDF_TRISTATE)
s3c2410_gpio_cfgpin(pd->gpio,
- value ? S3C2410_GPIO_OUTPUT : S3C2410_GPIO_INPUT);
+ value ? S3C2410_GPIO_OUTPUT : S3C2410_GPIO_INPUT);
}
@@ -151,7 +151,7 @@ static int __init s3c24xx_led_init(void)
static void __exit s3c24xx_led_exit(void)
{
- platform_driver_unregister(&s3c24xx_led_driver);
+ platform_driver_unregister(&s3c24xx_led_driver);
}
module_init(s3c24xx_led_init);
diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c
index 87007cc362c1..e75e8543bc5a 100644
--- a/drivers/leds/leds-spitz.c
+++ b/drivers/leds/leds-spitz.c
@@ -21,7 +21,8 @@
#include <asm/arch/pxa-regs.h>
#include <asm/arch/spitz.h>
-static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
+static void spitzled_amber_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
if (value)
set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
@@ -29,7 +30,8 @@ static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightnes
reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
}
-static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightness value)
+static void spitzled_green_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
if (value)
set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
@@ -53,7 +55,8 @@ static struct led_classdev spitz_green_led = {
static int spitzled_suspend(struct platform_device *dev, pm_message_t state)
{
#ifdef CONFIG_LEDS_TRIGGERS
- if (spitz_amber_led.trigger && strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
+ if (spitz_amber_led.trigger &&
+ strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
#endif
led_classdev_suspend(&spitz_amber_led);
led_classdev_suspend(&spitz_green_led);
@@ -116,7 +119,7 @@ static int __init spitzled_init(void)
static void __exit spitzled_exit(void)
{
- platform_driver_unregister(&spitzled_driver);
+ platform_driver_unregister(&spitzled_driver);
}
module_init(spitzled_init);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 12b6fe93b135..5edbf52c4fa7 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -27,6 +27,11 @@ static inline void led_set_brightness(struct led_classdev *led_cdev,
led_cdev->brightness_set(led_cdev, value);
}
+static inline int led_get_brightness(struct led_classdev *led_cdev)
+{
+ return led_cdev->brightness;
+}
+
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
@@ -34,9 +39,11 @@ extern struct list_head leds_list;
void led_trigger_set_default(struct led_classdev *led_cdev);
void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger);
+void led_trigger_remove(struct led_classdev *led_cdev);
#else
-#define led_trigger_set_default(x) do {} while(0)
-#define led_trigger_set(x, y) do {} while(0)
+#define led_trigger_set_default(x) do {} while (0)
+#define led_trigger_set(x, y) do {} while (0)
+#define led_trigger_remove(x) do {} while (0)
#endif
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/leds/ledtrig-default-on.c b/drivers/leds/ledtrig-default-on.c
new file mode 100644
index 000000000000..92995e40cfa4
--- /dev/null
+++ b/drivers/leds/ledtrig-default-on.c
@@ -0,0 +1,45 @@
+/*
+ * LED Kernel Default ON Trigger
+ *
+ * Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
+ *
+ * Based on Richard Purdie's ledtrig-timer.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+static void defon_trig_activate(struct led_classdev *led_cdev)
+{
+ led_set_brightness(led_cdev, LED_FULL);
+}
+
+static struct led_trigger defon_led_trigger = {
+ .name = "default-on",
+ .activate = defon_trig_activate,
+};
+
+static int __init defon_trig_init(void)
+{
+ return led_trigger_register(&defon_led_trigger);
+}
+
+static void __exit defon_trig_exit(void)
+{
+ led_trigger_unregister(&defon_led_trigger);
+}
+
+module_init(defon_trig_init);
+module_exit(defon_trig_exit);
+
+MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
+MODULE_DESCRIPTION("Default-ON LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c
index 54b155c7026f..883a577b1b97 100644
--- a/drivers/leds/ledtrig-ide-disk.c
+++ b/drivers/leds/ledtrig-ide-disk.c
@@ -38,7 +38,7 @@ static void ledtrig_ide_timerfunc(unsigned long data)
if (ide_lastactivity != ide_activity) {
ide_lastactivity = ide_activity;
led_trigger_event(ledtrig_ide, LED_FULL);
- mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
+ mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10));
} else {
led_trigger_event(ledtrig_ide, LED_OFF);
}
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 82c55d6e4902..5c99f4f0c692 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -25,6 +25,9 @@
#include "leds.h"
struct timer_trig_data {
+ int brightness_on; /* LED brightness during "on" period.
+ * (LED_OFF < brightness_on <= LED_FULL)
+ */
unsigned long delay_on; /* milliseconds on */
unsigned long delay_off; /* milliseconds off */
struct timer_list timer;
@@ -34,17 +37,26 @@ static void led_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (struct led_classdev *) data;
struct timer_trig_data *timer_data = led_cdev->trigger_data;
- unsigned long brightness = LED_OFF;
- unsigned long delay = timer_data->delay_off;
+ unsigned long brightness;
+ unsigned long delay;
if (!timer_data->delay_on || !timer_data->delay_off) {
led_set_brightness(led_cdev, LED_OFF);
return;
}
- if (!led_cdev->brightness) {
- brightness = LED_FULL;
+ brightness = led_get_brightness(led_cdev);
+ if (!brightness) {
+ /* Time to switch the LED on. */
+ brightness = timer_data->brightness_on;
delay = timer_data->delay_on;
+ } else {
+ /* Store the current brightness value to be able
+ * to restore it when the delay_off period is over.
+ */
+ timer_data->brightness_on = brightness;
+ brightness = LED_OFF;
+ delay = timer_data->delay_off;
}
led_set_brightness(led_cdev, brightness);
@@ -52,7 +64,7 @@ static void led_timer_function(unsigned long data)
mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
}
-static ssize_t led_delay_on_show(struct device *dev,
+static ssize_t led_delay_on_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -63,7 +75,7 @@ static ssize_t led_delay_on_show(struct device *dev,
return strlen(buf) + 1;
}
-static ssize_t led_delay_on_store(struct device *dev,
+static ssize_t led_delay_on_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -87,7 +99,7 @@ static ssize_t led_delay_on_store(struct device *dev,
/* try to activate hardware acceleration, if any */
if (!led_cdev->blink_set ||
led_cdev->blink_set(led_cdev,
- &timer_data->delay_on, &timer_data->delay_off)) {
+ &timer_data->delay_on, &timer_data->delay_off)) {
/* no hardware acceleration, blink via timer */
mod_timer(&timer_data->timer, jiffies + 1);
}
@@ -98,7 +110,7 @@ static ssize_t led_delay_on_store(struct device *dev,
return ret;
}
-static ssize_t led_delay_off_show(struct device *dev,
+static ssize_t led_delay_off_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -109,7 +121,7 @@ static ssize_t led_delay_off_show(struct device *dev,
return strlen(buf) + 1;
}
-static ssize_t led_delay_off_store(struct device *dev,
+static ssize_t led_delay_off_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -133,7 +145,7 @@ static ssize_t led_delay_off_store(struct device *dev,
/* try to activate hardware acceleration, if any */
if (!led_cdev->blink_set ||
led_cdev->blink_set(led_cdev,
- &timer_data->delay_on, &timer_data->delay_off)) {
+ &timer_data->delay_on, &timer_data->delay_off)) {
/* no hardware acceleration, blink via timer */
mod_timer(&timer_data->timer, jiffies + 1);
}
@@ -156,6 +168,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
if (!timer_data)
return;
+ timer_data->brightness_on = led_get_brightness(led_cdev);
+ if (timer_data->brightness_on == LED_OFF)
+ timer_data->brightness_on = LED_FULL;
led_cdev->trigger_data = timer_data;
init_timer(&timer_data->timer);
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 89302309da92..cc9f27514aef 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -103,6 +103,9 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
return 0;
}
+static struct lock_class_key emumousebtn_event_class;
+static struct lock_class_key emumousebtn_mutex_class;
+
static int emumousebtn_input_register(void)
{
int ret;
@@ -111,6 +114,9 @@ static int emumousebtn_input_register(void)
if (!emumousebtn)
return -ENOMEM;
+ lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class);
+ lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class);
+
emumousebtn->name = "Macintosh mouse button emulation";
emumousebtn->id.bustype = BUS_ADB;
emumousebtn->id.vendor = 0x0001;
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
index b3fbb45bc90a..73d695dc9e50 100644
--- a/drivers/macintosh/windfarm_pm112.c
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -668,7 +668,7 @@ static struct platform_driver wf_pm112_driver = {
.remove = __devexit_p(wf_pm112_remove),
.driver = {
.name = "windfarm",
- .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
},
};
@@ -711,3 +711,4 @@ module_exit(wf_pm112_exit);
MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
MODULE_DESCRIPTION("Thermal control for PowerMac11,2");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index f24fa734046a..abbe206474f5 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -770,7 +770,7 @@ static struct platform_driver wf_smu_driver = {
.remove = __devexit_p(wf_smu_remove),
.driver = {
.name = "windfarm",
- .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
},
};
@@ -810,4 +810,4 @@ module_exit(wf_smu_exit);
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Thermal control logic for iMac G5");
MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 26eee69ebe6d..764c525b2117 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -702,7 +702,7 @@ static struct platform_driver wf_smu_driver = {
.remove = __devexit_p(wf_smu_remove),
.driver = {
.name = "windfarm",
- .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
},
};
@@ -742,3 +742,4 @@ MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index d9aa7edb8780..7be09eeea293 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -3,10 +3,10 @@
#
dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
- dm-ioctl.o dm-io.o kcopyd.o
+ dm-ioctl.o dm-io.o dm-kcopyd.o
dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
dm-snapshot-objs := dm-snap.o dm-exception-store.o
-dm-mirror-objs := dm-log.o dm-raid1.o
+dm-mirror-objs := dm-raid1.o
dm-rdac-objs := dm-mpath-rdac.o
dm-hp-sw-objs := dm-mpath-hp-sw.o
md-mod-objs := md.o bitmap.o
@@ -39,7 +39,7 @@ obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
obj-$(CONFIG_DM_MULTIPATH_HP) += dm-hp-sw.o
obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
-obj-$(CONFIG_DM_MIRROR) += dm-mirror.o
+obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
quiet_cmd_unroll = UNROLL $@
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 5bbce29f143a..41f408068a7c 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -9,13 +9,13 @@
#include "dm.h"
#include "dm-snap.h"
-#include "dm-io.h"
-#include "kcopyd.h"
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/dm-io.h>
+#include <linux/dm-kcopyd.h>
#define DM_MSG_PREFIX "snapshots"
#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */
@@ -131,7 +131,7 @@ struct pstore {
static unsigned sectors_to_pages(unsigned sectors)
{
- return sectors / (PAGE_SIZE >> 9);
+ return DIV_ROUND_UP(sectors, PAGE_SIZE >> 9);
}
static int alloc_area(struct pstore *ps)
@@ -159,7 +159,7 @@ static void free_area(struct pstore *ps)
}
struct mdata_req {
- struct io_region *where;
+ struct dm_io_region *where;
struct dm_io_request *io_req;
struct work_struct work;
int result;
@@ -177,7 +177,7 @@ static void do_metadata(struct work_struct *work)
*/
static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)
{
- struct io_region where = {
+ struct dm_io_region where = {
.bdev = ps->snap->cow->bdev,
.sector = ps->snap->chunk_size * chunk,
.count = ps->snap->chunk_size,
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 8f25f628ef16..4789c42d9a3a 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -5,13 +5,14 @@
* This file is released under the GPL.
*/
-#include "dm-io.h"
+#include "dm.h"
#include <linux/bio.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/dm-io.h>
struct dm_io_client {
mempool_t *pool;
@@ -20,7 +21,7 @@ struct dm_io_client {
/* FIXME: can we shrink this ? */
struct io {
- unsigned long error;
+ unsigned long error_bits;
atomic_t count;
struct task_struct *sleeper;
struct dm_io_client *client;
@@ -107,14 +108,14 @@ static inline unsigned bio_get_region(struct bio *bio)
static void dec_count(struct io *io, unsigned int region, int error)
{
if (error)
- set_bit(region, &io->error);
+ set_bit(region, &io->error_bits);
if (atomic_dec_and_test(&io->count)) {
if (io->sleeper)
wake_up_process(io->sleeper);
else {
- unsigned long r = io->error;
+ unsigned long r = io->error_bits;
io_notify_fn fn = io->callback;
void *context = io->context;
@@ -271,7 +272,7 @@ static void km_dp_init(struct dpages *dp, void *data)
/*-----------------------------------------------------------------
* IO routines that accept a list of pages.
*---------------------------------------------------------------*/
-static void do_region(int rw, unsigned int region, struct io_region *where,
+static void do_region(int rw, unsigned region, struct dm_io_region *where,
struct dpages *dp, struct io *io)
{
struct bio *bio;
@@ -320,7 +321,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
}
static void dispatch_io(int rw, unsigned int num_regions,
- struct io_region *where, struct dpages *dp,
+ struct dm_io_region *where, struct dpages *dp,
struct io *io, int sync)
{
int i;
@@ -347,17 +348,17 @@ static void dispatch_io(int rw, unsigned int num_regions,
}
static int sync_io(struct dm_io_client *client, unsigned int num_regions,
- struct io_region *where, int rw, struct dpages *dp,
+ struct dm_io_region *where, int rw, struct dpages *dp,
unsigned long *error_bits)
{
struct io io;
- if (num_regions > 1 && rw != WRITE) {
+ if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
WARN_ON(1);
return -EIO;
}
- io.error = 0;
+ io.error_bits = 0;
atomic_set(&io.count, 1); /* see dispatch_io() */
io.sleeper = current;
io.client = client;
@@ -378,25 +379,25 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
return -EINTR;
if (error_bits)
- *error_bits = io.error;
+ *error_bits = io.error_bits;
- return io.error ? -EIO : 0;
+ return io.error_bits ? -EIO : 0;
}
static int async_io(struct dm_io_client *client, unsigned int num_regions,
- struct io_region *where, int rw, struct dpages *dp,
+ struct dm_io_region *where, int rw, struct dpages *dp,
io_notify_fn fn, void *context)
{
struct io *io;
- if (num_regions > 1 && rw != WRITE) {
+ if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
WARN_ON(1);
fn(1, context);
return -EIO;
}
io = mempool_alloc(client->pool, GFP_NOIO);
- io->error = 0;
+ io->error_bits = 0;
atomic_set(&io->count, 1); /* see dispatch_io() */
io->sleeper = NULL;
io->client = client;
@@ -435,10 +436,15 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
}
/*
- * New collapsed (a)synchronous interface
+ * New collapsed (a)synchronous interface.
+ *
+ * If the IO is asynchronous (i.e. it has notify.fn), you must either unplug
+ * the queue with blk_unplug() some time later or set the BIO_RW_SYNC bit in
+ * io_req->bi_rw. If you fail to do one of these, the IO will be submitted to
+ * the disk after q->unplug_delay, which defaults to 3ms in blk-settings.c.
*/
int dm_io(struct dm_io_request *io_req, unsigned num_regions,
- struct io_region *where, unsigned long *sync_error_bits)
+ struct dm_io_region *where, unsigned long *sync_error_bits)
{
int r;
struct dpages dp;
diff --git a/drivers/md/kcopyd.c b/drivers/md/dm-kcopyd.c
index e76b52ade690..996802b8a452 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -9,9 +9,8 @@
* completion notification.
*/
-#include <asm/types.h>
+#include <linux/types.h>
#include <asm/atomic.h>
-
#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -23,24 +22,15 @@
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <linux/dm-kcopyd.h>
-#include "kcopyd.h"
-
-static struct workqueue_struct *_kcopyd_wq;
-static struct work_struct _kcopyd_work;
-
-static void wake(void)
-{
- queue_work(_kcopyd_wq, &_kcopyd_work);
-}
+#include "dm.h"
/*-----------------------------------------------------------------
* Each kcopyd client has its own little pool of preallocated
* pages for kcopyd io.
*---------------------------------------------------------------*/
-struct kcopyd_client {
- struct list_head list;
-
+struct dm_kcopyd_client {
spinlock_t lock;
struct page_list *pages;
unsigned int nr_pages;
@@ -50,8 +40,32 @@ struct kcopyd_client {
wait_queue_head_t destroyq;
atomic_t nr_jobs;
+
+ mempool_t *job_pool;
+
+ struct workqueue_struct *kcopyd_wq;
+ struct work_struct kcopyd_work;
+
+/*
+ * We maintain three lists of jobs:
+ *
+ * i) jobs waiting for pages
+ * ii) jobs that have pages, and are waiting for the io to be issued.
+ * iii) jobs that have completed.
+ *
+ * All three of these are protected by job_lock.
+ */
+ spinlock_t job_lock;
+ struct list_head complete_jobs;
+ struct list_head io_jobs;
+ struct list_head pages_jobs;
};
+static void wake(struct dm_kcopyd_client *kc)
+{
+ queue_work(kc->kcopyd_wq, &kc->kcopyd_work);
+}
+
static struct page_list *alloc_pl(void)
{
struct page_list *pl;
@@ -75,7 +89,7 @@ static void free_pl(struct page_list *pl)
kfree(pl);
}
-static int kcopyd_get_pages(struct kcopyd_client *kc,
+static int kcopyd_get_pages(struct dm_kcopyd_client *kc,
unsigned int nr, struct page_list **pages)
{
struct page_list *pl;
@@ -98,7 +112,7 @@ static int kcopyd_get_pages(struct kcopyd_client *kc,
return 0;
}
-static void kcopyd_put_pages(struct kcopyd_client *kc, struct page_list *pl)
+static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl)
{
struct page_list *cursor;
@@ -126,7 +140,7 @@ static void drop_pages(struct page_list *pl)
}
}
-static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr)
+static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr)
{
unsigned int i;
struct page_list *pl = NULL, *next;
@@ -147,7 +161,7 @@ static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr)
return 0;
}
-static void client_free_pages(struct kcopyd_client *kc)
+static void client_free_pages(struct dm_kcopyd_client *kc)
{
BUG_ON(kc->nr_free_pages != kc->nr_pages);
drop_pages(kc->pages);
@@ -161,7 +175,7 @@ static void client_free_pages(struct kcopyd_client *kc)
* ever having to do io (which could cause a deadlock).
*---------------------------------------------------------------*/
struct kcopyd_job {
- struct kcopyd_client *kc;
+ struct dm_kcopyd_client *kc;
struct list_head list;
unsigned long flags;
@@ -175,13 +189,13 @@ struct kcopyd_job {
* Either READ or WRITE
*/
int rw;
- struct io_region source;
+ struct dm_io_region source;
/*
* The destinations for the transfer.
*/
unsigned int num_dests;
- struct io_region dests[KCOPYD_MAX_REGIONS];
+ struct dm_io_region dests[DM_KCOPYD_MAX_REGIONS];
sector_t offset;
unsigned int nr_pages;
@@ -191,7 +205,7 @@ struct kcopyd_job {
* Set this to ensure you are notified when the job has
* completed. 'context' is for callback to use.
*/
- kcopyd_notify_fn fn;
+ dm_kcopyd_notify_fn fn;
void *context;
/*
@@ -207,47 +221,19 @@ struct kcopyd_job {
#define MIN_JOBS 512
static struct kmem_cache *_job_cache;
-static mempool_t *_job_pool;
-/*
- * We maintain three lists of jobs:
- *
- * i) jobs waiting for pages
- * ii) jobs that have pages, and are waiting for the io to be issued.
- * iii) jobs that have completed.
- *
- * All three of these are protected by job_lock.
- */
-static DEFINE_SPINLOCK(_job_lock);
-
-static LIST_HEAD(_complete_jobs);
-static LIST_HEAD(_io_jobs);
-static LIST_HEAD(_pages_jobs);
-
-static int jobs_init(void)
+int __init dm_kcopyd_init(void)
{
_job_cache = KMEM_CACHE(kcopyd_job, 0);
if (!_job_cache)
return -ENOMEM;
- _job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
- if (!_job_pool) {
- kmem_cache_destroy(_job_cache);
- return -ENOMEM;
- }
-
return 0;
}
-static void jobs_exit(void)
+void dm_kcopyd_exit(void)
{
- BUG_ON(!list_empty(&_complete_jobs));
- BUG_ON(!list_empty(&_io_jobs));
- BUG_ON(!list_empty(&_pages_jobs));
-
- mempool_destroy(_job_pool);
kmem_cache_destroy(_job_cache);
- _job_pool = NULL;
_job_cache = NULL;
}
@@ -255,18 +241,19 @@ static void jobs_exit(void)
* Functions to push and pop a job onto the head of a given job
* list.
*/
-static struct kcopyd_job *pop(struct list_head *jobs)
+static struct kcopyd_job *pop(struct list_head *jobs,
+ struct dm_kcopyd_client *kc)
{
struct kcopyd_job *job = NULL;
unsigned long flags;
- spin_lock_irqsave(&_job_lock, flags);
+ spin_lock_irqsave(&kc->job_lock, flags);
if (!list_empty(jobs)) {
job = list_entry(jobs->next, struct kcopyd_job, list);
list_del(&job->list);
}
- spin_unlock_irqrestore(&_job_lock, flags);
+ spin_unlock_irqrestore(&kc->job_lock, flags);
return job;
}
@@ -274,10 +261,11 @@ static struct kcopyd_job *pop(struct list_head *jobs)
static void push(struct list_head *jobs, struct kcopyd_job *job)
{
unsigned long flags;
+ struct dm_kcopyd_client *kc = job->kc;
- spin_lock_irqsave(&_job_lock, flags);
+ spin_lock_irqsave(&kc->job_lock, flags);
list_add_tail(&job->list, jobs);
- spin_unlock_irqrestore(&_job_lock, flags);
+ spin_unlock_irqrestore(&kc->job_lock, flags);
}
/*
@@ -294,11 +282,11 @@ static int run_complete_job(struct kcopyd_job *job)
void *context = job->context;
int read_err = job->read_err;
unsigned long write_err = job->write_err;
- kcopyd_notify_fn fn = job->fn;
- struct kcopyd_client *kc = job->kc;
+ dm_kcopyd_notify_fn fn = job->fn;
+ struct dm_kcopyd_client *kc = job->kc;
kcopyd_put_pages(kc, job->pages);
- mempool_free(job, _job_pool);
+ mempool_free(job, kc->job_pool);
fn(read_err, write_err, context);
if (atomic_dec_and_test(&kc->nr_jobs))
@@ -310,6 +298,7 @@ static int run_complete_job(struct kcopyd_job *job)
static void complete_io(unsigned long error, void *context)
{
struct kcopyd_job *job = (struct kcopyd_job *) context;
+ struct dm_kcopyd_client *kc = job->kc;
if (error) {
if (job->rw == WRITE)
@@ -317,22 +306,22 @@ static void complete_io(unsigned long error, void *context)
else
job->read_err = 1;
- if (!test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) {
- push(&_complete_jobs, job);
- wake();
+ if (!test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
+ push(&kc->complete_jobs, job);
+ wake(kc);
return;
}
}
if (job->rw == WRITE)
- push(&_complete_jobs, job);
+ push(&kc->complete_jobs, job);
else {
job->rw = WRITE;
- push(&_io_jobs, job);
+ push(&kc->io_jobs, job);
}
- wake();
+ wake(kc);
}
/*
@@ -343,7 +332,7 @@ static int run_io_job(struct kcopyd_job *job)
{
int r;
struct dm_io_request io_req = {
- .bi_rw = job->rw,
+ .bi_rw = job->rw | (1 << BIO_RW_SYNC),
.mem.type = DM_IO_PAGE_LIST,
.mem.ptr.pl = job->pages,
.mem.offset = job->offset,
@@ -369,7 +358,7 @@ static int run_pages_job(struct kcopyd_job *job)
r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages);
if (!r) {
/* this job is ready for io */
- push(&_io_jobs, job);
+ push(&job->kc->io_jobs, job);
return 0;
}
@@ -384,12 +373,13 @@ static int run_pages_job(struct kcopyd_job *job)
* Run through a list for as long as possible. Returns the count
* of successful jobs.
*/
-static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
+static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
+ int (*fn) (struct kcopyd_job *))
{
struct kcopyd_job *job;
int r, count = 0;
- while ((job = pop(jobs))) {
+ while ((job = pop(jobs, kc))) {
r = fn(job);
@@ -399,7 +389,7 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
job->write_err = (unsigned long) -1L;
else
job->read_err = 1;
- push(&_complete_jobs, job);
+ push(&kc->complete_jobs, job);
break;
}
@@ -421,8 +411,11 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
/*
* kcopyd does this every time it's woken up.
*/
-static void do_work(struct work_struct *ignored)
+static void do_work(struct work_struct *work)
{
+ struct dm_kcopyd_client *kc = container_of(work,
+ struct dm_kcopyd_client, kcopyd_work);
+
/*
* The order that these are called is *very* important.
* complete jobs can free some pages for pages jobs.
@@ -430,9 +423,9 @@ static void do_work(struct work_struct *ignored)
* list. io jobs call wake when they complete and it all
* starts again.
*/
- process_jobs(&_complete_jobs, run_complete_job);
- process_jobs(&_pages_jobs, run_pages_job);
- process_jobs(&_io_jobs, run_io_job);
+ process_jobs(&kc->complete_jobs, kc, run_complete_job);
+ process_jobs(&kc->pages_jobs, kc, run_pages_job);
+ process_jobs(&kc->io_jobs, kc, run_io_job);
}
/*
@@ -442,9 +435,10 @@ static void do_work(struct work_struct *ignored)
*/
static void dispatch_job(struct kcopyd_job *job)
{
- atomic_inc(&job->kc->nr_jobs);
- push(&_pages_jobs, job);
- wake();
+ struct dm_kcopyd_client *kc = job->kc;
+ atomic_inc(&kc->nr_jobs);
+ push(&kc->pages_jobs, job);
+ wake(kc);
}
#define SUB_JOB_SIZE 128
@@ -469,7 +463,7 @@ static void segment_complete(int read_err, unsigned long write_err,
* Only dispatch more work if there hasn't been an error.
*/
if ((!job->read_err && !job->write_err) ||
- test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) {
+ test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
/* get the next chunk of work */
progress = job->progress;
count = job->source.count - progress;
@@ -484,7 +478,8 @@ static void segment_complete(int read_err, unsigned long write_err,
if (count) {
int i;
- struct kcopyd_job *sub_job = mempool_alloc(_job_pool, GFP_NOIO);
+ struct kcopyd_job *sub_job = mempool_alloc(job->kc->job_pool,
+ GFP_NOIO);
*sub_job = *job;
sub_job->source.sector += progress;
@@ -508,7 +503,7 @@ static void segment_complete(int read_err, unsigned long write_err,
* after we've completed.
*/
job->fn(read_err, write_err, job->context);
- mempool_free(job, _job_pool);
+ mempool_free(job, job->kc->job_pool);
}
}
@@ -526,16 +521,16 @@ static void split_job(struct kcopyd_job *job)
segment_complete(0, 0u, job);
}
-int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
- unsigned int num_dests, struct io_region *dests,
- unsigned int flags, kcopyd_notify_fn fn, void *context)
+int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
+ unsigned int num_dests, struct dm_io_region *dests,
+ unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
{
struct kcopyd_job *job;
/*
* Allocate a new job.
*/
- job = mempool_alloc(_job_pool, GFP_NOIO);
+ job = mempool_alloc(kc->job_pool, GFP_NOIO);
/*
* set up for the read.
@@ -569,6 +564,7 @@ int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
return 0;
}
+EXPORT_SYMBOL(dm_kcopyd_copy);
/*
* Cancels a kcopyd job, eg. someone might be deactivating a
@@ -583,126 +579,76 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
#endif /* 0 */
/*-----------------------------------------------------------------
- * Unit setup
+ * Client setup
*---------------------------------------------------------------*/
-static DEFINE_MUTEX(_client_lock);
-static LIST_HEAD(_clients);
-
-static void client_add(struct kcopyd_client *kc)
+int dm_kcopyd_client_create(unsigned int nr_pages,
+ struct dm_kcopyd_client **result)
{
- mutex_lock(&_client_lock);
- list_add(&kc->list, &_clients);
- mutex_unlock(&_client_lock);
-}
-
-static void client_del(struct kcopyd_client *kc)
-{
- mutex_lock(&_client_lock);
- list_del(&kc->list);
- mutex_unlock(&_client_lock);
-}
-
-static DEFINE_MUTEX(kcopyd_init_lock);
-static int kcopyd_clients = 0;
+ int r = -ENOMEM;
+ struct dm_kcopyd_client *kc;
-static int kcopyd_init(void)
-{
- int r;
-
- mutex_lock(&kcopyd_init_lock);
-
- if (kcopyd_clients) {
- /* Already initialized. */
- kcopyd_clients++;
- mutex_unlock(&kcopyd_init_lock);
- return 0;
- }
-
- r = jobs_init();
- if (r) {
- mutex_unlock(&kcopyd_init_lock);
- return r;
- }
-
- _kcopyd_wq = create_singlethread_workqueue("kcopyd");
- if (!_kcopyd_wq) {
- jobs_exit();
- mutex_unlock(&kcopyd_init_lock);
+ kc = kmalloc(sizeof(*kc), GFP_KERNEL);
+ if (!kc)
return -ENOMEM;
- }
-
- kcopyd_clients++;
- INIT_WORK(&_kcopyd_work, do_work);
- mutex_unlock(&kcopyd_init_lock);
- return 0;
-}
-static void kcopyd_exit(void)
-{
- mutex_lock(&kcopyd_init_lock);
- kcopyd_clients--;
- if (!kcopyd_clients) {
- jobs_exit();
- destroy_workqueue(_kcopyd_wq);
- _kcopyd_wq = NULL;
- }
- mutex_unlock(&kcopyd_init_lock);
-}
-
-int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
-{
- int r = 0;
- struct kcopyd_client *kc;
+ spin_lock_init(&kc->lock);
+ spin_lock_init(&kc->job_lock);
+ INIT_LIST_HEAD(&kc->complete_jobs);
+ INIT_LIST_HEAD(&kc->io_jobs);
+ INIT_LIST_HEAD(&kc->pages_jobs);
- r = kcopyd_init();
- if (r)
- return r;
+ kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
+ if (!kc->job_pool)
+ goto bad_slab;
- kc = kmalloc(sizeof(*kc), GFP_KERNEL);
- if (!kc) {
- kcopyd_exit();
- return -ENOMEM;
- }
+ INIT_WORK(&kc->kcopyd_work, do_work);
+ kc->kcopyd_wq = create_singlethread_workqueue("kcopyd");
+ if (!kc->kcopyd_wq)
+ goto bad_workqueue;
- spin_lock_init(&kc->lock);
kc->pages = NULL;
kc->nr_pages = kc->nr_free_pages = 0;
r = client_alloc_pages(kc, nr_pages);
- if (r) {
- kfree(kc);
- kcopyd_exit();
- return r;
- }
+ if (r)
+ goto bad_client_pages;
kc->io_client = dm_io_client_create(nr_pages);
if (IS_ERR(kc->io_client)) {
r = PTR_ERR(kc->io_client);
- client_free_pages(kc);
- kfree(kc);
- kcopyd_exit();
- return r;
+ goto bad_io_client;
}
init_waitqueue_head(&kc->destroyq);
atomic_set(&kc->nr_jobs, 0);
- client_add(kc);
*result = kc;
return 0;
+
+bad_io_client:
+ client_free_pages(kc);
+bad_client_pages:
+ destroy_workqueue(kc->kcopyd_wq);
+bad_workqueue:
+ mempool_destroy(kc->job_pool);
+bad_slab:
+ kfree(kc);
+
+ return r;
}
+EXPORT_SYMBOL(dm_kcopyd_client_create);
-void kcopyd_client_destroy(struct kcopyd_client *kc)
+void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
{
/* Wait for completion of all jobs submitted by this client. */
wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
+ BUG_ON(!list_empty(&kc->complete_jobs));
+ BUG_ON(!list_empty(&kc->io_jobs));
+ BUG_ON(!list_empty(&kc->pages_jobs));
+ destroy_workqueue(kc->kcopyd_wq);
dm_io_client_destroy(kc->io_client);
client_free_pages(kc);
- client_del(kc);
+ mempool_destroy(kc->job_pool);
kfree(kc);
- kcopyd_exit();
}
-
-EXPORT_SYMBOL(kcopyd_client_create);
-EXPORT_SYMBOL(kcopyd_client_destroy);
-EXPORT_SYMBOL(kcopyd_copy);
+EXPORT_SYMBOL(dm_kcopyd_client_destroy);
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 2a74b2142f50..67a6f31b7fc3 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
*
* This file is released under the LGPL.
*/
@@ -8,64 +9,58 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
+#include <linux/dm-io.h>
+#include <linux/dm-dirty-log.h>
-#include "dm-log.h"
-#include "dm-io.h"
+#include "dm.h"
-#define DM_MSG_PREFIX "mirror log"
+#define DM_MSG_PREFIX "dirty region log"
-static LIST_HEAD(_log_types);
-static DEFINE_SPINLOCK(_lock);
+struct dm_dirty_log_internal {
+ struct dm_dirty_log_type *type;
-int dm_register_dirty_log_type(struct dirty_log_type *type)
-{
- spin_lock(&_lock);
- type->use_count = 0;
- list_add(&type->list, &_log_types);
- spin_unlock(&_lock);
+ struct list_head list;
+ long use;
+};
- return 0;
-}
+static LIST_HEAD(_log_types);
+static DEFINE_SPINLOCK(_lock);
-int dm_unregister_dirty_log_type(struct dirty_log_type *type)
+static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name)
{
- spin_lock(&_lock);
-
- if (type->use_count)
- DMWARN("Attempt to unregister a log type that is still in use");
- else
- list_del(&type->list);
+ struct dm_dirty_log_internal *log_type;
- spin_unlock(&_lock);
+ list_for_each_entry(log_type, &_log_types, list)
+ if (!strcmp(name, log_type->type->name))
+ return log_type;
- return 0;
+ return NULL;
}
-static struct dirty_log_type *_get_type(const char *type_name)
+static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
{
- struct dirty_log_type *type;
+ struct dm_dirty_log_internal *log_type;
spin_lock(&_lock);
- list_for_each_entry (type, &_log_types, list)
- if (!strcmp(type_name, type->name)) {
- if (!type->use_count && !try_module_get(type->module)){
- spin_unlock(&_lock);
- return NULL;
- }
- type->use_count++;
- spin_unlock(&_lock);
- return type;
- }
+
+ log_type = __find_dirty_log_type(name);
+ if (log_type) {
+ if (!log_type->use && !try_module_get(log_type->type->module))
+ log_type = NULL;
+ else
+ log_type->use++;
+ }
spin_unlock(&_lock);
- return NULL;
+
+ return log_type;
}
/*
* get_type
* @type_name
*
- * Attempt to retrieve the dirty_log_type by name. If not already
+ * Attempt to retrieve the dm_dirty_log_type by name. If not already
* available, attempt to load the appropriate module.
*
* Log modules are named "dm-log-" followed by the 'type_name'.
@@ -78,14 +73,17 @@ static struct dirty_log_type *_get_type(const char *type_name)
*
* Returns: dirty_log_type* on success, NULL on failure
*/
-static struct dirty_log_type *get_type(const char *type_name)
+static struct dm_dirty_log_type *get_type(const char *type_name)
{
char *p, *type_name_dup;
- struct dirty_log_type *type;
+ struct dm_dirty_log_internal *log_type;
+
+ if (!type_name)
+ return NULL;
- type = _get_type(type_name);
- if (type)
- return type;
+ log_type = _get_dirty_log_type(type_name);
+ if (log_type)
+ return log_type->type;
type_name_dup = kstrdup(type_name, GFP_KERNEL);
if (!type_name_dup) {
@@ -95,34 +93,106 @@ static struct dirty_log_type *get_type(const char *type_name)
}
while (request_module("dm-log-%s", type_name_dup) ||
- !(type = _get_type(type_name))) {
+ !(log_type = _get_dirty_log_type(type_name))) {
p = strrchr(type_name_dup, '-');
if (!p)
break;
p[0] = '\0';
}
- if (!type)
+ if (!log_type)
DMWARN("Module for logging type \"%s\" not found.", type_name);
kfree(type_name_dup);
- return type;
+ return log_type ? log_type->type : NULL;
}
-static void put_type(struct dirty_log_type *type)
+static void put_type(struct dm_dirty_log_type *type)
{
+ struct dm_dirty_log_internal *log_type;
+
+ if (!type)
+ return;
+
spin_lock(&_lock);
- if (!--type->use_count)
+ log_type = __find_dirty_log_type(type->name);
+ if (!log_type)
+ goto out;
+
+ if (!--log_type->use)
module_put(type->module);
+
+ BUG_ON(log_type->use < 0);
+
+out:
spin_unlock(&_lock);
}
-struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,
- unsigned int argc, char **argv)
+static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type)
{
- struct dirty_log_type *type;
- struct dirty_log *log;
+ struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type),
+ GFP_KERNEL);
+
+ if (log_type)
+ log_type->type = type;
+
+ return log_type;
+}
+
+int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
+{
+ struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type);
+ int r = 0;
+
+ if (!log_type)
+ return -ENOMEM;
+
+ spin_lock(&_lock);
+ if (!__find_dirty_log_type(type->name))
+ list_add(&log_type->list, &_log_types);
+ else {
+ kfree(log_type);
+ r = -EEXIST;
+ }
+ spin_unlock(&_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(dm_dirty_log_type_register);
+
+int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
+{
+ struct dm_dirty_log_internal *log_type;
+
+ spin_lock(&_lock);
+
+ log_type = __find_dirty_log_type(type->name);
+ if (!log_type) {
+ spin_unlock(&_lock);
+ return -EINVAL;
+ }
+
+ if (log_type->use) {
+ spin_unlock(&_lock);
+ return -ETXTBSY;
+ }
+
+ list_del(&log_type->list);
+
+ spin_unlock(&_lock);
+ kfree(log_type);
+
+ return 0;
+}
+EXPORT_SYMBOL(dm_dirty_log_type_unregister);
+
+struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
+ struct dm_target *ti,
+ unsigned int argc, char **argv)
+{
+ struct dm_dirty_log_type *type;
+ struct dm_dirty_log *log;
log = kmalloc(sizeof(*log), GFP_KERNEL);
if (!log)
@@ -143,13 +213,15 @@ struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *t
return log;
}
+EXPORT_SYMBOL(dm_dirty_log_create);
-void dm_destroy_dirty_log(struct dirty_log *log)
+void dm_dirty_log_destroy(struct dm_dirty_log *log)
{
log->type->dtr(log);
put_type(log->type);
kfree(log);
}
+EXPORT_SYMBOL(dm_dirty_log_destroy);
/*-----------------------------------------------------------------
* Persistent and core logs share a lot of their implementation.
@@ -207,7 +279,7 @@ struct log_c {
struct dm_dev *log_dev;
struct log_header header;
- struct io_region header_location;
+ struct dm_io_region header_location;
struct log_header *disk_header;
};
@@ -215,7 +287,7 @@ struct log_c {
* The touched member needs to be updated every time we access
* one of the bitsets.
*/
-static inline int log_test_bit(uint32_t *bs, unsigned bit)
+static inline int log_test_bit(uint32_t *bs, unsigned bit)
{
return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0;
}
@@ -302,7 +374,7 @@ static inline int write_header(struct log_c *log)
* argv contains region_size followed optionally by [no]sync
*--------------------------------------------------------------*/
#define BYTE_SHIFT 3
-static int create_log_context(struct dirty_log *log, struct dm_target *ti,
+static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv,
struct dm_dev *dev)
{
@@ -315,7 +387,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
int r;
if (argc < 1 || argc > 2) {
- DMWARN("wrong number of arguments to mirror log");
+ DMWARN("wrong number of arguments to dirty region log");
return -EINVAL;
}
@@ -325,8 +397,8 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
else if (!strcmp(argv[1], "nosync"))
sync = NOSYNC;
else {
- DMWARN("unrecognised sync argument to mirror log: %s",
- argv[1]);
+ DMWARN("unrecognised sync argument to "
+ "dirty region log: %s", argv[1]);
return -EINVAL;
}
}
@@ -434,7 +506,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
return 0;
}
-static int core_ctr(struct dirty_log *log, struct dm_target *ti,
+static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv)
{
return create_log_context(log, ti, argc, argv, NULL);
@@ -447,7 +519,7 @@ static void destroy_log_context(struct log_c *lc)
kfree(lc);
}
-static void core_dtr(struct dirty_log *log)
+static void core_dtr(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
@@ -460,14 +532,14 @@ static void core_dtr(struct dirty_log *log)
*
* argv contains log_device region_size followed optionally by [no]sync
*--------------------------------------------------------------*/
-static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
+static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv)
{
int r;
struct dm_dev *dev;
if (argc < 2 || argc > 3) {
- DMWARN("wrong number of arguments to disk mirror log");
+ DMWARN("wrong number of arguments to disk dirty region log");
return -EINVAL;
}
@@ -485,7 +557,7 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
return 0;
}
-static void disk_dtr(struct dirty_log *log)
+static void disk_dtr(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
@@ -514,7 +586,7 @@ static void fail_log_device(struct log_c *lc)
dm_table_event(lc->ti->table);
}
-static int disk_resume(struct dirty_log *log)
+static int disk_resume(struct dm_dirty_log *log)
{
int r;
unsigned i;
@@ -524,7 +596,7 @@ static int disk_resume(struct dirty_log *log)
/* read the disk header */
r = read_header(lc);
if (r) {
- DMWARN("%s: Failed to read header on mirror log device",
+ DMWARN("%s: Failed to read header on dirty region log device",
lc->log_dev->name);
fail_log_device(lc);
/*
@@ -562,7 +634,7 @@ static int disk_resume(struct dirty_log *log)
/* write the new header */
r = write_header(lc);
if (r) {
- DMWARN("%s: Failed to write header on mirror log device",
+ DMWARN("%s: Failed to write header on dirty region log device",
lc->log_dev->name);
fail_log_device(lc);
}
@@ -570,38 +642,38 @@ static int disk_resume(struct dirty_log *log)
return r;
}
-static uint32_t core_get_region_size(struct dirty_log *log)
+static uint32_t core_get_region_size(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
return lc->region_size;
}
-static int core_resume(struct dirty_log *log)
+static int core_resume(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
lc->sync_search = 0;
return 0;
}
-static int core_is_clean(struct dirty_log *log, region_t region)
+static int core_is_clean(struct dm_dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
return log_test_bit(lc->clean_bits, region);
}
-static int core_in_sync(struct dirty_log *log, region_t region, int block)
+static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
{
struct log_c *lc = (struct log_c *) log->context;
return log_test_bit(lc->sync_bits, region);
}
-static int core_flush(struct dirty_log *log)
+static int core_flush(struct dm_dirty_log *log)
{
/* no op */
return 0;
}
-static int disk_flush(struct dirty_log *log)
+static int disk_flush(struct dm_dirty_log *log)
{
int r;
struct log_c *lc = (struct log_c *) log->context;
@@ -619,19 +691,19 @@ static int disk_flush(struct dirty_log *log)
return r;
}
-static void core_mark_region(struct dirty_log *log, region_t region)
+static void core_mark_region(struct dm_dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
log_clear_bit(lc, lc->clean_bits, region);
}
-static void core_clear_region(struct dirty_log *log, region_t region)
+static void core_clear_region(struct dm_dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
log_set_bit(lc, lc->clean_bits, region);
}
-static int core_get_resync_work(struct dirty_log *log, region_t *region)
+static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
{
struct log_c *lc = (struct log_c *) log->context;
@@ -654,7 +726,7 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region)
return 1;
}
-static void core_set_region_sync(struct dirty_log *log, region_t region,
+static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
int in_sync)
{
struct log_c *lc = (struct log_c *) log->context;
@@ -669,7 +741,7 @@ static void core_set_region_sync(struct dirty_log *log, region_t region,
}
}
-static region_t core_get_sync_count(struct dirty_log *log)
+static region_t core_get_sync_count(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
@@ -680,7 +752,7 @@ static region_t core_get_sync_count(struct dirty_log *log)
if (lc->sync != DEFAULTSYNC) \
DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
-static int core_status(struct dirty_log *log, status_type_t status,
+static int core_status(struct dm_dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
{
int sz = 0;
@@ -700,7 +772,7 @@ static int core_status(struct dirty_log *log, status_type_t status,
return sz;
}
-static int disk_status(struct dirty_log *log, status_type_t status,
+static int disk_status(struct dm_dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
{
int sz = 0;
@@ -722,7 +794,7 @@ static int disk_status(struct dirty_log *log, status_type_t status,
return sz;
}
-static struct dirty_log_type _core_type = {
+static struct dm_dirty_log_type _core_type = {
.name = "core",
.module = THIS_MODULE,
.ctr = core_ctr,
@@ -740,7 +812,7 @@ static struct dirty_log_type _core_type = {
.status = core_status,
};
-static struct dirty_log_type _disk_type = {
+static struct dm_dirty_log_type _disk_type = {
.name = "disk",
.module = THIS_MODULE,
.ctr = disk_ctr,
@@ -763,26 +835,28 @@ int __init dm_dirty_log_init(void)
{
int r;
- r = dm_register_dirty_log_type(&_core_type);
+ r = dm_dirty_log_type_register(&_core_type);
if (r)
DMWARN("couldn't register core log");
- r = dm_register_dirty_log_type(&_disk_type);
+ r = dm_dirty_log_type_register(&_disk_type);
if (r) {
DMWARN("couldn't register disk type");
- dm_unregister_dirty_log_type(&_core_type);
+ dm_dirty_log_type_unregister(&_core_type);
}
return r;
}
-void dm_dirty_log_exit(void)
+void __exit dm_dirty_log_exit(void)
{
- dm_unregister_dirty_log_type(&_disk_type);
- dm_unregister_dirty_log_type(&_core_type);
+ dm_dirty_log_type_unregister(&_disk_type);
+ dm_dirty_log_type_unregister(&_core_type);
}
-EXPORT_SYMBOL(dm_register_dirty_log_type);
-EXPORT_SYMBOL(dm_unregister_dirty_log_type);
-EXPORT_SYMBOL(dm_create_dirty_log);
-EXPORT_SYMBOL(dm_destroy_dirty_log);
+module_init(dm_dirty_log_init);
+module_exit(dm_dirty_log_exit);
+
+MODULE_DESCRIPTION(DM_NAME " dirty region log");
+MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 762cb086bb7f..ff05fe893083 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -7,9 +7,6 @@
#include "dm.h"
#include "dm-bio-list.h"
#include "dm-bio-record.h"
-#include "dm-io.h"
-#include "dm-log.h"
-#include "kcopyd.h"
#include <linux/ctype.h>
#include <linux/init.h>
@@ -22,6 +19,9 @@
#include <linux/workqueue.h>
#include <linux/log2.h>
#include <linux/hardirq.h>
+#include <linux/dm-io.h>
+#include <linux/dm-dirty-log.h>
+#include <linux/dm-kcopyd.h>
#define DM_MSG_PREFIX "raid1"
#define DM_IO_PAGES 64
@@ -74,7 +74,7 @@ struct region_hash {
unsigned region_shift;
/* holds persistent region state */
- struct dirty_log *log;
+ struct dm_dirty_log *log;
/* hash table */
rwlock_t hash_lock;
@@ -133,7 +133,7 @@ struct mirror_set {
struct dm_target *ti;
struct list_head list;
struct region_hash rh;
- struct kcopyd_client *kcopyd_client;
+ struct dm_kcopyd_client *kcopyd_client;
uint64_t features;
spinlock_t lock; /* protects the lists */
@@ -154,6 +154,9 @@ struct mirror_set {
struct workqueue_struct *kmirrord_wq;
struct work_struct kmirrord_work;
+ struct timer_list timer;
+ unsigned long timer_pending;
+
struct work_struct trigger_event;
unsigned int nr_mirrors;
@@ -178,13 +181,32 @@ static void wake(struct mirror_set *ms)
queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
}
+static void delayed_wake_fn(unsigned long data)
+{
+ struct mirror_set *ms = (struct mirror_set *) data;
+
+ clear_bit(0, &ms->timer_pending);
+ wake(ms);
+}
+
+static void delayed_wake(struct mirror_set *ms)
+{
+ if (test_and_set_bit(0, &ms->timer_pending))
+ return;
+
+ ms->timer.expires = jiffies + HZ / 5;
+ ms->timer.data = (unsigned long) ms;
+ ms->timer.function = delayed_wake_fn;
+ add_timer(&ms->timer);
+}
+
/* FIXME move this */
static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
#define MIN_REGIONS 64
#define MAX_RECOVERY 1
static int rh_init(struct region_hash *rh, struct mirror_set *ms,
- struct dirty_log *log, uint32_t region_size,
+ struct dm_dirty_log *log, uint32_t region_size,
region_t nr_regions)
{
unsigned int nr_buckets, max_buckets;
@@ -249,7 +271,7 @@ static void rh_exit(struct region_hash *rh)
}
if (rh->log)
- dm_destroy_dirty_log(rh->log);
+ dm_dirty_log_destroy(rh->log);
if (rh->region_pool)
mempool_destroy(rh->region_pool);
vfree(rh->buckets);
@@ -405,24 +427,22 @@ static void rh_update_states(struct region_hash *rh)
write_lock_irq(&rh->hash_lock);
spin_lock(&rh->region_lock);
if (!list_empty(&rh->clean_regions)) {
- list_splice(&rh->clean_regions, &clean);
- INIT_LIST_HEAD(&rh->clean_regions);
+ list_splice_init(&rh->clean_regions, &clean);
list_for_each_entry(reg, &clean, list)
list_del(&reg->hash_list);
}
if (!list_empty(&rh->recovered_regions)) {
- list_splice(&rh->recovered_regions, &recovered);
- INIT_LIST_HEAD(&rh->recovered_regions);
+ list_splice_init(&rh->recovered_regions, &recovered);
list_for_each_entry (reg, &recovered, list)
list_del(&reg->hash_list);
}
if (!list_empty(&rh->failed_recovered_regions)) {
- list_splice(&rh->failed_recovered_regions, &failed_recovered);
- INIT_LIST_HEAD(&rh->failed_recovered_regions);
+ list_splice_init(&rh->failed_recovered_regions,
+ &failed_recovered);
list_for_each_entry(reg, &failed_recovered, list)
list_del(&reg->hash_list);
@@ -790,7 +810,7 @@ static int recover(struct mirror_set *ms, struct region *reg)
{
int r;
unsigned int i;
- struct io_region from, to[KCOPYD_MAX_REGIONS], *dest;
+ struct dm_io_region from, to[DM_KCOPYD_MAX_REGIONS], *dest;
struct mirror *m;
unsigned long flags = 0;
@@ -822,9 +842,9 @@ static int recover(struct mirror_set *ms, struct region *reg)
}
/* hand to kcopyd */
- set_bit(KCOPYD_IGNORE_ERROR, &flags);
- r = kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, flags,
- recovery_complete, reg);
+ set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+ r = dm_kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to,
+ flags, recovery_complete, reg);
return r;
}
@@ -833,7 +853,7 @@ static void do_recovery(struct mirror_set *ms)
{
int r;
struct region *reg;
- struct dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = ms->rh.log;
/*
* Start quiescing some regions.
@@ -909,7 +929,7 @@ static void map_bio(struct mirror *m, struct bio *bio)
bio->bi_sector = map_sector(m, bio);
}
-static void map_region(struct io_region *io, struct mirror *m,
+static void map_region(struct dm_io_region *io, struct mirror *m,
struct bio *bio)
{
io->bdev = m->dev->bdev;
@@ -951,7 +971,7 @@ static void read_callback(unsigned long error, void *context)
/* Asynchronous read. */
static void read_async_bio(struct mirror *m, struct bio *bio)
{
- struct io_region io;
+ struct dm_io_region io;
struct dm_io_request io_req = {
.bi_rw = READ,
.mem.type = DM_IO_BVEC,
@@ -1019,7 +1039,7 @@ static void __bio_mark_nosync(struct mirror_set *ms,
{
unsigned long flags;
struct region_hash *rh = &ms->rh;
- struct dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = ms->rh.log;
struct region *reg;
region_t region = bio_to_region(rh, bio);
int recovering = 0;
@@ -1107,7 +1127,7 @@ out:
static void do_write(struct mirror_set *ms, struct bio *bio)
{
unsigned int i;
- struct io_region io[ms->nr_mirrors], *dest = io;
+ struct dm_io_region io[ms->nr_mirrors], *dest = io;
struct mirror *m;
struct dm_io_request io_req = {
.bi_rw = WRITE,
@@ -1182,6 +1202,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
spin_lock_irq(&ms->lock);
bio_list_merge(&ms->failures, &sync);
spin_unlock_irq(&ms->lock);
+ wake(ms);
} else
while ((bio = bio_list_pop(&sync)))
do_write(ms, bio);
@@ -1241,7 +1262,7 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures)
bio_list_merge(&ms->failures, failures);
spin_unlock_irq(&ms->lock);
- wake(ms);
+ delayed_wake(ms);
}
static void trigger_event(struct work_struct *work)
@@ -1255,7 +1276,7 @@ static void trigger_event(struct work_struct *work)
/*-----------------------------------------------------------------
* kmirrord
*---------------------------------------------------------------*/
-static int _do_mirror(struct work_struct *work)
+static void do_mirror(struct work_struct *work)
{
struct mirror_set *ms =container_of(work, struct mirror_set,
kmirrord_work);
@@ -1277,23 +1298,7 @@ static int _do_mirror(struct work_struct *work)
do_writes(ms, &writes);
do_failures(ms, &failures);
- return (ms->failures.head) ? 1 : 0;
-}
-
-static void do_mirror(struct work_struct *work)
-{
- /*
- * If _do_mirror returns 1, we give it
- * another shot. This helps for cases like
- * 'suspend' where we call flush_workqueue
- * and expect all work to be finished. If
- * a failure happens during a suspend, we
- * couldn't issue a 'wake' because it would
- * not be honored. Therefore, we return '1'
- * from _do_mirror, and retry here.
- */
- while (_do_mirror(work))
- schedule();
+ dm_table_unplug_all(ms->ti->table);
}
@@ -1303,7 +1308,7 @@ static void do_mirror(struct work_struct *work)
static struct mirror_set *alloc_context(unsigned int nr_mirrors,
uint32_t region_size,
struct dm_target *ti,
- struct dirty_log *dl)
+ struct dm_dirty_log *dl)
{
size_t len;
struct mirror_set *ms = NULL;
@@ -1403,12 +1408,12 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
/*
* Create dirty log: log_type #log_params <log_params>
*/
-static struct dirty_log *create_dirty_log(struct dm_target *ti,
+static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
unsigned int argc, char **argv,
unsigned int *args_used)
{
unsigned int param_count;
- struct dirty_log *dl;
+ struct dm_dirty_log *dl;
if (argc < 2) {
ti->error = "Insufficient mirror log arguments";
@@ -1427,7 +1432,7 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
return NULL;
}
- dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2);
+ dl = dm_dirty_log_create(argv[0], ti, param_count, argv + 2);
if (!dl) {
ti->error = "Error creating mirror dirty log";
return NULL;
@@ -1435,7 +1440,7 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
if (!_check_region_size(ti, dl->type->get_region_size(dl))) {
ti->error = "Invalid region size";
- dm_destroy_dirty_log(dl);
+ dm_dirty_log_destroy(dl);
return NULL;
}
@@ -1496,7 +1501,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
int r;
unsigned int nr_mirrors, m, args_used;
struct mirror_set *ms;
- struct dirty_log *dl;
+ struct dm_dirty_log *dl;
dl = create_dirty_log(ti, argc, argv, &args_used);
if (!dl)
@@ -1506,9 +1511,9 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argc -= args_used;
if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
- nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) {
+ nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) {
ti->error = "Invalid number of mirrors";
- dm_destroy_dirty_log(dl);
+ dm_dirty_log_destroy(dl);
return -EINVAL;
}
@@ -1516,13 +1521,13 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (argc < nr_mirrors * 2) {
ti->error = "Too few mirror arguments";
- dm_destroy_dirty_log(dl);
+ dm_dirty_log_destroy(dl);
return -EINVAL;
}
ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl);
if (!ms) {
- dm_destroy_dirty_log(dl);
+ dm_dirty_log_destroy(dl);
return -ENOMEM;
}
@@ -1547,6 +1552,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto err_free_context;
}
INIT_WORK(&ms->kmirrord_work, do_mirror);
+ init_timer(&ms->timer);
+ ms->timer_pending = 0;
INIT_WORK(&ms->trigger_event, trigger_event);
r = parse_features(ms, argc, argv, &args_used);
@@ -1571,7 +1578,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto err_destroy_wq;
}
- r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
+ r = dm_kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
if (r)
goto err_destroy_wq;
@@ -1589,8 +1596,9 @@ static void mirror_dtr(struct dm_target *ti)
{
struct mirror_set *ms = (struct mirror_set *) ti->private;
+ del_timer_sync(&ms->timer);
flush_workqueue(ms->kmirrord_wq);
- kcopyd_client_destroy(ms->kcopyd_client);
+ dm_kcopyd_client_destroy(ms->kcopyd_client);
destroy_workqueue(ms->kmirrord_wq);
free_context(ms, ti, ms->nr_mirrors);
}
@@ -1734,7 +1742,7 @@ out:
static void mirror_presuspend(struct dm_target *ti)
{
struct mirror_set *ms = (struct mirror_set *) ti->private;
- struct dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = ms->rh.log;
atomic_set(&ms->suspend, 1);
@@ -1763,7 +1771,7 @@ static void mirror_presuspend(struct dm_target *ti)
static void mirror_postsuspend(struct dm_target *ti)
{
struct mirror_set *ms = ti->private;
- struct dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = ms->rh.log;
if (log->type->postsuspend && log->type->postsuspend(log))
/* FIXME: need better error handling */
@@ -1773,7 +1781,7 @@ static void mirror_postsuspend(struct dm_target *ti)
static void mirror_resume(struct dm_target *ti)
{
struct mirror_set *ms = ti->private;
- struct dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = ms->rh.log;
atomic_set(&ms->suspend, 0);
if (log->type->resume && log->type->resume(log))
@@ -1811,7 +1819,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
{
unsigned int m, sz = 0;
struct mirror_set *ms = (struct mirror_set *) ti->private;
- struct dirty_log *log = ms->rh.log;
+ struct dm_dirty_log *log = ms->rh.log;
char buffer[ms->nr_mirrors + 1];
switch (type) {
@@ -1864,15 +1872,9 @@ static int __init dm_mirror_init(void)
{
int r;
- r = dm_dirty_log_init();
- if (r)
- return r;
-
r = dm_register_target(&mirror_target);
- if (r < 0) {
+ if (r < 0)
DMERR("Failed to register mirror target");
- dm_dirty_log_exit();
- }
return r;
}
@@ -1884,8 +1886,6 @@ static void __exit dm_mirror_exit(void)
r = dm_unregister_target(&mirror_target);
if (r < 0)
DMERR("unregister failed %d", r);
-
- dm_dirty_log_exit();
}
/* Module hooks */
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 4dc8a43c034b..1ba8a47d61b1 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -18,10 +18,10 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/log2.h>
+#include <linux/dm-kcopyd.h>
#include "dm-snap.h"
#include "dm-bio-list.h"
-#include "kcopyd.h"
#define DM_MSG_PREFIX "snapshots"
@@ -36,9 +36,9 @@
#define SNAPSHOT_COPY_PRIORITY 2
/*
- * Each snapshot reserves this many pages for io
+ * Reserve 1MB for each snapshot initially (with minimum of 1 page).
*/
-#define SNAPSHOT_PAGES 256
+#define SNAPSHOT_PAGES (((1UL << 20) >> PAGE_SHIFT) ? : 1)
static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);
@@ -536,7 +536,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
s->last_percent = 0;
init_rwsem(&s->lock);
spin_lock_init(&s->pe_lock);
- s->table = ti->table;
+ s->ti = ti;
/* Allocate hash table for COW data */
if (init_hash_tables(s)) {
@@ -558,7 +558,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad4;
}
- r = kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
+ r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
if (r) {
ti->error = "Could not create kcopyd client";
goto bad5;
@@ -591,7 +591,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return 0;
bad6:
- kcopyd_client_destroy(s->kcopyd_client);
+ dm_kcopyd_client_destroy(s->kcopyd_client);
bad5:
s->store.destroy(&s->store);
@@ -613,7 +613,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
static void __free_exceptions(struct dm_snapshot *s)
{
- kcopyd_client_destroy(s->kcopyd_client);
+ dm_kcopyd_client_destroy(s->kcopyd_client);
s->kcopyd_client = NULL;
exit_exception_table(&s->pending, pending_cache);
@@ -699,7 +699,7 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
s->valid = 0;
- dm_table_event(s->table);
+ dm_table_event(s->ti->table);
}
static void get_pending_exception(struct dm_snap_pending_exception *pe)
@@ -824,7 +824,7 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)
static void start_copy(struct dm_snap_pending_exception *pe)
{
struct dm_snapshot *s = pe->snap;
- struct io_region src, dest;
+ struct dm_io_region src, dest;
struct block_device *bdev = s->origin->bdev;
sector_t dev_size;
@@ -839,7 +839,7 @@ static void start_copy(struct dm_snap_pending_exception *pe)
dest.count = src.count;
/* Hand over to kcopyd */
- kcopyd_copy(s->kcopyd_client,
+ dm_kcopyd_copy(s->kcopyd_client,
&src, 1, &dest, 0, copy_callback, pe);
}
@@ -1060,7 +1060,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
goto next_snapshot;
/* Nothing to do if writing beyond end of snapshot */
- if (bio->bi_sector >= dm_table_get_size(snap->table))
+ if (bio->bi_sector >= dm_table_get_size(snap->ti->table))
goto next_snapshot;
/*
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
index 93bce5d49742..24f9fb73b982 100644
--- a/drivers/md/dm-snap.h
+++ b/drivers/md/dm-snap.h
@@ -132,7 +132,7 @@ struct exception_store {
struct dm_snapshot {
struct rw_semaphore lock;
- struct dm_table *table;
+ struct dm_target *ti;
struct dm_dev *origin;
struct dm_dev *cow;
@@ -169,7 +169,7 @@ struct dm_snapshot {
/* The on disk metadata handler */
struct exception_store store;
- struct kcopyd_client *kcopyd_client;
+ struct dm_kcopyd_client *kcopyd_client;
/* Queue of snapshot writes for ksnapd to flush */
struct bio_list queued_bios;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index e75b1437b58b..51be53344214 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -245,44 +245,6 @@ int dm_table_create(struct dm_table **result, int mode,
return 0;
}
-int dm_create_error_table(struct dm_table **result, struct mapped_device *md)
-{
- struct dm_table *t;
- sector_t dev_size = 1;
- int r;
-
- /*
- * Find current size of device.
- * Default to 1 sector if inactive.
- */
- t = dm_get_table(md);
- if (t) {
- dev_size = dm_table_get_size(t);
- dm_table_put(t);
- }
-
- r = dm_table_create(&t, FMODE_READ, 1, md);
- if (r)
- return r;
-
- r = dm_table_add_target(t, "error", 0, dev_size, NULL);
- if (r)
- goto out;
-
- r = dm_table_complete(t);
- if (r)
- goto out;
-
- *result = t;
-
-out:
- if (r)
- dm_table_put(t);
-
- return r;
-}
-EXPORT_SYMBOL_GPL(dm_create_error_table);
-
static void free_devices(struct list_head *devices)
{
struct list_head *tmp, *next;
@@ -954,7 +916,7 @@ void dm_table_presuspend_targets(struct dm_table *t)
if (!t)
return;
- return suspend_targets(t, 0);
+ suspend_targets(t, 0);
}
void dm_table_postsuspend_targets(struct dm_table *t)
@@ -962,7 +924,7 @@ void dm_table_postsuspend_targets(struct dm_table *t)
if (!t)
return;
- return suspend_targets(t, 1);
+ suspend_targets(t, 1);
}
int dm_table_resume_targets(struct dm_table *t)
diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c
index 50377e5dc2a3..6f65883aef12 100644
--- a/drivers/md/dm-uevent.c
+++ b/drivers/md/dm-uevent.c
@@ -78,7 +78,7 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
event = dm_uevent_alloc(md);
if (!event) {
- DMERR("%s: dm_uevent_alloc() failed", __FUNCTION__);
+ DMERR("%s: dm_uevent_alloc() failed", __func__);
goto err_nomem;
}
@@ -86,32 +86,32 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) {
DMERR("%s: add_uevent_var() for DM_TARGET failed",
- __FUNCTION__);
+ __func__);
goto err_add;
}
if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) {
DMERR("%s: add_uevent_var() for DM_ACTION failed",
- __FUNCTION__);
+ __func__);
goto err_add;
}
if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u",
dm_next_uevent_seq(md))) {
DMERR("%s: add_uevent_var() for DM_SEQNUM failed",
- __FUNCTION__);
+ __func__);
goto err_add;
}
if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) {
- DMERR("%s: add_uevent_var() for DM_PATH failed", __FUNCTION__);
+ DMERR("%s: add_uevent_var() for DM_PATH failed", __func__);
goto err_add;
}
if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d",
nr_valid_paths)) {
DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed",
- __FUNCTION__);
+ __func__);
goto err_add;
}
@@ -146,25 +146,25 @@ void dm_send_uevents(struct list_head *events, struct kobject *kobj)
if (dm_copy_name_and_uuid(event->md, event->name,
event->uuid)) {
DMERR("%s: dm_copy_name_and_uuid() failed",
- __FUNCTION__);
+ __func__);
goto uevent_free;
}
if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) {
DMERR("%s: add_uevent_var() for DM_NAME failed",
- __FUNCTION__);
+ __func__);
goto uevent_free;
}
if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) {
DMERR("%s: add_uevent_var() for DM_UUID failed",
- __FUNCTION__);
+ __func__);
goto uevent_free;
}
r = kobject_uevent_env(kobj, event->action, event->ku_env.envp);
if (r)
- DMERR("%s: kobject_uevent_env failed", __FUNCTION__);
+ DMERR("%s: kobject_uevent_env failed", __func__);
uevent_free:
dm_uevent_free(event);
}
@@ -187,7 +187,7 @@ void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
struct dm_uevent *event;
if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) {
- DMERR("%s: Invalid event_type %d", __FUNCTION__, event_type);
+ DMERR("%s: Invalid event_type %d", __func__, event_type);
goto out;
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 6617ce4af095..372369b1cc20 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -204,6 +204,7 @@ static int (*_inits[])(void) __initdata = {
dm_target_init,
dm_linear_init,
dm_stripe_init,
+ dm_kcopyd_init,
dm_interface_init,
};
@@ -212,6 +213,7 @@ static void (*_exits[])(void) = {
dm_target_exit,
dm_linear_exit,
dm_stripe_exit,
+ dm_kcopyd_exit,
dm_interface_exit,
};
@@ -922,7 +924,7 @@ static void free_minor(int minor)
/*
* See if the device with a specific minor # is free.
*/
-static int specific_minor(struct mapped_device *md, int minor)
+static int specific_minor(int minor)
{
int r, m;
@@ -955,7 +957,7 @@ out:
return r;
}
-static int next_free_minor(struct mapped_device *md, int *minor)
+static int next_free_minor(int *minor)
{
int r, m;
@@ -966,9 +968,8 @@ static int next_free_minor(struct mapped_device *md, int *minor)
spin_lock(&_minor_lock);
r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m);
- if (r) {
+ if (r)
goto out;
- }
if (m >= (1 << MINORBITS)) {
idr_remove(&_minor_idr, m);
@@ -991,7 +992,7 @@ static struct block_device_operations dm_blk_dops;
static struct mapped_device *alloc_dev(int minor)
{
int r;
- struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
+ struct mapped_device *md = kzalloc(sizeof(*md), GFP_KERNEL);
void *old_md;
if (!md) {
@@ -1004,13 +1005,12 @@ static struct mapped_device *alloc_dev(int minor)
/* get a minor number for the dev */
if (minor == DM_ANY_MINOR)
- r = next_free_minor(md, &minor);
+ r = next_free_minor(&minor);
else
- r = specific_minor(md, minor);
+ r = specific_minor(minor);
if (r < 0)
goto bad_minor;
- memset(md, 0, sizeof(*md));
init_rwsem(&md->io_lock);
mutex_init(&md->suspend_lock);
spin_lock_init(&md->pushback_lock);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index b4584a39383b..8c03b634e62e 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -16,67 +16,6 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
-#define DM_NAME "device-mapper"
-
-#define DMERR(f, arg...) \
- printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMERR_LIMIT(f, arg...) \
- do { \
- if (printk_ratelimit()) \
- printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \
- f "\n", ## arg); \
- } while (0)
-
-#define DMWARN(f, arg...) \
- printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMWARN_LIMIT(f, arg...) \
- do { \
- if (printk_ratelimit()) \
- printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \
- f "\n", ## arg); \
- } while (0)
-
-#define DMINFO(f, arg...) \
- printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMINFO_LIMIT(f, arg...) \
- do { \
- if (printk_ratelimit()) \
- printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \
- "\n", ## arg); \
- } while (0)
-
-#ifdef CONFIG_DM_DEBUG
-# define DMDEBUG(f, arg...) \
- printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
-# define DMDEBUG_LIMIT(f, arg...) \
- do { \
- if (printk_ratelimit()) \
- printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \
- "\n", ## arg); \
- } while (0)
-#else
-# define DMDEBUG(f, arg...) do {} while (0)
-# define DMDEBUG_LIMIT(f, arg...) do {} while (0)
-#endif
-
-#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
- 0 : scnprintf(result + sz, maxlen - sz, x))
-
-#define SECTOR_SHIFT 9
-
-/*
- * Definitions of return values from target end_io function.
- */
-#define DM_ENDIO_INCOMPLETE 1
-#define DM_ENDIO_REQUEUE 2
-
-/*
- * Definitions of return values from target map function.
- */
-#define DM_MAPIO_SUBMITTED 0
-#define DM_MAPIO_REMAPPED 1
-#define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE
-
/*
* Suspend feature flags
*/
@@ -136,34 +75,6 @@ static inline int array_too_big(unsigned long fixed, unsigned long obj,
return (num > (ULONG_MAX - fixed) / obj);
}
-/*
- * Ceiling(n / sz)
- */
-#define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz))
-
-#define dm_sector_div_up(n, sz) ( \
-{ \
- sector_t _r = ((n) + (sz) - 1); \
- sector_div(_r, (sz)); \
- _r; \
-} \
-)
-
-/*
- * ceiling(n / size) * size
- */
-#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
-
-static inline sector_t to_sector(unsigned long n)
-{
- return (n >> 9);
-}
-
-static inline unsigned long to_bytes(sector_t n)
-{
- return (n << 9);
-}
-
int dm_split_args(int *argc, char ***argvp, char *input);
/*
@@ -189,4 +100,13 @@ int dm_lock_for_deletion(struct mapped_device *md);
void dm_kobject_uevent(struct mapped_device *md);
+/*
+ * Dirty log
+ */
+int dm_dirty_log_init(void);
+void dm_dirty_log_exit(void);
+
+int dm_kcopyd_init(void);
+void dm_kcopyd_exit(void);
+
#endif
diff --git a/drivers/md/kcopyd.h b/drivers/md/kcopyd.h
deleted file mode 100644
index 4845f2a0c676..000000000000
--- a/drivers/md/kcopyd.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2001 Sistina Software
- *
- * This file is released under the GPL.
- *
- * Kcopyd provides a simple interface for copying an area of one
- * block-device to one or more other block-devices, with an asynchronous
- * completion notification.
- */
-
-#ifndef DM_KCOPYD_H
-#define DM_KCOPYD_H
-
-#include "dm-io.h"
-
-/* FIXME: make this configurable */
-#define KCOPYD_MAX_REGIONS 8
-
-#define KCOPYD_IGNORE_ERROR 1
-
-/*
- * To use kcopyd you must first create a kcopyd client object.
- */
-struct kcopyd_client;
-int kcopyd_client_create(unsigned int num_pages, struct kcopyd_client **result);
-void kcopyd_client_destroy(struct kcopyd_client *kc);
-
-/*
- * Submit a copy job to kcopyd. This is built on top of the
- * previous three fns.
- *
- * read_err is a boolean,
- * write_err is a bitset, with 1 bit for each destination region
- */
-typedef void (*kcopyd_notify_fn)(int read_err, unsigned long write_err,
- void *context);
-
-int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
- unsigned int num_dests, struct io_region *dests,
- unsigned int flags, kcopyd_notify_fn fn, void *context);
-
-#endif
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5ebfb4d79901..87620b705bee 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -731,9 +731,9 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
else
rdev->desc_nr = sb->this_disk.number;
- if (refdev == 0)
+ if (!refdev) {
ret = 1;
- else {
+ } else {
__u64 ev1, ev2;
mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page);
if (!uuid_equal(refsb, sb)) {
@@ -1116,9 +1116,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
else
rdev->desc_nr = le32_to_cpu(sb->dev_number);
- if (refdev == 0)
+ if (!refdev) {
ret = 1;
- else {
+ } else {
__u64 ev1, ev2;
struct mdp_superblock_1 *refsb =
(struct mdp_superblock_1*)page_address(refdev->sb_page);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 3f299d835a2b..42ee1a2dc144 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -244,7 +244,8 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)
conf->working_disks--;
mddev->degraded++;
printk(KERN_ALERT "multipath: IO failure on %s,"
- " disabling IO path. \n Operation continuing"
+ " disabling IO path.\n"
+ "multipath: Operation continuing"
" on %d IO paths.\n",
bdevname (rdev->bdev,b),
conf->working_disks);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index ff61b309129a..9fd473a6dbf5 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1008,8 +1008,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
} else
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
- printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
- " Operation continuing on %d devices\n",
+ printk(KERN_ALERT "raid1: Disk failure on %s, disabling device.\n"
+ "raid1: Operation continuing on %d devices.\n",
bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 32389d2f18fc..1e96aa3ff513 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1001,8 +1001,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
}
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
- printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
- " Operation continuing on %d devices\n",
+ printk(KERN_ALERT "raid10: Disk failure on %s, disabling device.\n"
+ "raid10: Operation continuing on %d devices.\n",
bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index b162b839a662..968dacaced6d 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -63,6 +63,7 @@
#define STRIPE_SHIFT (PAGE_SHIFT - 9)
#define STRIPE_SECTORS (STRIPE_SIZE>>9)
#define IO_THRESHOLD 1
+#define BYPASS_THRESHOLD 1
#define NR_HASH (PAGE_SIZE / sizeof(struct hlist_head))
#define HASH_MASK (NR_HASH - 1)
@@ -398,6 +399,7 @@ static void ops_run_io(struct stripe_head *sh)
might_sleep();
+ set_bit(STRIPE_IO_STARTED, &sh->state);
for (i = disks; i--; ) {
int rw;
struct bio *bi;
@@ -433,7 +435,7 @@ static void ops_run_io(struct stripe_head *sh)
bi->bi_bdev = rdev->bdev;
pr_debug("%s: for %llu schedule op %ld on disc %d\n",
- __FUNCTION__, (unsigned long long)sh->sector,
+ __func__, (unsigned long long)sh->sector,
bi->bi_rw, i);
atomic_inc(&sh->count);
bi->bi_sector = sh->sector + rdev->data_offset;
@@ -520,7 +522,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
raid5_conf_t *conf = sh->raid_conf;
int i;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
/* clear completed biofills */
@@ -569,7 +571,7 @@ static void ops_run_biofill(struct stripe_head *sh)
raid5_conf_t *conf = sh->raid_conf;
int i;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
for (i = sh->disks; i--; ) {
@@ -600,7 +602,7 @@ static void ops_complete_compute5(void *stripe_head_ref)
int target = sh->ops.target;
struct r5dev *tgt = &sh->dev[target];
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
set_bit(R5_UPTODATE, &tgt->flags);
@@ -625,7 +627,7 @@ ops_run_compute5(struct stripe_head *sh, unsigned long pending)
int i;
pr_debug("%s: stripe %llu block: %d\n",
- __FUNCTION__, (unsigned long long)sh->sector, target);
+ __func__, (unsigned long long)sh->sector, target);
BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags));
for (i = disks; i--; )
@@ -653,7 +655,7 @@ static void ops_complete_prexor(void *stripe_head_ref)
{
struct stripe_head *sh = stripe_head_ref;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
set_bit(STRIPE_OP_PREXOR, &sh->ops.complete);
@@ -670,7 +672,7 @@ ops_run_prexor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
/* existing parity data subtracted */
struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
for (i = disks; i--; ) {
@@ -699,7 +701,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx,
*/
int prexor = test_bit(STRIPE_OP_PREXOR, &pending);
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
for (i = disks; i--; ) {
@@ -744,7 +746,7 @@ static void ops_complete_postxor(void *stripe_head_ref)
{
struct stripe_head *sh = stripe_head_ref;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
set_bit(STRIPE_OP_POSTXOR, &sh->ops.complete);
@@ -757,7 +759,7 @@ static void ops_complete_write(void *stripe_head_ref)
struct stripe_head *sh = stripe_head_ref;
int disks = sh->disks, i, pd_idx = sh->pd_idx;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
for (i = disks; i--; ) {
@@ -787,7 +789,7 @@ ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx,
unsigned long flags;
dma_async_tx_callback callback;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
/* check if prexor is active which means only process blocks
@@ -837,7 +839,7 @@ static void ops_complete_check(void *stripe_head_ref)
struct stripe_head *sh = stripe_head_ref;
int pd_idx = sh->pd_idx;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
if (test_and_clear_bit(STRIPE_OP_MOD_DMA_CHECK, &sh->ops.pending) &&
@@ -859,7 +861,7 @@ static void ops_run_check(struct stripe_head *sh)
int count = 0, pd_idx = sh->pd_idx, i;
struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page;
- pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
for (i = disks; i--; ) {
@@ -1260,8 +1262,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
}
set_bit(Faulty, &rdev->flags);
printk (KERN_ALERT
- "raid5: Disk failure on %s, disabling device."
- " Operation continuing on %d devices\n",
+ "raid5: Disk failure on %s, disabling device.\n"
+ "raid5: Operation continuing on %d devices.\n",
bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
}
}
@@ -1720,6 +1722,9 @@ handle_write_operations5(struct stripe_head *sh, int rcw, int expand)
locked++;
}
}
+ if (locked + 1 == disks)
+ if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state))
+ atomic_inc(&sh->raid_conf->pending_full_writes);
} else {
BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) ||
test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags)));
@@ -1759,7 +1764,7 @@ handle_write_operations5(struct stripe_head *sh, int rcw, int expand)
locked++;
pr_debug("%s: stripe %llu locked: %d pending: %lx\n",
- __FUNCTION__, (unsigned long long)sh->sector,
+ __func__, (unsigned long long)sh->sector,
locked, sh->ops.pending);
return locked;
@@ -1947,6 +1952,9 @@ handle_requests_to_failed_array(raid5_conf_t *conf, struct stripe_head *sh,
STRIPE_SECTORS, 0, 0);
}
+ if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state))
+ if (atomic_dec_and_test(&conf->pending_full_writes))
+ md_wakeup_thread(conf->mddev->thread);
}
/* __handle_issuing_new_read_requests5 - returns 0 if there are no more disks
@@ -2149,6 +2157,10 @@ static void handle_completed_write_requests(raid5_conf_t *conf,
0);
}
}
+
+ if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state))
+ if (atomic_dec_and_test(&conf->pending_full_writes))
+ md_wakeup_thread(conf->mddev->thread);
}
static void handle_issuing_new_write_requests5(raid5_conf_t *conf,
@@ -2333,6 +2345,9 @@ static void handle_issuing_new_write_requests6(raid5_conf_t *conf,
s->locked++;
set_bit(R5_Wantwrite, &sh->dev[i].flags);
}
+ if (s->locked == disks)
+ if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state))
+ atomic_inc(&conf->pending_full_writes);
/* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
set_bit(STRIPE_INSYNC, &sh->state);
@@ -3094,6 +3109,8 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
else
continue;
+ set_bit(STRIPE_IO_STARTED, &sh->state);
+
bi = &sh->dev[i].req;
bi->bi_rw = rw;
@@ -3164,7 +3181,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf)
clear_bit(STRIPE_DELAYED, &sh->state);
if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
atomic_inc(&conf->preread_active_stripes);
- list_add_tail(&sh->lru, &conf->handle_list);
+ list_add_tail(&sh->lru, &conf->hold_list);
}
} else
blk_plug_device(conf->mddev->queue);
@@ -3442,6 +3459,58 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
}
}
+/* __get_priority_stripe - get the next stripe to process
+ *
+ * Full stripe writes are allowed to pass preread active stripes up until
+ * the bypass_threshold is exceeded. In general the bypass_count
+ * increments when the handle_list is handled before the hold_list; however, it
+ * will not be incremented when STRIPE_IO_STARTED is sampled set signifying a
+ * stripe with in flight i/o. The bypass_count will be reset when the
+ * head of the hold_list has changed, i.e. the head was promoted to the
+ * handle_list.
+ */
+static struct stripe_head *__get_priority_stripe(raid5_conf_t *conf)
+{
+ struct stripe_head *sh;
+
+ pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n",
+ __func__,
+ list_empty(&conf->handle_list) ? "empty" : "busy",
+ list_empty(&conf->hold_list) ? "empty" : "busy",
+ atomic_read(&conf->pending_full_writes), conf->bypass_count);
+
+ if (!list_empty(&conf->handle_list)) {
+ sh = list_entry(conf->handle_list.next, typeof(*sh), lru);
+
+ if (list_empty(&conf->hold_list))
+ conf->bypass_count = 0;
+ else if (!test_bit(STRIPE_IO_STARTED, &sh->state)) {
+ if (conf->hold_list.next == conf->last_hold)
+ conf->bypass_count++;
+ else {
+ conf->last_hold = conf->hold_list.next;
+ conf->bypass_count -= conf->bypass_threshold;
+ if (conf->bypass_count < 0)
+ conf->bypass_count = 0;
+ }
+ }
+ } else if (!list_empty(&conf->hold_list) &&
+ ((conf->bypass_threshold &&
+ conf->bypass_count > conf->bypass_threshold) ||
+ atomic_read(&conf->pending_full_writes) == 0)) {
+ sh = list_entry(conf->hold_list.next,
+ typeof(*sh), lru);
+ conf->bypass_count -= conf->bypass_threshold;
+ if (conf->bypass_count < 0)
+ conf->bypass_count = 0;
+ } else
+ return NULL;
+
+ list_del_init(&sh->lru);
+ atomic_inc(&sh->count);
+ BUG_ON(atomic_read(&sh->count) != 1);
+ return sh;
+}
static int make_request(struct request_queue *q, struct bio * bi)
{
@@ -3914,7 +3983,6 @@ static void raid5d(mddev_t *mddev)
handled = 0;
spin_lock_irq(&conf->device_lock);
while (1) {
- struct list_head *first;
struct bio *bio;
if (conf->seq_flush != conf->seq_write) {
@@ -3936,17 +4004,12 @@ static void raid5d(mddev_t *mddev)
handled++;
}
- if (list_empty(&conf->handle_list)) {
+ sh = __get_priority_stripe(conf);
+
+ if (!sh) {
async_tx_issue_pending_all();
break;
}
-
- first = conf->handle_list.next;
- sh = list_entry(first, struct stripe_head, lru);
-
- list_del_init(first);
- atomic_inc(&sh->count);
- BUG_ON(atomic_read(&sh->count)!= 1);
spin_unlock_irq(&conf->device_lock);
handled++;
@@ -3978,15 +4041,13 @@ static ssize_t
raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
{
raid5_conf_t *conf = mddev_to_conf(mddev);
- char *end;
- int new;
+ unsigned long new;
if (len >= PAGE_SIZE)
return -EINVAL;
if (!conf)
return -ENODEV;
- new = simple_strtoul(page, &end, 10);
- if (!*page || (*end && *end != '\n') )
+ if (strict_strtoul(page, 10, &new))
return -EINVAL;
if (new <= 16 || new > 32768)
return -EINVAL;
@@ -4011,6 +4072,40 @@ raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
raid5_store_stripe_cache_size);
static ssize_t
+raid5_show_preread_threshold(mddev_t *mddev, char *page)
+{
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", conf->bypass_threshold);
+ else
+ return 0;
+}
+
+static ssize_t
+raid5_store_preread_threshold(mddev_t *mddev, const char *page, size_t len)
+{
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+ unsigned long new;
+ if (len >= PAGE_SIZE)
+ return -EINVAL;
+ if (!conf)
+ return -ENODEV;
+
+ if (strict_strtoul(page, 10, &new))
+ return -EINVAL;
+ if (new > conf->max_nr_stripes)
+ return -EINVAL;
+ conf->bypass_threshold = new;
+ return len;
+}
+
+static struct md_sysfs_entry
+raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold,
+ S_IRUGO | S_IWUSR,
+ raid5_show_preread_threshold,
+ raid5_store_preread_threshold);
+
+static ssize_t
stripe_cache_active_show(mddev_t *mddev, char *page)
{
raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -4026,6 +4121,7 @@ raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
static struct attribute *raid5_attrs[] = {
&raid5_stripecache_size.attr,
&raid5_stripecache_active.attr,
+ &raid5_preread_bypass_threshold.attr,
NULL,
};
static struct attribute_group raid5_attrs_group = {
@@ -4130,12 +4226,14 @@ static int run(mddev_t *mddev)
init_waitqueue_head(&conf->wait_for_stripe);
init_waitqueue_head(&conf->wait_for_overlap);
INIT_LIST_HEAD(&conf->handle_list);
+ INIT_LIST_HEAD(&conf->hold_list);
INIT_LIST_HEAD(&conf->delayed_list);
INIT_LIST_HEAD(&conf->bitmap_list);
INIT_LIST_HEAD(&conf->inactive_list);
atomic_set(&conf->active_stripes, 0);
atomic_set(&conf->preread_active_stripes, 0);
atomic_set(&conf->active_aligned_reads, 0);
+ conf->bypass_threshold = BYPASS_THRESHOLD;
pr_debug("raid5: run(%s) called.\n", mdname(mddev));
diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c
index 77a6e4bf503d..21987e3dbe6c 100644
--- a/drivers/md/raid6algos.c
+++ b/drivers/md/raid6algos.c
@@ -121,7 +121,8 @@ int __init raid6_select_algo(void)
j0 = jiffies;
while ( (j1 = jiffies) == j0 )
cpu_relax();
- while ( (jiffies-j1) < (1 << RAID6_TIME_JIFFIES_LG2) ) {
+ while (time_before(jiffies,
+ j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
(*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs);
perf++;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 6477fc66cc23..346223856f59 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -299,7 +299,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
}
/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
-struct dibx000_agc_config xc3028_agc_config = {
+static struct dibx000_agc_config xc3028_agc_config = {
BAND_VHF | BAND_UHF, /* band_caps */
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
@@ -342,7 +342,7 @@ struct dibx000_agc_config xc3028_agc_config = {
};
/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
-struct dibx000_bandwidth_config xc3028_bw_config = {
+static struct dibx000_bandwidth_config xc3028_bw_config = {
60000, 30000, /* internal, sampling */
1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 68fab616f55d..f5fceb3cdb3c 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -307,6 +307,14 @@ config DVB_AU8522
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_S5H1411
+ tristate "Samsung S5H1411 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
comment "Tuners/PLL support"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 2f873fc0f649..9747c73dc826 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 96338f0c4dd4..de796eab3911 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -33,7 +33,7 @@ struct mt312_config {
u8 demod_address;
/* inverted voltage setting */
- int voltage_inverted:1;
+ unsigned int voltage_inverted:1;
};
#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
new file mode 100644
index 000000000000..eb5bfc99d4e9
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -0,0 +1,888 @@
+/*
+ Samsung S5H1411 VSB/QAM demodulator driver
+
+ Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "s5h1411.h"
+
+struct s5h1411_state {
+
+ struct i2c_adapter *i2c;
+
+ /* configuration settings */
+ const struct s5h1411_config *config;
+
+ struct dvb_frontend frontend;
+
+ fe_modulation_t current_modulation;
+
+ u32 current_frequency;
+ int if_freq;
+
+ u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do { \
+ if (debug) \
+ printk(arg); \
+ } while (0)
+
+/* Register values to initialise the demod, defaults to VSB */
+static struct init_tab {
+ u8 addr;
+ u8 reg;
+ u16 data;
+} init_tab[] = {
+ { S5H1411_I2C_TOP_ADDR, 0x00, 0x0071, },
+ { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, },
+ { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, },
+ { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, },
+ { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342a, },
+ { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, },
+ { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, },
+ { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, },
+ { S5H1411_I2C_TOP_ADDR, 0x27, 0x0f04, },
+ { S5H1411_I2C_TOP_ADDR, 0x28, 0x070f, },
+ { S5H1411_I2C_TOP_ADDR, 0x29, 0x2820, },
+ { S5H1411_I2C_TOP_ADDR, 0x2a, 0x102e, },
+ { S5H1411_I2C_TOP_ADDR, 0x2b, 0x0220, },
+ { S5H1411_I2C_TOP_ADDR, 0x2e, 0x0d0e, },
+ { S5H1411_I2C_TOP_ADDR, 0x2f, 0x1013, },
+ { S5H1411_I2C_TOP_ADDR, 0x31, 0x171b, },
+ { S5H1411_I2C_TOP_ADDR, 0x32, 0x0e0f, },
+ { S5H1411_I2C_TOP_ADDR, 0x33, 0x0f10, },
+ { S5H1411_I2C_TOP_ADDR, 0x34, 0x170e, },
+ { S5H1411_I2C_TOP_ADDR, 0x35, 0x4b10, },
+ { S5H1411_I2C_TOP_ADDR, 0x36, 0x0f17, },
+ { S5H1411_I2C_TOP_ADDR, 0x3c, 0x1577, },
+ { S5H1411_I2C_TOP_ADDR, 0x3d, 0x081a, },
+ { S5H1411_I2C_TOP_ADDR, 0x3e, 0x77ee, },
+ { S5H1411_I2C_TOP_ADDR, 0x40, 0x1e09, },
+ { S5H1411_I2C_TOP_ADDR, 0x41, 0x0f0c, },
+ { S5H1411_I2C_TOP_ADDR, 0x42, 0x1f10, },
+ { S5H1411_I2C_TOP_ADDR, 0x4d, 0x0509, },
+ { S5H1411_I2C_TOP_ADDR, 0x4e, 0x0a00, },
+ { S5H1411_I2C_TOP_ADDR, 0x50, 0x0000, },
+ { S5H1411_I2C_TOP_ADDR, 0x5b, 0x0000, },
+ { S5H1411_I2C_TOP_ADDR, 0x5c, 0x0008, },
+ { S5H1411_I2C_TOP_ADDR, 0x57, 0x1101, },
+ { S5H1411_I2C_TOP_ADDR, 0x65, 0x007c, },
+ { S5H1411_I2C_TOP_ADDR, 0x68, 0x0512, },
+ { S5H1411_I2C_TOP_ADDR, 0x69, 0x0258, },
+ { S5H1411_I2C_TOP_ADDR, 0x70, 0x0004, },
+ { S5H1411_I2C_TOP_ADDR, 0x71, 0x0007, },
+ { S5H1411_I2C_TOP_ADDR, 0x76, 0x00a9, },
+ { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, },
+ { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, },
+ { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, },
+ { S5H1411_I2C_TOP_ADDR, 0xb5, 0xafbb, },
+ { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, },
+ { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, },
+ { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, },
+ { S5H1411_I2C_TOP_ADDR, 0xb8, 0x003f, },
+ { S5H1411_I2C_TOP_ADDR, 0xb9, 0x2700, },
+ { S5H1411_I2C_TOP_ADDR, 0xba, 0xfac8, },
+ { S5H1411_I2C_TOP_ADDR, 0xbe, 0x1003, },
+ { S5H1411_I2C_TOP_ADDR, 0xbf, 0x103f, },
+ { S5H1411_I2C_TOP_ADDR, 0xce, 0x2000, },
+ { S5H1411_I2C_TOP_ADDR, 0xcf, 0x0800, },
+ { S5H1411_I2C_TOP_ADDR, 0xd0, 0x0800, },
+ { S5H1411_I2C_TOP_ADDR, 0xd1, 0x0400, },
+ { S5H1411_I2C_TOP_ADDR, 0xd2, 0x0800, },
+ { S5H1411_I2C_TOP_ADDR, 0xd3, 0x2000, },
+ { S5H1411_I2C_TOP_ADDR, 0xd4, 0x3000, },
+ { S5H1411_I2C_TOP_ADDR, 0xdb, 0x4a9b, },
+ { S5H1411_I2C_TOP_ADDR, 0xdc, 0x1000, },
+ { S5H1411_I2C_TOP_ADDR, 0xde, 0x0001, },
+ { S5H1411_I2C_TOP_ADDR, 0xdf, 0x0000, },
+ { S5H1411_I2C_TOP_ADDR, 0xe3, 0x0301, },
+ { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0000, },
+ { S5H1411_I2C_QAM_ADDR, 0xf3, 0x0001, },
+ { S5H1411_I2C_QAM_ADDR, 0x08, 0x0600, },
+ { S5H1411_I2C_QAM_ADDR, 0x18, 0x4201, },
+ { S5H1411_I2C_QAM_ADDR, 0x1e, 0x6476, },
+ { S5H1411_I2C_QAM_ADDR, 0x21, 0x0830, },
+ { S5H1411_I2C_QAM_ADDR, 0x0c, 0x5679, },
+ { S5H1411_I2C_QAM_ADDR, 0x0d, 0x579b, },
+ { S5H1411_I2C_QAM_ADDR, 0x24, 0x0102, },
+ { S5H1411_I2C_QAM_ADDR, 0x31, 0x7488, },
+ { S5H1411_I2C_QAM_ADDR, 0x32, 0x0a08, },
+ { S5H1411_I2C_QAM_ADDR, 0x3d, 0x8689, },
+ { S5H1411_I2C_QAM_ADDR, 0x49, 0x0048, },
+ { S5H1411_I2C_QAM_ADDR, 0x57, 0x2012, },
+ { S5H1411_I2C_QAM_ADDR, 0x5d, 0x7676, },
+ { S5H1411_I2C_QAM_ADDR, 0x04, 0x0400, },
+ { S5H1411_I2C_QAM_ADDR, 0x58, 0x00c0, },
+ { S5H1411_I2C_QAM_ADDR, 0x5b, 0x0100, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+ u16 val;
+ u16 data;
+} vsb_snr_tab[] = {
+ { 0x39f, 300, },
+ { 0x39b, 295, },
+ { 0x397, 290, },
+ { 0x394, 285, },
+ { 0x38f, 280, },
+ { 0x38b, 275, },
+ { 0x387, 270, },
+ { 0x382, 265, },
+ { 0x37d, 260, },
+ { 0x377, 255, },
+ { 0x370, 250, },
+ { 0x36a, 245, },
+ { 0x364, 240, },
+ { 0x35b, 235, },
+ { 0x353, 230, },
+ { 0x349, 225, },
+ { 0x340, 320, },
+ { 0x337, 215, },
+ { 0x327, 210, },
+ { 0x31b, 205, },
+ { 0x310, 200, },
+ { 0x302, 195, },
+ { 0x2f3, 190, },
+ { 0x2e4, 185, },
+ { 0x2d7, 180, },
+ { 0x2cd, 175, },
+ { 0x2bb, 170, },
+ { 0x2a9, 165, },
+ { 0x29e, 160, },
+ { 0x284, 155, },
+ { 0x27a, 150, },
+ { 0x260, 145, },
+ { 0x23a, 140, },
+ { 0x224, 135, },
+ { 0x213, 130, },
+ { 0x204, 125, },
+ { 0x1fe, 120, },
+ { 0, 0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+ u16 val;
+ u16 data;
+} qam64_snr_tab[] = {
+ { 0x0001, 0, },
+ { 0x0af0, 300, },
+ { 0x0d80, 290, },
+ { 0x10a0, 280, },
+ { 0x14b5, 270, },
+ { 0x1590, 268, },
+ { 0x1680, 266, },
+ { 0x17b0, 264, },
+ { 0x18c0, 262, },
+ { 0x19b0, 260, },
+ { 0x1ad0, 258, },
+ { 0x1d00, 256, },
+ { 0x1da0, 254, },
+ { 0x1ef0, 252, },
+ { 0x2050, 250, },
+ { 0x20f0, 249, },
+ { 0x21d0, 248, },
+ { 0x22b0, 247, },
+ { 0x23a0, 246, },
+ { 0x2470, 245, },
+ { 0x24f0, 244, },
+ { 0x25a0, 243, },
+ { 0x26c0, 242, },
+ { 0x27b0, 241, },
+ { 0x28d0, 240, },
+ { 0x29b0, 239, },
+ { 0x2ad0, 238, },
+ { 0x2ba0, 237, },
+ { 0x2c80, 236, },
+ { 0x2d20, 235, },
+ { 0x2e00, 234, },
+ { 0x2f10, 233, },
+ { 0x3050, 232, },
+ { 0x3190, 231, },
+ { 0x3300, 230, },
+ { 0x3340, 229, },
+ { 0x3200, 228, },
+ { 0x3550, 227, },
+ { 0x3610, 226, },
+ { 0x3600, 225, },
+ { 0x3700, 224, },
+ { 0x3800, 223, },
+ { 0x3920, 222, },
+ { 0x3a20, 221, },
+ { 0x3b30, 220, },
+ { 0x3d00, 219, },
+ { 0x3e00, 218, },
+ { 0x4000, 217, },
+ { 0x4100, 216, },
+ { 0x4300, 215, },
+ { 0x4400, 214, },
+ { 0x4600, 213, },
+ { 0x4700, 212, },
+ { 0x4800, 211, },
+ { 0x4a00, 210, },
+ { 0x4b00, 209, },
+ { 0x4d00, 208, },
+ { 0x4f00, 207, },
+ { 0x5050, 206, },
+ { 0x5200, 205, },
+ { 0x53c0, 204, },
+ { 0x5450, 203, },
+ { 0x5650, 202, },
+ { 0x5820, 201, },
+ { 0x6000, 200, },
+ { 0xffff, 0, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+ u16 val;
+ u16 data;
+} qam256_snr_tab[] = {
+ { 0x0001, 0, },
+ { 0x0970, 400, },
+ { 0x0a90, 390, },
+ { 0x0b90, 380, },
+ { 0x0d90, 370, },
+ { 0x0ff0, 360, },
+ { 0x1240, 350, },
+ { 0x1345, 348, },
+ { 0x13c0, 346, },
+ { 0x14c0, 344, },
+ { 0x1500, 342, },
+ { 0x1610, 340, },
+ { 0x1700, 338, },
+ { 0x1800, 336, },
+ { 0x18b0, 334, },
+ { 0x1900, 332, },
+ { 0x1ab0, 330, },
+ { 0x1bc0, 328, },
+ { 0x1cb0, 326, },
+ { 0x1db0, 324, },
+ { 0x1eb0, 322, },
+ { 0x2030, 320, },
+ { 0x2200, 318, },
+ { 0x2280, 316, },
+ { 0x2410, 314, },
+ { 0x25b0, 312, },
+ { 0x27a0, 310, },
+ { 0x2840, 308, },
+ { 0x29d0, 306, },
+ { 0x2b10, 304, },
+ { 0x2d30, 302, },
+ { 0x2f20, 300, },
+ { 0x30c0, 298, },
+ { 0x3260, 297, },
+ { 0x32c0, 296, },
+ { 0x3300, 295, },
+ { 0x33b0, 294, },
+ { 0x34b0, 293, },
+ { 0x35a0, 292, },
+ { 0x3650, 291, },
+ { 0x3800, 290, },
+ { 0x3900, 289, },
+ { 0x3a50, 288, },
+ { 0x3b30, 287, },
+ { 0x3cb0, 286, },
+ { 0x3e20, 285, },
+ { 0x3fa0, 284, },
+ { 0x40a0, 283, },
+ { 0x41c0, 282, },
+ { 0x42f0, 281, },
+ { 0x44a0, 280, },
+ { 0x4600, 279, },
+ { 0x47b0, 278, },
+ { 0x4900, 277, },
+ { 0x4a00, 276, },
+ { 0x4ba0, 275, },
+ { 0x4d00, 274, },
+ { 0x4f00, 273, },
+ { 0x5000, 272, },
+ { 0x51f0, 272, },
+ { 0x53a0, 270, },
+ { 0x5520, 269, },
+ { 0x5700, 268, },
+ { 0x5800, 267, },
+ { 0x5a00, 266, },
+ { 0x5c00, 265, },
+ { 0x5d00, 264, },
+ { 0x5f00, 263, },
+ { 0x6000, 262, },
+ { 0x6200, 261, },
+ { 0x6400, 260, },
+ { 0xffff, 0, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1411_writereg(struct s5h1411_state *state,
+ u8 addr, u8 reg, u16 data)
+{
+ int ret;
+ u8 buf [] = { reg, data >> 8, data & 0xff };
+
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+ "ret == %i)\n", __func__, addr, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0, 0 };
+
+ struct i2c_msg msg [] = {
+ { .addr = addr, .flags = 0, .buf = b0, .len = 1 },
+ { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+ return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1411_softreset(struct dvb_frontend *fe)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __func__);
+
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 0);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf7, 1);
+ return 0;
+}
+
+static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d KHz)\n", __func__, KHz);
+
+ switch (KHz) {
+ case 3250:
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d9);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342);
+ s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9);
+ break;
+ case 3500:
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1225);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x1e96);
+ s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1225);
+ break;
+ case 4000:
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x14bc);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0xb53e);
+ s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x14bd);
+ break;
+ default:
+ dprintk("%s(%d KHz) Invalid, defaulting to 5380\n",
+ __func__, KHz);
+ /* no break, need to continue */
+ case 5380:
+ case 44000:
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x1be4);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x3655);
+ s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x1be4);
+ break;
+ }
+
+ state->if_freq = KHz;
+
+ return 0;
+}
+
+static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ u16 val;
+
+ dprintk("%s(%d)\n", __func__, mode);
+
+ val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
+ switch (mode) {
+ case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+ val |= 0x0000;
+ break;
+ case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+ dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
+ val |= 0x1000;
+ break;
+ case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+ val |= 0x2000;
+ break;
+ case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+ val |= 0x3000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Configure MPEG Signal Timing charactistics */
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbe, val);
+}
+
+static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ u16 val;
+
+ dprintk("%s(%d)\n", __func__, inversion);
+ val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x24) & ~0x1000;
+
+ if (inversion == 1)
+ val |= 0x1000; /* Inverted */
+ else
+ val |= 0x0000;
+
+ state->inversion = inversion;
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val);
+}
+
+static int s5h1411_enable_modulation(struct dvb_frontend *fe,
+ fe_modulation_t m)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s(0x%08x)\n", __func__, m);
+
+ switch (m) {
+ case VSB_8:
+ dprintk("%s() VSB_8\n", __func__);
+ s5h1411_set_if_freq(fe, state->config->vsb_if);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x71);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x00);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0xf1);
+ break;
+ case QAM_64:
+ case QAM_256:
+ dprintk("%s() QAM_AUTO (64/256)\n", __func__);
+ s5h1411_set_if_freq(fe, state->config->qam_if);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf6, 0x0001);
+ s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x16, 0x1101);
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xcd, 0x00f0);
+ break;
+ default:
+ dprintk("%s() Invalid modulation\n", __func__);
+ return -EINVAL;
+ }
+
+ state->current_modulation = m;
+ s5h1411_softreset(fe);
+
+ return 0;
+}
+
+static int s5h1411_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ if (enable)
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
+ else
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 0);
+}
+
+static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ u16 val;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xe0) & ~0x02;
+
+ if (enable)
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0,
+ val | 0x02);
+ else
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val);
+}
+
+static int s5h1411_sleep(struct dvb_frontend *fe, int enable)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ if (enable)
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 1);
+ else {
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf4, 0);
+ s5h1411_softreset(fe);
+ }
+
+ return 0;
+}
+
+static int s5h1411_register_reset(struct dvb_frontend *fe)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __func__);
+
+ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf3, 0);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1411_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+ s5h1411_softreset(fe);
+
+ state->current_frequency = p->frequency;
+
+ s5h1411_enable_modulation(fe, p->u.vsb.modulation);
+
+ /* Allow the demod to settle */
+ msleep(100);
+
+ if (fe->ops.tuner_ops.set_params) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.set_params(fe, p);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+static int s5h1411_init(struct dvb_frontend *fe)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ int i;
+
+ dprintk("%s()\n", __func__);
+
+ s5h1411_sleep(fe, 0);
+ s5h1411_register_reset(fe);
+
+ for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+ s5h1411_writereg(state, init_tab[i].addr,
+ init_tab[i].reg,
+ init_tab[i].data);
+
+ /* The datasheet says that after initialisation, VSB is default */
+ state->current_modulation = VSB_8;
+
+ if (state->config->output_mode == S5H1411_SERIAL_OUTPUT)
+ /* Serial */
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101);
+ else
+ /* Parallel */
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001);
+
+ s5h1411_set_spectralinversion(fe, state->config->inversion);
+ s5h1411_set_if_freq(fe, state->config->vsb_if);
+ s5h1411_set_gpio(fe, state->config->gpio);
+ s5h1411_set_mpeg_timing(fe, state->config->mpeg_timing);
+ s5h1411_softreset(fe);
+
+ /* Note: Leaving the I2C gate closed. */
+ s5h1411_i2c_gate_ctrl(fe, 0);
+
+ return 0;
+}
+
+static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ u16 reg;
+ u32 tuner_status = 0;
+
+ *status = 0;
+
+ /* Get the demodulator status */
+ reg = (s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2) >> 15)
+ & 0x0001;
+ if (reg)
+ *status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+ switch (state->current_modulation) {
+ case QAM_64:
+ case QAM_256:
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0);
+ if (reg & 0x100)
+ *status |= FE_HAS_VITERBI;
+ if (reg & 0x10)
+ *status |= FE_HAS_SYNC;
+ break;
+ case VSB_8:
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x5e);
+ if (reg & 0x0001)
+ *status |= FE_HAS_SYNC;
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2);
+ if (reg & 0x1000)
+ *status |= FE_HAS_VITERBI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (state->config->status_mode) {
+ case S5H1411_DEMODLOCKING:
+ if (*status & FE_HAS_VITERBI)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ case S5H1411_TUNERLOCKING:
+ /* Get the tuner status */
+ if (fe->ops.tuner_ops.get_status) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (tuner_status)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ }
+
+ dprintk("%s() status 0x%08x\n", __func__, *status);
+
+ return 0;
+}
+
+static int s5h1411_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+ if (v < qam256_snr_tab[i].val) {
+ *snr = qam256_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int s5h1411_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+ if (v < qam64_snr_tab[i].val) {
+ *snr = qam64_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int s5h1411_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+ if (v > vsb_snr_tab[i].val) {
+ *snr = vsb_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ dprintk("%s() snr=%d\n", __func__, *snr);
+ return ret;
+}
+
+static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ u16 reg;
+ dprintk("%s()\n", __func__);
+
+ switch (state->current_modulation) {
+ case QAM_64:
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
+ return s5h1411_qam64_lookup_snr(fe, snr, reg);
+ case QAM_256:
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf1);
+ return s5h1411_qam256_lookup_snr(fe, snr, reg);
+ case VSB_8:
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR,
+ 0xf2) & 0x3ff;
+ return s5h1411_vsb_lookup_snr(fe, snr, reg);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ return s5h1411_read_snr(fe, signal_strength);
+}
+
+static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ *ucblocks = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xc9);
+
+ return 0;
+}
+
+static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ return s5h1411_read_ucblocks(fe, ber);
+}
+
+static int s5h1411_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+
+ p->frequency = state->current_frequency;
+ p->u.vsb.modulation = state->current_modulation;
+
+ return 0;
+}
+
+static int s5h1411_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void s5h1411_release(struct dvb_frontend *fe)
+{
+ struct s5h1411_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1411_ops;
+
+struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct s5h1411_state *state = NULL;
+ u16 reg;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1411_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->current_modulation = VSB_8;
+ state->inversion = state->config->inversion;
+
+ /* check if the demod exists */
+ reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x05);
+ if (reg != 0x0066)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s5h1411_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ state->frontend.demodulator_priv = state;
+
+ if (s5h1411_init(&state->frontend) != 0) {
+ printk(KERN_ERR "%s: Failed to initialize correctly\n",
+ __func__);
+ goto error;
+ }
+
+ /* Note: Leaving the I2C gate open here. */
+ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(s5h1411_attach);
+
+static struct dvb_frontend_ops s5h1411_ops = {
+
+ .info = {
+ .name = "Samsung S5H1411 QAM/8VSB Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .init = s5h1411_init,
+ .i2c_gate_ctrl = s5h1411_i2c_gate_ctrl,
+ .set_frontend = s5h1411_set_frontend,
+ .get_frontend = s5h1411_get_frontend,
+ .get_tune_settings = s5h1411_get_tune_settings,
+ .read_status = s5h1411_read_status,
+ .read_ber = s5h1411_read_ber,
+ .read_signal_strength = s5h1411_read_signal_strength,
+ .read_snr = s5h1411_read_snr,
+ .read_ucblocks = s5h1411_read_ucblocks,
+ .release = s5h1411_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
new file mode 100644
index 000000000000..1855f64ed4d8
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -0,0 +1,90 @@
+/*
+ Samsung S5H1411 VSB/QAM demodulator driver
+
+ Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __S5H1411_H__
+#define __S5H1411_H__
+
+#include <linux/dvb/frontend.h>
+
+#define S5H1411_I2C_TOP_ADDR (0x32 >> 1)
+#define S5H1411_I2C_QAM_ADDR (0x34 >> 1)
+
+struct s5h1411_config {
+
+ /* serial/parallel output */
+#define S5H1411_PARALLEL_OUTPUT 0
+#define S5H1411_SERIAL_OUTPUT 1
+ u8 output_mode;
+
+ /* GPIO Setting */
+#define S5H1411_GPIO_OFF 0
+#define S5H1411_GPIO_ON 1
+ u8 gpio;
+
+ /* MPEG signal timing */
+#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
+#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
+#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
+#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+ u16 mpeg_timing;
+
+ /* IF Freq for QAM and VSB in KHz */
+#define S5H1411_IF_2500 2500
+#define S5H1411_IF_3500 3500
+#define S5H1411_IF_4000 4000
+#define S5H1411_IF_5380 5380
+#define S5H1411_IF_44000 44000
+#define S5H1411_VSB_IF_DEFAULT S5H1411_IF_44000
+#define S5H1411_QAM_IF_DEFAULT S5H1411_IF_44000
+ u16 qam_if;
+ u16 vsb_if;
+
+ /* Spectral Inversion */
+#define S5H1411_INVERSION_OFF 0
+#define S5H1411_INVERSION_ON 1
+ u8 inversion;
+
+ /* Return lock status based on tuner lock, or demod lock */
+#define S5H1411_TUNERLOCKING 0
+#define S5H1411_DEMODLOCKING 1
+ u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1411) || \
+ (defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1411_attach(
+ const struct s5h1411_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_S5H1411 */
+
+#endif /* __S5H1411_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index c97c4bd24841..41708267e7a4 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
- depends on VIDEO_DEV && I2C && INPUT
+ depends on VIDEO_DEV && I2C && INPUT && DVB_CORE
select I2C_ALGOBIT
select DVB_AU8522 if !DVB_FE_CUSTOMIZE
select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 8ca91f814277..a2a6983444fa 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -36,7 +36,6 @@ struct au0828_board au0828_boards[] = {
.name = "DViCO FusionHDTV USB",
},
};
-const unsigned int au0828_bcount = ARRAY_SIZE(au0828_boards);
/* Tuner callback function for au0828 boards. Currently only needed
* for HVR1500Q, which has an xc5000 tuner.
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
index e65d5642cb1d..54bfc0f05295 100644
--- a/drivers/media/video/au0828/au0828-core.c
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -32,18 +32,10 @@
* 4 = I2C related
* 8 = Bridge related
*/
-unsigned int debug;
-module_param(debug, int, 0644);
+int au0828_debug;
+module_param_named(debug, au0828_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
-unsigned int usb_debug;
-module_param(usb_debug, int, 0644);
-MODULE_PARM_DESC(usb_debug, "enable usb debug messages");
-
-unsigned int bridge_debug;
-module_param(bridge_debug, int, 0644);
-MODULE_PARM_DESC(bridge_debug, "enable bridge debug messages");
-
#define _AU0828_BULKPIPE 0x03
#define _BULKPIPESIZE 0xffff
@@ -229,24 +221,18 @@ static int __init au0828_init(void)
{
int ret;
- if (debug)
+ if (au0828_debug & 1)
printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
- if (usb_debug) {
+ if (au0828_debug & 2)
printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
- debug |= 2;
- }
- if (i2c_debug) {
+ if (au0828_debug & 4)
printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
- debug |= 4;
- }
- if (bridge_debug) {
+ if (au0828_debug & 8)
printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
__func__);
- debug |= 8;
- }
printk(KERN_INFO "au0828 driver loaded\n");
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 85d0ae9a322f..1371b4e4b5f1 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -119,7 +119,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
if (!purb->transfer_buffer) {
usb_free_urb(purb);
- dev->urbs[i] = 0;
+ dev->urbs[i] = NULL;
goto err;
}
@@ -204,7 +204,7 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
return ret;
}
-int dvb_register(struct au0828_dev *dev)
+static int dvb_register(struct au0828_dev *dev)
{
struct au0828_dvb *dvb = &dev->dvb;
int result;
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index 94c8b74a6651..741a4937b050 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -29,11 +29,7 @@
#include <media/v4l2-common.h>
-unsigned int i2c_debug;
-module_param(i2c_debug, int, 0444);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-
-unsigned int i2c_scan;
+static int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 0200b9fc5dc4..7beb571798e5 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -96,15 +96,12 @@ struct au0828_buff {
/* au0828-core.c */
extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
-extern unsigned int debug;
-extern unsigned int usb_debug;
-extern unsigned int bridge_debug;
+extern int au0828_debug;
/* ----------------------------------------------------------- */
/* au0828-cards.c */
extern struct au0828_board au0828_boards[];
extern struct usb_device_id au0828_usb_id_table[];
-extern const unsigned int au0828_bcount;
extern void au0828_gpio_setup(struct au0828_dev *dev);
extern int au0828_tuner_callback(void *priv, int command, int arg);
extern void au0828_card_setup(struct au0828_dev *dev);
@@ -115,7 +112,6 @@ extern int au0828_i2c_register(struct au0828_dev *dev);
extern int au0828_i2c_unregister(struct au0828_dev *dev);
extern void au0828_call_i2c_clients(struct au0828_dev *dev,
unsigned int cmd, void *arg);
-extern unsigned int i2c_debug;
/* ----------------------------------------------------------- */
/* au0828-dvb.c */
@@ -123,6 +119,6 @@ extern int au0828_dvb_register(struct au0828_dev *dev);
extern void au0828_dvb_unregister(struct au0828_dev *dev);
#define dprintk(level, fmt, arg...)\
- do { if (debug & level)\
+ do { if (au0828_debug & level)\
printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
} while (0)
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 870d6e197d65..f05649727b60 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -191,7 +191,7 @@ static struct tda18271_config hauppauge_hvr1200_tuner_config = {
.gate = TDA18271_GATE_ANALOG,
};
-struct dibx000_agc_config xc3028_agc_config = {
+static struct dibx000_agc_config xc3028_agc_config = {
BAND_VHF | BAND_UHF, /* band_caps */
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
@@ -237,7 +237,7 @@ struct dibx000_agc_config xc3028_agc_config = {
/* PLL Configuration for COFDM BW_MHz = 8.000000
* With external clock = 30.000000 */
-struct dibx000_bandwidth_config xc3028_bw_config = {
+static struct dibx000_bandwidth_config xc3028_bw_config = {
60000, /* internal */
30000, /* sampling */
1, /* pll_cfg: prediv */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index bcf6d9ba063d..27635cdcbaf2 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -58,6 +58,7 @@ config VIDEO_CX88_DVB
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 61c4f72644b8..6c0c94c5ef91 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -546,10 +546,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
if (retval < 0)
return retval;
- dev->mailbox = blackbird_find_mailbox(dev);
- if (dev->mailbox < 0)
+ retval = blackbird_find_mailbox(dev);
+ if (retval < 0)
return -1;
+ dev->mailbox = retval;
+
retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 620159d05506..2b6b283cda15 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1591,6 +1591,7 @@ static const struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x16d9,
}},
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PROLINK_PV_8000GT] = {
.name = "Prolink Pixelview MPEG 8000GT",
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index f1251b844e08..1c7fe6862a60 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -47,6 +47,7 @@
#include "isl6421.h"
#include "tuner-simple.h"
#include "tda9887.h"
+#include "s5h1411.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -463,6 +464,22 @@ static struct zl10353_config cx88_geniatech_x8000_mt = {
.no_tuner = 1,
};
+static struct s5h1411_config dvico_fusionhdtv7_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_ON,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .qam_if = S5H1411_IF_44000,
+ .vsb_if = S5H1411_IF_44000,
+ .inversion = S5H1411_INVERSION_OFF,
+ .status_mode = S5H1411_DEMODLOCKING
+};
+
+static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+ .i2c_address = 0xc2 >> 1,
+ .if_khz = 5380,
+ .tuner_callback = cx88_tuner_callback,
+};
+
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
{
struct dvb_frontend *fe;
@@ -844,6 +861,21 @@ static int dvb_register(struct cx8802_dev *dev)
if (attach_xc3028(0x61, dev) < 0)
return -EINVAL;
break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+ dev->dvb.frontend = dvb_attach(s5h1411_attach,
+ &dvico_fusionhdtv7_config,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ /* tuner_config.video_dev must point to
+ * i2c_adap.algo_data
+ */
+ dvico_fusionhdtv7_tuner_config.priv =
+ dev->core->i2c_adap.algo_data;
+ dvb_attach(xc5000_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap,
+ &dvico_fusionhdtv7_tuner_config);
+ }
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index f8c41d8c74c4..5d837c16ee22 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -650,7 +650,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
GFP_KERNEL);
- if (!dev->isoc_ctl.urb) {
+ if (!dev->isoc_ctl.transfer_buffer) {
em28xx_errdev("cannot allocate memory for usbtransfer\n");
kfree(dev->isoc_ctl.urb);
return -ENOMEM;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 11c5fdedc23b..7b65f5e537f8 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -509,8 +509,11 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
static const int probe_cx23885[] = { 0x6b, -1 };
const int *probe;
- struct i2c_client *c;
- unsigned char buf;
+ struct i2c_msg msg = {
+ .flags = I2C_M_RD,
+ .len = 0,
+ .buf = NULL,
+ };
int i, rc;
switch (adap->id) {
@@ -536,23 +539,17 @@ static int ir_probe(struct i2c_adapter *adap)
return 0;
}
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
-
- c->adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
- c->addr = probe[i];
- rc = i2c_master_recv(c, &buf, 0);
+ msg.addr = probe[i];
+ rc = i2c_transfer(adap, &msg, 1);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
- (0 == rc) ? "yes" : "no");
- if (0 == rc) {
+ (1 == rc) ? "yes" : "no");
+ if (1 == rc) {
ir_attach(adap, probe[i], 0, 0);
break;
}
}
- kfree(c);
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 393d917cd672..62f70bd5e3cb 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -1098,8 +1098,8 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
ivtv_yuv_next_free(itv);
/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
- dma_args.y_source = 0L;
- dma_args.uv_source = 0L;
+ dma_args.y_source = NULL;
+ dma_args.uv_source = NULL;
dma_args.src.left = 0;
dma_args.src.top = 0;
dma_args.src.width = yi->v4l2_src_w;
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index a8da90f69dd9..158b3d0c6532 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -64,6 +64,7 @@ config VIDEO_PVRUSB2_DVB
depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 9a7c8e9c3e8b..8d859ccd48ec 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -75,7 +75,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != 0) &&
+ ((sp = routing_schemes + sid) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
route.input = sp->def[hdw->input_val];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index b5db6a5bab31..73dcb1c57ae6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -195,7 +195,7 @@ static int pvr2_context_thread_func(void *foo)
int pvr2_context_global_init(void)
{
pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
- 0,
+ NULL,
"pvrusb2-context");
return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 97350b048b8d..29d50597c88a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -123,7 +123,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
memset(&route,0,sizeof(route));
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != 0) &&
+ ((sp = routing_schemes + sid) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
vid_input = sp->def[hdw->input_val].vid;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 2dd06a90adce..3a141d93e1a9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -36,6 +36,7 @@ pvr2_device_desc structures.
#include "pvrusb2-hdw-internal.h"
#include "lgdt330x.h"
#include "s5h1409.h"
+#include "s5h1411.h"
#include "tda10048.h"
#include "tda18271.h"
#include "tda8290.h"
@@ -368,6 +369,15 @@ static struct s5h1409_config pvr2_s5h1409_config = {
.status_mode = S5H1409_DEMODLOCKING,
};
+static struct s5h1411_config pvr2_s5h1411_config = {
+ .output_mode = S5H1411_PARALLEL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_44000,
+ .qam_if = S5H1411_IF_4000,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+};
+
static struct tda18271_std_map hauppauge_tda18271_std_map = {
.atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3,
.if_lvl = 6, .rfagc_top = 0x37, },
@@ -390,6 +400,16 @@ static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
return -EIO;
}
+static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
{
dvb_attach(tda829x_attach, adap->fe,
@@ -406,6 +426,11 @@ struct pvr2_dvb_props pvr2_750xx_dvb_props = {
.frontend_attach = pvr2_s5h1409_attach,
.tuner_attach = pvr2_tda18271_8295_attach,
};
+
+struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1411_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+};
#endif
static const char *pvr2_client_75xxx[] = {
@@ -454,6 +479,9 @@ static const struct pvr2_device_desc pvr2_device_751xx = {
.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
.default_std_mask = V4L2_STD_NTSC_M,
.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_751xx_dvb_props,
+#endif
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index c2e2b06fe2e0..d016f8b6c70b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -104,28 +104,28 @@ struct pvr2_device_desc {
unsigned char digital_control_scheme;
/* If set, we don't bother trying to load cx23416 firmware. */
- int flag_skip_cx23416_firmware:1;
+ unsigned int flag_skip_cx23416_firmware:1;
/* If set, the encoder must be healthy in order for digital mode to
work (otherwise we assume that digital streaming will work even
if we fail to locate firmware for the encoder). If the device
doesn't support digital streaming then this flag has no
effect. */
- int flag_digital_requires_cx23416:1;
+ unsigned int flag_digital_requires_cx23416:1;
/* Device has a hauppauge eeprom which we can interrogate. */
- int flag_has_hauppauge_rom:1;
+ unsigned int flag_has_hauppauge_rom:1;
/* Device does not require a powerup command to be issued. */
- int flag_no_powerup:1;
+ unsigned int flag_no_powerup:1;
/* Device has a cx25840 - this enables special additional logic to
handle it. */
- int flag_has_cx25840:1;
+ unsigned int flag_has_cx25840:1;
/* Device has a wm8775 - this enables special additional logic to
ensure that it is found. */
- int flag_has_wm8775:1;
+ unsigned int flag_has_wm8775:1;
/* Device has IR hardware that can be faked into looking like a
normal Hauppauge i2c IR receiver. This is currently very
@@ -135,15 +135,15 @@ struct pvr2_device_desc {
to virtualize the presence of the non-existant IR receiver chip and
implement the virtual receiver in terms of appropriate FX2
commands. */
- int flag_has_hauppauge_custom_ir:1;
+ unsigned int flag_has_hauppauge_custom_ir:1;
/* These bits define which kinds of sources the device can handle.
Note: Digital tuner presence is inferred by the
digital_control_scheme enumeration. */
- int flag_has_fmradio:1; /* Has FM radio receiver */
- int flag_has_analogtuner:1; /* Has analog tuner */
- int flag_has_composite:1; /* Has composite input */
- int flag_has_svideo:1; /* Has s-video input */
+ unsigned int flag_has_fmradio:1; /* Has FM radio receiver */
+ unsigned int flag_has_analogtuner:1; /* Has analog tuner */
+ unsigned int flag_has_composite:1; /* Has composite input */
+ unsigned int flag_has_svideo:1; /* Has s-video input */
};
extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
index 2e64f98d1241..6504c97e0bbc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -130,7 +130,7 @@ static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap)
for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
if (!(adap->buffer_storage[idx])) continue;
kfree(adap->buffer_storage[idx]);
- adap->buffer_storage[idx] = 0;
+ adap->buffer_storage[idx] = NULL;
}
adap->stream_run = 0;
}
@@ -142,7 +142,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap)
unsigned int idx;
int ret;
struct pvr2_buffer *bp;
- struct pvr2_stream *stream = 0;
+ struct pvr2_stream *stream = NULL;
if (adap->stream_run) return -EIO;
@@ -174,7 +174,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap)
ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1);
if (ret < 0) return ret;
- while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) {
+ while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) {
ret = pvr2_buffer_queue(bp);
if (ret < 0) return ret;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 087a18245560..e9b5d4e91327 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -1261,7 +1261,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
fail:
pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
pvr2_v4l2_destroy_no_lock(vp);
- return 0;
+ return NULL;
}
/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 7c47345501b6..2433a3160041 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -81,7 +81,7 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != 0) &&
+ ((sp = routing_schemes + sid) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
route.input = sp->def[hdw->input_val];
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 529e00952a8d..2b72e10e6b9f 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -369,19 +369,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
break;
}
case TUNER_TEA5767:
- if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_TEA5761:
- if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_PHILIPS_FMD1216ME_MK3:
@@ -394,12 +388,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- if (simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
- t->type) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
+ t->type))
+ goto attach_failed;
break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
@@ -407,12 +398,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0xa4;
i2c_master_send(c,buffer,4);
- if (simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
+ t->i2c->addr, t->type))
+ goto attach_failed;
break;
case TUNER_XC2028:
{
@@ -421,40 +409,34 @@ static void set_type(struct i2c_client *c, unsigned int type,
.i2c_addr = t->i2c->addr,
.callback = t->tuner_callback,
};
- if (!xc2028_attach(&t->fe, &cfg)) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!xc2028_attach(&t->fe, &cfg))
+ goto attach_failed;
break;
}
case TUNER_TDA9887:
tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
break;
case TUNER_XC5000:
+ {
+ struct dvb_tuner_ops *xc_tuner_ops;
+
xc5000_cfg.i2c_address = t->i2c->addr;
xc5000_cfg.if_khz = 5380;
xc5000_cfg.priv = c->adapter->algo_data;
xc5000_cfg.tuner_callback = t->tuner_callback;
- if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
- {
- struct dvb_tuner_ops *xc_tuner_ops;
+ if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg))
+ goto attach_failed;
+
xc_tuner_ops = &t->fe.ops.tuner_ops;
- if(xc_tuner_ops->init != NULL)
+ if (xc_tuner_ops->init)
xc_tuner_ops->init(&t->fe);
- }
break;
+ }
default:
- if (simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
+ t->i2c->addr, t->type))
+ goto attach_failed;
+
break;
}
@@ -476,11 +458,27 @@ static void set_type(struct i2c_client *c, unsigned int type,
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
- set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
+ /* xc2028/3028 and xc5000 requires a firmware to be set-up later
+ trying to set a frequency here will just fail
+ FIXME: better to move set_freq to the tuner code. This is needed
+ on analog tuners for PLL to properly work
+ */
+ if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
+ set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
+ t->radio_freq : t->tv_freq);
+
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask);
tuner_i2c_address_check(t);
+ return;
+
+attach_failed:
+ tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+
+ return;
}
/*
@@ -495,14 +493,16 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
- tuner_dbg("set addr for type %i\n", t->type);
-
if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
(t->mode_mask & tun_setup->mode_mask))) ||
(tun_setup->addr == c->addr)) {
set_type(c, tun_setup->type, tun_setup->mode_mask,
tun_setup->config, tun_setup->tuner_callback);
- }
+ } else
+ tuner_dbg("set addr discarded for type %i, mask %x. "
+ "Asked to change tuner at addr 0x%02x, with mask %x\n",
+ t->type, t->mode_mask,
+ tun_setup->addr, tun_setup->mode_mask);
}
static inline int check_mode(struct tuner *t, char *cmd)
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index cc3db7d79a0d..9e9003cffc7f 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -432,7 +432,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
type &= type_mask;
- if (!type & SCODE)
+ if (!(type & SCODE))
type_mask = ~0;
/* Seek for exact match */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 34deb68ae568..7cc42c1da457 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -716,7 +716,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
int err;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index fc51e4918bbf..982f4463896c 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -97,7 +97,10 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
struct videobuf_buffer *buf)
{
- return CALL(q, vmalloc, buf);
+ if (q->int_ops->vmalloc)
+ return q->int_ops->vmalloc(buf);
+ else
+ return NULL;
}
EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index d545c98dd5e7..01ea99c9bc1a 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -13,7 +13,7 @@
/*
* TODO:
* - remove "mark pages reserved-hacks" from memory allocation code
- * and implement nopage()
+ * and implement fault()
* - check decimation, calculating and reporting image size when
* using decimation
* - implement read(), user mode buffers and overlay (?)
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index b1e9592acb90..845be1864f68 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -888,7 +888,7 @@ static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct vivi_dev *dev;
- struct vivi_fh *fh;
+ struct vivi_fh *fh = NULL;
int i;
int retval = 0;
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 13bac53db69a..6e655b4c6682 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -22,6 +22,7 @@
#include <linux/sm501.h>
#include <linux/sm501-regs.h>
+#include <linux/serial_8250.h>
#include <asm/io.h>
@@ -723,13 +724,14 @@ static void sm501_device_release(struct device *dev)
*/
static struct platform_device *
-sm501_create_subdev(struct sm501_devdata *sm,
- char *name, unsigned int res_count)
+sm501_create_subdev(struct sm501_devdata *sm, char *name,
+ unsigned int res_count, unsigned int platform_data_size)
{
struct sm501_device *smdev;
smdev = kzalloc(sizeof(struct sm501_device) +
- sizeof(struct resource) * res_count, GFP_KERNEL);
+ (sizeof(struct resource) * res_count) +
+ platform_data_size, GFP_KERNEL);
if (!smdev)
return NULL;
@@ -737,11 +739,15 @@ sm501_create_subdev(struct sm501_devdata *sm,
smdev->pdev.name = name;
smdev->pdev.id = sm->pdev_id;
- smdev->pdev.resource = (struct resource *)(smdev+1);
- smdev->pdev.num_resources = res_count;
-
smdev->pdev.dev.parent = sm->dev;
+ if (res_count) {
+ smdev->pdev.resource = (struct resource *)(smdev+1);
+ smdev->pdev.num_resources = res_count;
+ }
+ if (platform_data_size)
+ smdev->pdev.dev.platform_data = (void *)(smdev+1);
+
return &smdev->pdev;
}
@@ -829,7 +835,7 @@ static int sm501_register_usbhost(struct sm501_devdata *sm,
{
struct platform_device *pdev;
- pdev = sm501_create_subdev(sm, "sm501-usb", 3);
+ pdev = sm501_create_subdev(sm, "sm501-usb", 3, 0);
if (!pdev)
return -ENOMEM;
@@ -840,12 +846,55 @@ static int sm501_register_usbhost(struct sm501_devdata *sm,
return sm501_register_device(sm, pdev);
}
+static void sm501_setup_uart_data(struct sm501_devdata *sm,
+ struct plat_serial8250_port *uart_data,
+ unsigned int offset)
+{
+ uart_data->membase = sm->regs + offset;
+ uart_data->mapbase = sm->io_res->start + offset;
+ uart_data->iotype = UPIO_MEM;
+ uart_data->irq = sm->irq;
+ uart_data->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ uart_data->regshift = 2;
+ uart_data->uartclk = (9600 * 16);
+}
+
+static int sm501_register_uart(struct sm501_devdata *sm, int devices)
+{
+ struct platform_device *pdev;
+ struct plat_serial8250_port *uart_data;
+
+ pdev = sm501_create_subdev(sm, "serial8250", 0,
+ sizeof(struct plat_serial8250_port) * 3);
+ if (!pdev)
+ return -ENOMEM;
+
+ uart_data = pdev->dev.platform_data;
+
+ if (devices & SM501_USE_UART0) {
+ sm501_setup_uart_data(sm, uart_data++, 0x30000);
+ sm501_unit_power(sm->dev, SM501_GATE_UART0, 1);
+ sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 12, 0);
+ sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x01e0, 0);
+ }
+ if (devices & SM501_USE_UART1) {
+ sm501_setup_uart_data(sm, uart_data++, 0x30020);
+ sm501_unit_power(sm->dev, SM501_GATE_UART1, 1);
+ sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 13, 0);
+ sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x1e00, 0);
+ }
+
+ pdev->id = PLAT8250_DEV_SM501;
+
+ return sm501_register_device(sm, pdev);
+}
+
static int sm501_register_display(struct sm501_devdata *sm,
resource_size_t *mem_avail)
{
struct platform_device *pdev;
- pdev = sm501_create_subdev(sm, "sm501-fb", 4);
+ pdev = sm501_create_subdev(sm, "sm501-fb", 4, 0);
if (!pdev)
return -ENOMEM;
@@ -963,6 +1012,7 @@ static unsigned int sm501_mem_local[] = {
static int sm501_init_dev(struct sm501_devdata *sm)
{
+ struct sm501_initdata *idata;
resource_size_t mem_avail;
unsigned long dramctrl;
unsigned long devid;
@@ -980,6 +1030,9 @@ static int sm501_init_dev(struct sm501_devdata *sm)
return -EINVAL;
}
+ /* disable irqs */
+ writel(0, sm->regs + SM501_IRQ_MASK);
+
dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
@@ -998,15 +1051,14 @@ static int sm501_init_dev(struct sm501_devdata *sm)
/* check to see if we have some device initialisation */
- if (sm->platdata) {
- struct sm501_platdata *pdata = sm->platdata;
+ idata = sm->platdata ? sm->platdata->init : NULL;
+ if (idata) {
+ sm501_init_regs(sm, idata);
- if (pdata->init) {
- sm501_init_regs(sm, sm->platdata->init);
-
- if (pdata->init->devices & SM501_USE_USB_HOST)
- sm501_register_usbhost(sm, &mem_avail);
- }
+ if (idata->devices & SM501_USE_USB_HOST)
+ sm501_register_usbhost(sm, &mem_avail);
+ if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1))
+ sm501_register_uart(sm, idata->devices);
}
ret = sm501_check_clocks(sm);
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 5e859486eaf8..ad34e2d22524 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -204,8 +204,7 @@ static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
static int ucb1x00_thread(void *_ts)
{
struct ucb1x00_ts *ts = _ts;
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
+ DECLARE_WAITQUEUE(wait, current);
int valid = 0;
set_freezable();
@@ -234,7 +233,7 @@ static int ucb1x00_thread(void *_ts)
if (ucb1x00_ts_pen_down(ts)) {
- set_task_state(tsk, TASK_INTERRUPTIBLE);
+ set_current_state(TASK_INTERRUPTIBLE);
ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
ucb1x00_disable(ts->ucb);
@@ -262,7 +261,7 @@ static int ucb1x00_thread(void *_ts)
valid = 1;
}
- set_task_state(tsk, TASK_INTERRUPTIBLE);
+ set_current_state(TASK_INTERRUPTIBLE);
timeout = HZ / 100;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 297a48f85446..636af2862308 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -140,6 +140,7 @@ config ACER_WMI
depends on EXPERIMENTAL
depends on ACPI
depends on LEDS_CLASS
+ depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
select ACPI_WMI
@@ -160,6 +161,7 @@ config ASUS_LAPTOP
depends on ACPI
depends on EXPERIMENTAL && !ACPI_ASUS
depends on LEDS_CLASS
+ depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
---help---
This is the new Linux driver for Asus laptops. It may also support some
@@ -241,10 +243,13 @@ config SONYPI_COMPAT
config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on X86 && ACPI
+ select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
- depends on INPUT
+ select INPUT
+ select NEW_LEDS
+ select LEDS_CLASS
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -344,6 +349,7 @@ config ATMEL_SSC
config INTEL_MENLOW
tristate "Thermal Management driver for Intel menlow platform"
depends on ACPI_THERMAL
+ select THERMAL
depends on X86
---help---
ACPI thermal management enhancement driver on
@@ -351,6 +357,19 @@ config INTEL_MENLOW
If unsure, say N.
+config EEEPC_LAPTOP
+ tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+ depends on X86
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on HWMON
+ depends on EXPERIMENTAL
+ ---help---
+ This driver supports the Fn-Fx keys on Eee PC laptops.
+ It also adds the ability to switch camera/wlan on/off.
+
+ If you have an Eee PC laptop, say Y or M here.
+
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
default n
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5914da434854..1952875a272e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,7 +7,8 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
-obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
new file mode 100644
index 000000000000..6d727609097f
--- /dev/null
+++ b/drivers/misc/eeepc-laptop.c
@@ -0,0 +1,666 @@
+/*
+ * eepc-laptop.c - Asus Eee PC extras
+ *
+ * Based on asus_acpi.c as patched for the Eee PC by Asus:
+ * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
+ * Based on eee.c from eeepc-linux
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <linux/uaccess.h>
+
+#define EEEPC_LAPTOP_VERSION "0.1"
+
+#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
+#define EEEPC_HOTK_FILE "eeepc"
+#define EEEPC_HOTK_CLASS "hotkey"
+#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
+#define EEEPC_HOTK_HID "ASUS010"
+
+#define EEEPC_LOG EEEPC_HOTK_FILE ": "
+#define EEEPC_ERR KERN_ERR EEEPC_LOG
+#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
+#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
+#define EEEPC_INFO KERN_INFO EEEPC_LOG
+
+/*
+ * Definitions for Asus EeePC
+ */
+#define NOTIFY_WLAN_ON 0x10
+#define NOTIFY_BRN_MIN 0x20
+#define NOTIFY_BRN_MAX 0x2f
+
+enum {
+ DISABLE_ASL_WLAN = 0x0001,
+ DISABLE_ASL_BLUETOOTH = 0x0002,
+ DISABLE_ASL_IRDA = 0x0004,
+ DISABLE_ASL_CAMERA = 0x0008,
+ DISABLE_ASL_TV = 0x0010,
+ DISABLE_ASL_GPS = 0x0020,
+ DISABLE_ASL_DISPLAYSWITCH = 0x0040,
+ DISABLE_ASL_MODEM = 0x0080,
+ DISABLE_ASL_CARDREADER = 0x0100
+};
+
+enum {
+ CM_ASL_WLAN = 0,
+ CM_ASL_BLUETOOTH,
+ CM_ASL_IRDA,
+ CM_ASL_1394,
+ CM_ASL_CAMERA,
+ CM_ASL_TV,
+ CM_ASL_GPS,
+ CM_ASL_DVDROM,
+ CM_ASL_DISPLAYSWITCH,
+ CM_ASL_PANELBRIGHT,
+ CM_ASL_BIOSFLASH,
+ CM_ASL_ACPIFLASH,
+ CM_ASL_CPUFV,
+ CM_ASL_CPUTEMPERATURE,
+ CM_ASL_FANCPU,
+ CM_ASL_FANCHASSIS,
+ CM_ASL_USBPORT1,
+ CM_ASL_USBPORT2,
+ CM_ASL_USBPORT3,
+ CM_ASL_MODEM,
+ CM_ASL_CARDREADER,
+ CM_ASL_LID
+};
+
+const char *cm_getv[] = {
+ "WLDG", NULL, NULL, NULL,
+ "CAMG", NULL, NULL, NULL,
+ NULL, "PBLG", NULL, NULL,
+ "CFVG", NULL, NULL, NULL,
+ "USBG", NULL, NULL, "MODG",
+ "CRDG", "LIDG"
+};
+
+const char *cm_setv[] = {
+ "WLDS", NULL, NULL, NULL,
+ "CAMS", NULL, NULL, NULL,
+ "SDSP", "PBLS", "HDPS", NULL,
+ "CFVS", NULL, NULL, NULL,
+ "USBG", NULL, NULL, "MODS",
+ "CRDS", NULL
+};
+
+#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
+
+#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
+#define EEEPC_EC_SC02 0x63
+#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
+#define EEEPC_EC_SFB3 0xD3
+
+/*
+ * This is the main structure, we can use it to store useful information
+ * about the hotk device
+ */
+struct eeepc_hotk {
+ struct acpi_device *device; /* the device we are in */
+ acpi_handle handle; /* the handle of the hotk device */
+ u32 cm_supported; /* the control methods supported
+ by this BIOS */
+ uint init_flag; /* Init flags */
+ u16 event_count[128]; /* count for each event */
+};
+
+/* The actual device the driver binds to */
+static struct eeepc_hotk *ehotk;
+
+/* Platform device/driver */
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = EEEPC_HOTK_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *platform_device;
+
+/*
+ * The hotkey driver declaration
+ */
+static int eeepc_hotk_add(struct acpi_device *device);
+static int eeepc_hotk_remove(struct acpi_device *device, int type);
+
+static const struct acpi_device_id eeepc_device_ids[] = {
+ {EEEPC_HOTK_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
+
+static struct acpi_driver eeepc_hotk_driver = {
+ .name = EEEPC_HOTK_NAME,
+ .class = EEEPC_HOTK_CLASS,
+ .ids = eeepc_device_ids,
+ .ops = {
+ .add = eeepc_hotk_add,
+ .remove = eeepc_hotk_remove,
+ },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *eeepc_backlight_device;
+
+/* The hwmon device */
+static struct device *eeepc_hwmon_device;
+
+/*
+ * The backlight class declaration
+ */
+static int read_brightness(struct backlight_device *bd);
+static int update_bl_status(struct backlight_device *bd);
+static struct backlight_ops eeepcbl_ops = {
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+};
+
+MODULE_AUTHOR("Corentin Chary, Eric Cooper");
+MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+/*
+ * ACPI Helpers
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *)method, &params, output);
+ return (status == AE_OK ? 0 : -1);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ ulong result;
+
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
+ if (ACPI_FAILURE(status)) {
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
+ }
+}
+
+static int set_acpi(int cm, int value)
+{
+ if (ehotk->cm_supported & (0x1 << cm)) {
+ const char *method = cm_setv[cm];
+ if (method == NULL)
+ return -ENODEV;
+ if (write_acpi_int(ehotk->handle, method, value, NULL))
+ printk(EEEPC_WARNING "Error writing %s\n", method);
+ }
+ return 0;
+}
+
+static int get_acpi(int cm)
+{
+ int value = -1;
+ if ((ehotk->cm_supported & (0x1 << cm))) {
+ const char *method = cm_getv[cm];
+ if (method == NULL)
+ return -ENODEV;
+ if (read_acpi_int(ehotk->handle, method, &value))
+ printk(EEEPC_WARNING "Error reading %s\n", method);
+ }
+ return value;
+}
+
+/*
+ * Backlight
+ */
+static int read_brightness(struct backlight_device *bd)
+{
+ return get_acpi(CM_ASL_PANELBRIGHT);
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+ value = max(0, min(15, value));
+ return set_acpi(CM_ASL_PANELBRIGHT, value);
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ return set_brightness(bd, bd->props.brightness);
+}
+
+/*
+ * Sys helpers
+ */
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_acpi(cm, value);
+ return rv;
+}
+
+static ssize_t show_sys_acpi(int cm, char *buf)
+{
+ return sprintf(buf, "%d\n", get_acpi(cm));
+}
+
+#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_acpi(_cm, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_acpi(_cm, buf, count); \
+ } \
+ static struct device_attribute dev_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644 }, \
+ .show = show_##_name, \
+ .store = store_##_name, \
+ }
+
+EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
+EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
+EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
+EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
+
+static struct attribute *platform_attributes[] = {
+ &dev_attr_camera.attr,
+ &dev_attr_cardr.attr,
+ &dev_attr_disp.attr,
+ &dev_attr_wlan.attr,
+ NULL
+};
+
+static struct attribute_group platform_attribute_group = {
+ .attrs = platform_attributes
+};
+
+/*
+ * Hotkey functions
+ */
+static int eeepc_hotk_check(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ int result;
+
+ result = acpi_bus_get_status(ehotk->device);
+ if (result)
+ return result;
+ if (ehotk->device->status.present) {
+ if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
+ &buffer)) {
+ printk(EEEPC_ERR "Hotkey initialization failed\n");
+ return -ENODEV;
+ } else {
+ printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
+ ehotk->init_flag);
+ }
+ /* get control methods supported */
+ if (read_acpi_int(ehotk->handle, "CMSG"
+ , &ehotk->cm_supported)) {
+ printk(EEEPC_ERR
+ "Get control methods supported failed\n");
+ return -ENODEV;
+ } else {
+ printk(EEEPC_INFO
+ "Get control methods supported: 0x%x\n",
+ ehotk->cm_supported);
+ }
+ } else {
+ printk(EEEPC_ERR "Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void notify_wlan(u32 *event)
+{
+ /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
+ will always be 0x10 */
+ if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
+ const char *method = cm_getv[CM_ASL_WLAN];
+ int value;
+ if (read_acpi_int(ehotk->handle, method, &value))
+ printk(EEEPC_WARNING "Error reading %s\n",
+ method);
+ else if (value == 1)
+ *event = 0x11;
+ }
+}
+
+static void notify_brn(void)
+{
+ struct backlight_device *bd = eeepc_backlight_device;
+ bd->props.brightness = read_brightness(bd);
+}
+
+static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ if (!ehotk)
+ return;
+ if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
+ notify_wlan(&event);
+ if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
+ notify_brn();
+ acpi_bus_generate_proc_event(ehotk->device, event,
+ ehotk->event_count[event % 128]++);
+}
+
+static int eeepc_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+ printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
+ ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
+ if (!ehotk)
+ return -ENOMEM;
+ ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
+ ehotk->handle = device->handle;
+ strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
+ acpi_driver_data(device) = ehotk;
+ ehotk->device = device;
+ result = eeepc_hotk_check();
+ if (result)
+ goto end;
+ status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+ eeepc_hotk_notify, ehotk);
+ if (ACPI_FAILURE(status))
+ printk(EEEPC_ERR "Error installing notify handler\n");
+ end:
+ if (result) {
+ kfree(ehotk);
+ ehotk = NULL;
+ }
+ return result;
+}
+
+static int eeepc_hotk_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+ eeepc_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(EEEPC_ERR "Error removing notify handler\n");
+ kfree(ehotk);
+ return 0;
+}
+
+/*
+ * Hwmon
+ */
+static int eeepc_get_fan_pwm(void)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
+ return (value);
+}
+
+static void eeepc_set_fan_pwm(int value)
+{
+ value = SENSORS_LIMIT(value, 0, 100);
+ ec_write(EEEPC_EC_SC02, value);
+}
+
+static int eeepc_get_fan_rpm(void)
+{
+ int high = 0;
+ int low = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
+ read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
+ return (high << 8 | low);
+}
+
+static int eeepc_get_fan_ctrl(void)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
+ return ((value & 0x02 ? 1 : 0));
+}
+
+static void eeepc_set_fan_ctrl(int manual)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
+ if (manual)
+ value |= 0x02;
+ else
+ value &= ~0x02;
+ ec_write(EEEPC_EC_SFB3, value);
+}
+
+static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set(value);
+ return rv;
+}
+
+static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
+{
+ return sprintf(buf, "%d\n", get());
+}
+
+#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_hwmon(_set, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_hwmon(_get, buf, count); \
+ } \
+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
+
+EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
+EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+ eeepc_get_fan_pwm, eeepc_set_fan_pwm);
+EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+ eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_fan1_pwm.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group hwmon_attribute_group = {
+ .attrs = hwmon_attributes
+};
+
+/*
+ * exit/init
+ */
+static void eeepc_backlight_exit(void)
+{
+ if (eeepc_backlight_device)
+ backlight_device_unregister(eeepc_backlight_device);
+ eeepc_backlight_device = NULL;
+}
+
+static void eeepc_hwmon_exit(void)
+{
+ struct device *hwmon;
+
+ hwmon = eeepc_hwmon_device;
+ if (!hwmon)
+ return ;
+ hwmon_device_unregister(hwmon);
+ sysfs_remove_group(&hwmon->kobj,
+ &hwmon_attribute_group);
+ eeepc_hwmon_device = NULL;
+}
+
+static void __exit eeepc_laptop_exit(void)
+{
+ eeepc_backlight_exit();
+ eeepc_hwmon_exit();
+ acpi_bus_unregister_driver(&eeepc_hotk_driver);
+ sysfs_remove_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
+ platform_device_unregister(platform_device);
+ platform_driver_unregister(&platform_driver);
+}
+
+static int eeepc_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
+ NULL, &eeepcbl_ops);
+ if (IS_ERR(bd)) {
+ printk(EEEPC_ERR
+ "Could not register eeepc backlight device\n");
+ eeepc_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+ eeepc_backlight_device = bd;
+ bd->props.max_brightness = 15;
+ bd->props.brightness = read_brightness(NULL);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+ return 0;
+}
+
+static int eeepc_hwmon_init(struct device *dev)
+{
+ struct device *hwmon;
+ int result;
+
+ hwmon = hwmon_device_register(dev);
+ if (IS_ERR(hwmon)) {
+ printk(EEEPC_ERR
+ "Could not register eeepc hwmon device\n");
+ eeepc_hwmon_device = NULL;
+ return PTR_ERR(hwmon);
+ }
+ eeepc_hwmon_device = hwmon;
+ result = sysfs_create_group(&hwmon->kobj,
+ &hwmon_attribute_group);
+ if (result)
+ eeepc_hwmon_exit();
+ return result;
+}
+
+static int __init eeepc_laptop_init(void)
+{
+ struct device *dev;
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+ result = acpi_bus_register_driver(&eeepc_hotk_driver);
+ if (result < 0)
+ return result;
+ if (!ehotk) {
+ acpi_bus_unregister_driver(&eeepc_hotk_driver);
+ return -ENODEV;
+ }
+ dev = acpi_get_physical_device(ehotk->device->handle);
+ result = eeepc_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+ result = eeepc_hwmon_init(dev);
+ if (result)
+ goto fail_hwmon;
+ /* Register platform stuff */
+ result = platform_driver_register(&platform_driver);
+ if (result)
+ goto fail_platform_driver;
+ platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
+ if (!platform_device) {
+ result = -ENOMEM;
+ goto fail_platform_device1;
+ }
+ result = platform_device_add(platform_device);
+ if (result)
+ goto fail_platform_device2;
+ result = sysfs_create_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
+ if (result)
+ goto fail_sysfs;
+ return 0;
+fail_sysfs:
+ platform_device_del(platform_device);
+fail_platform_device2:
+ platform_device_put(platform_device);
+fail_platform_device1:
+ platform_driver_unregister(&platform_driver);
+fail_platform_driver:
+ eeepc_hwmon_exit();
+fail_hwmon:
+ eeepc_backlight_exit();
+fail_backlight:
+ return result;
+}
+
+module_init(eeepc_laptop_init);
+module_exit(eeepc_laptop_exit);
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index fafb57fed761..0736cff9d97a 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -31,7 +31,6 @@
static LIST_HEAD(container_list);
static DEFINE_MUTEX(container_list_lock);
static struct class enclosure_class;
-static struct class enclosure_component_class;
/**
* enclosure_find - find an enclosure given a device
@@ -166,6 +165,40 @@ void enclosure_unregister(struct enclosure_device *edev)
}
EXPORT_SYMBOL_GPL(enclosure_unregister);
+#define ENCLOSURE_NAME_SIZE 64
+
+static void enclosure_link_name(struct enclosure_component *cdev, char *name)
+{
+ strcpy(name, "enclosure_device:");
+ strcat(name, cdev->cdev.bus_id);
+}
+
+static void enclosure_remove_links(struct enclosure_component *cdev)
+{
+ char name[ENCLOSURE_NAME_SIZE];
+
+ enclosure_link_name(cdev, name);
+ sysfs_remove_link(&cdev->dev->kobj, name);
+ sysfs_remove_link(&cdev->cdev.kobj, "device");
+}
+
+static int enclosure_add_links(struct enclosure_component *cdev)
+{
+ int error;
+ char name[ENCLOSURE_NAME_SIZE];
+
+ error = sysfs_create_link(&cdev->cdev.kobj, &cdev->dev->kobj, "device");
+ if (error)
+ return error;
+
+ enclosure_link_name(cdev, name);
+ error = sysfs_create_link(&cdev->dev->kobj, &cdev->cdev.kobj, name);
+ if (error)
+ sysfs_remove_link(&cdev->cdev.kobj, "device");
+
+ return error;
+}
+
static void enclosure_release(struct device *cdev)
{
struct enclosure_device *edev = to_enclosure_device(cdev);
@@ -178,10 +211,15 @@ static void enclosure_component_release(struct device *dev)
{
struct enclosure_component *cdev = to_enclosure_component(dev);
- put_device(cdev->dev);
+ if (cdev->dev) {
+ enclosure_remove_links(cdev);
+ put_device(cdev->dev);
+ }
put_device(dev->parent);
}
+static struct attribute_group *enclosure_groups[];
+
/**
* enclosure_component_register - add a particular component to an enclosure
* @edev: the enclosure to add the component
@@ -217,12 +255,14 @@ enclosure_component_register(struct enclosure_device *edev,
ecomp->number = number;
cdev = &ecomp->cdev;
cdev->parent = get_device(&edev->edev);
- cdev->class = &enclosure_component_class;
if (name)
snprintf(cdev->bus_id, BUS_ID_SIZE, "%s", name);
else
snprintf(cdev->bus_id, BUS_ID_SIZE, "%u", number);
+ cdev->release = enclosure_component_release;
+ cdev->groups = enclosure_groups;
+
err = device_register(cdev);
if (err)
ERR_PTR(err);
@@ -255,10 +295,12 @@ int enclosure_add_device(struct enclosure_device *edev, int component,
cdev = &edev->component[component];
- device_del(&cdev->cdev);
+ if (cdev->dev)
+ enclosure_remove_links(cdev);
+
put_device(cdev->dev);
cdev->dev = get_device(dev);
- return device_add(&cdev->cdev);
+ return enclosure_add_links(cdev);
}
EXPORT_SYMBOL_GPL(enclosure_add_device);
@@ -442,24 +484,32 @@ static ssize_t get_component_type(struct device *cdev,
}
-static struct device_attribute enclosure_component_attrs[] = {
- __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
- set_component_fault),
- __ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
- set_component_status),
- __ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
- set_component_active),
- __ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
- set_component_locate),
- __ATTR(type, S_IRUGO, get_component_type, NULL),
- __ATTR_NULL
+static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
+ set_component_fault);
+static DEVICE_ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
+ set_component_status);
+static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
+ set_component_active);
+static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
+ set_component_locate);
+static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
+
+static struct attribute *enclosure_component_attrs[] = {
+ &dev_attr_fault.attr,
+ &dev_attr_status.attr,
+ &dev_attr_active.attr,
+ &dev_attr_locate.attr,
+ &dev_attr_type.attr,
+ NULL
};
-static struct class enclosure_component_class = {
- .name = "enclosure_component",
- .owner = THIS_MODULE,
- .dev_attrs = enclosure_component_attrs,
- .dev_release = enclosure_component_release,
+static struct attribute_group enclosure_group = {
+ .attrs = enclosure_component_attrs,
+};
+
+static struct attribute_group *enclosure_groups[] = {
+ &enclosure_group,
+ NULL
};
static int __init enclosure_init(void)
@@ -469,20 +519,12 @@ static int __init enclosure_init(void)
err = class_register(&enclosure_class);
if (err)
return err;
- err = class_register(&enclosure_component_class);
- if (err)
- goto err_out;
return 0;
- err_out:
- class_unregister(&enclosure_class);
-
- return err;
}
static void __exit enclosure_exit(void)
{
- class_unregister(&enclosure_component_class);
class_unregister(&enclosure_class);
}
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 0c0bb3093e07..5bb8816c9126 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -175,28 +175,18 @@ static int intel_menlow_memory_add(struct acpi_device *device)
goto end;
}
- if (cdev) {
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj, "thermal_cooling");
- if (result)
- goto unregister;
-
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj, "device");
- if (result) {
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- goto unregister;
- }
- }
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj, "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj, "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
end:
return result;
-
- unregister:
- thermal_cooling_device_unregister(cdev);
- return result;
-
}
static int intel_menlow_memory_remove(struct acpi_device *device, int type)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6cb781262f94..3f28f6eabdbf 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
* 02110-1301, USA.
*/
-#define TPACPI_VERSION "0.19"
+#define TPACPI_VERSION "0.20"
#define TPACPI_SYSFS_VERSION 0x020200
/*
@@ -67,6 +67,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
@@ -85,6 +86,8 @@
#define TP_CMOS_VOLUME_MUTE 2
#define TP_CMOS_BRIGHTNESS_UP 4
#define TP_CMOS_BRIGHTNESS_DOWN 5
+#define TP_CMOS_THINKLIGHT_ON 12
+#define TP_CMOS_THINKLIGHT_OFF 13
/* NVRAM Addresses */
enum tp_nvram_addr {
@@ -133,8 +136,12 @@ enum {
#define TPACPI_PROC_DIR "ibm"
#define TPACPI_ACPI_EVENT_PREFIX "ibm"
#define TPACPI_DRVR_NAME TPACPI_FILE
+#define TPACPI_DRVR_SHORTNAME "tpacpi"
#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
+#define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd"
+#define TPACPI_WORKQUEUE_NAME "ktpacpid"
+
#define TPACPI_MAX_ACPI_ARGS 3
/* Debugging */
@@ -225,6 +232,7 @@ static struct {
u32 light:1;
u32 light_status:1;
u32 bright_16levels:1;
+ u32 bright_acpimode:1;
u32 wan:1;
u32 fan_ctrl_status_undef:1;
u32 input_device_registered:1;
@@ -236,6 +244,11 @@ static struct {
u32 hotkey_poll_active:1;
} tp_features;
+static struct {
+ u16 hotkey_mask_ff:1;
+ u16 bright_cmos_ec_unsync:1;
+} tp_warned;
+
struct thinkpad_id_data {
unsigned int vendor; /* ThinkPad vendor:
* PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
@@ -246,7 +259,8 @@ struct thinkpad_id_data {
u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
u16 ec_model;
- char *model_str;
+ char *model_str; /* ThinkPad T43 */
+ char *nummodel_str; /* 9384A9C for a 9384-A9C model */
};
static struct thinkpad_id_data thinkpad_id;
@@ -259,6 +273,16 @@ static enum {
static int experimental;
static u32 dbg_level;
+static struct workqueue_struct *tpacpi_wq;
+
+/* Special LED class that can defer work */
+struct tpacpi_led_classdev {
+ struct led_classdev led_classdev;
+ struct work_struct work;
+ enum led_brightness new_brightness;
+ unsigned int led;
+};
+
/****************************************************************************
****************************************************************************
*
@@ -807,6 +831,80 @@ static int parse_strtoul(const char *buf,
return 0;
}
+static int __init tpacpi_query_bcl_levels(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ int rc;
+
+ if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+ obj = (union acpi_object *)buffer.pointer;
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+ printk(TPACPI_ERR "Unknown _BCL data, "
+ "please report this to %s\n", TPACPI_MAIL);
+ rc = 0;
+ } else {
+ rc = obj->package.count;
+ }
+ } else {
+ return 0;
+ }
+
+ kfree(buffer.pointer);
+ return rc;
+}
+
+static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
+ u32 lvl, void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("_BCL", name, sizeof(name) - 1)) {
+ BUG_ON(!rv || !*rv);
+ **(int **)rv = tpacpi_query_bcl_levels(handle);
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+}
+
+/*
+ * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
+ */
+static int __init tpacpi_check_std_acpi_brightness_support(void)
+{
+ int status;
+ int bcl_levels = 0;
+ void *bcl_ptr = &bcl_levels;
+
+ if (!vid_handle) {
+ TPACPI_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /*
+ * Search for a _BCL method, and execute it. This is safe on all
+ * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
+ * BIOS in ACPI backlight control mode. We do NOT have to care
+ * about calling the _BCL method in an enabled video device, any
+ * will do for our purposes.
+ */
+
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+ tpacpi_acpi_walk_find_bcl, NULL,
+ &bcl_ptr);
+
+ if (ACPI_SUCCESS(status) && bcl_levels > 2) {
+ tp_features.bright_acpimode = 1;
+ return (bcl_levels - 2);
+ }
+
+ return 0;
+}
+
/*************************************************************************
* thinkpad-acpi driver attributes
*/
@@ -909,12 +1007,14 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
thinkpad_id.ec_version_str : "unknown");
if (thinkpad_id.vendor && thinkpad_id.model_str)
- printk(TPACPI_INFO "%s %s\n",
+ printk(TPACPI_INFO "%s %s, model %s\n",
(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
"IBM" : ((thinkpad_id.vendor ==
PCI_VENDOR_ID_LENOVO) ?
"Lenovo" : "Unknown vendor"),
- thinkpad_id.model_str);
+ thinkpad_id.model_str,
+ (thinkpad_id.nummodel_str) ?
+ thinkpad_id.nummodel_str : "unknown");
return 0;
}
@@ -1107,6 +1207,19 @@ static int hotkey_mask_set(u32 mask)
int rc = 0;
if (tp_features.hotkey_mask) {
+ if (!tp_warned.hotkey_mask_ff &&
+ (mask == 0xffff || mask == 0xffffff ||
+ mask == 0xffffffff)) {
+ tp_warned.hotkey_mask_ff = 1;
+ printk(TPACPI_NOTICE
+ "setting the hotkey mask to 0x%08x is likely "
+ "not the best way to go about it\n", mask);
+ printk(TPACPI_NOTICE
+ "please consider using the driver defaults, "
+ "and refer to up-to-date thinkpad-acpi "
+ "documentation\n");
+ }
+
HOTKEY_CONFIG_CRITICAL_START
for (i = 0; i < 32; i++) {
u32 m = 1 << i;
@@ -1427,8 +1540,7 @@ static void hotkey_poll_setup(int may_warn)
(tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
if (!tpacpi_hotkey_task) {
tpacpi_hotkey_task = kthread_run(hotkey_kthread,
- NULL,
- TPACPI_FILE "d");
+ NULL, TPACPI_NVRAM_KTHREAD_NAME);
if (IS_ERR(tpacpi_hotkey_task)) {
tpacpi_hotkey_task = NULL;
printk(TPACPI_ERR
@@ -1887,6 +1999,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ /* These either have to go through ACPI video, or
+ * act like in the IBM ThinkPads, so don't ever
+ * enable them by default */
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
@@ -2091,6 +2206,32 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
}
+ /* Do not issue duplicate brightness change events to
+ * userspace */
+ if (!tp_features.bright_acpimode)
+ /* update bright_acpimode... */
+ tpacpi_check_std_acpi_brightness_support();
+
+ if (tp_features.bright_acpimode) {
+ printk(TPACPI_INFO
+ "This ThinkPad has standard ACPI backlight "
+ "brightness control, supported by the ACPI "
+ "video driver\n");
+ printk(TPACPI_NOTICE
+ "Disabling thinkpad-acpi brightness events "
+ "by default...\n");
+
+ /* The hotkey_reserved_mask change below is not
+ * necessary while the keys are at KEY_RESERVED in the
+ * default map, but better safe than sorry, leave it
+ * here as a marker of what we have to do, especially
+ * when we finally become able to set this at runtime
+ * on response to X.org requests */
+ hotkey_reserved_mask |=
+ (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
+ | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
+ }
+
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
res = hotkey_status_set(1);
@@ -3110,13 +3251,82 @@ static struct ibm_struct video_driver_data = {
TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
+static int light_get_status(void)
+{
+ int status = 0;
+
+ if (tp_features.light_status) {
+ if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+ return -EIO;
+ return (!!status);
+ }
+
+ return -ENXIO;
+}
+
+static int light_set_status(int status)
+{
+ int rc;
+
+ if (tp_features.light) {
+ if (cmos_handle) {
+ rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
+ (status)?
+ TP_CMOS_THINKLIGHT_ON :
+ TP_CMOS_THINKLIGHT_OFF);
+ } else {
+ rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
+ (status)? 1 : 0);
+ }
+ return (rc)? 0 : -EIO;
+ }
+
+ return -ENXIO;
+}
+
+static void light_set_status_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ light_set_status((data->new_brightness != LED_OFF));
+}
+
+static void light_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(led_cdev,
+ struct tpacpi_led_classdev,
+ led_classdev);
+ data->new_brightness = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
+{
+ return (light_get_status() == 1)? LED_FULL : LED_OFF;
+}
+
+static struct tpacpi_led_classdev tpacpi_led_thinklight = {
+ .led_classdev = {
+ .name = "tpacpi::thinklight",
+ .brightness_set = &light_sysfs_set,
+ .brightness_get = &light_sysfs_get,
+ }
+};
+
static int __init light_init(struct ibm_init_struct *iibm)
{
+ int rc = 0;
+
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
TPACPI_ACPIHANDLE_INIT(ledb);
TPACPI_ACPIHANDLE_INIT(lght);
TPACPI_ACPIHANDLE_INIT(cmos);
+ INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker);
/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -3130,13 +3340,31 @@ static int __init light_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
str_supported(tp_features.light));
- return (tp_features.light)? 0 : 1;
+ if (tp_features.light) {
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_led_thinklight.led_classdev);
+ }
+
+ if (rc < 0) {
+ tp_features.light = 0;
+ tp_features.light_status = 0;
+ } else {
+ rc = (tp_features.light)? 0 : 1;
+ }
+ return rc;
+}
+
+static void light_exit(void)
+{
+ led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
+ if (work_pending(&tpacpi_led_thinklight.work))
+ flush_workqueue(tpacpi_wq);
}
static int light_read(char *p)
{
int len = 0;
- int status = 0;
+ int status;
if (!tp_features.light) {
len += sprintf(p + len, "status:\t\tnot supported\n");
@@ -3144,8 +3372,9 @@ static int light_read(char *p)
len += sprintf(p + len, "status:\t\tunknown\n");
len += sprintf(p + len, "commands:\ton, off\n");
} else {
- if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
- return -EIO;
+ status = light_get_status();
+ if (status < 0)
+ return status;
len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
len += sprintf(p + len, "commands:\ton, off\n");
}
@@ -3155,37 +3384,29 @@ static int light_read(char *p)
static int light_write(char *buf)
{
- int cmos_cmd, lght_cmd;
char *cmd;
- int success;
+ int newstatus = 0;
if (!tp_features.light)
return -ENODEV;
while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "on") == 0) {
- cmos_cmd = 0x0c;
- lght_cmd = 1;
+ newstatus = 1;
} else if (strlencmp(cmd, "off") == 0) {
- cmos_cmd = 0x0d;
- lght_cmd = 0;
+ newstatus = 0;
} else
return -EINVAL;
-
- success = cmos_handle ?
- acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
- acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
- if (!success)
- return -EIO;
}
- return 0;
+ return light_set_status(newstatus);
}
static struct ibm_struct light_driver_data = {
.name = "light",
.read = light_read,
.write = light_write,
+ .exit = light_exit,
};
/*************************************************************************
@@ -3583,6 +3804,12 @@ enum { /* For TPACPI_LED_OLD */
TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
};
+enum led_status_t {
+ TPACPI_LED_OFF = 0,
+ TPACPI_LED_ON,
+ TPACPI_LED_BLINK,
+};
+
static enum led_access_mode led_supported;
TPACPI_HANDLE(led, ec, "SLED", /* 570 */
@@ -3591,8 +3818,174 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
"LED", /* all others */
); /* R30, R31 */
+#define TPACPI_LED_NUMLEDS 8
+static struct tpacpi_led_classdev *tpacpi_leds;
+static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
+static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
+ /* there's a limit of 19 chars + NULL before 2.6.26 */
+ "tpacpi::power",
+ "tpacpi:orange:batt",
+ "tpacpi:green:batt",
+ "tpacpi::dock_active",
+ "tpacpi::bay_active",
+ "tpacpi::dock_batt",
+ "tpacpi::unknown_led",
+ "tpacpi::standby",
+};
+
+static int led_get_status(unsigned int led)
+{
+ int status;
+ enum led_status_t led_s;
+
+ switch (led_supported) {
+ case TPACPI_LED_570:
+ if (!acpi_evalf(ec_handle,
+ &status, "GLED", "dd", 1 << led))
+ return -EIO;
+ led_s = (status == 0)?
+ TPACPI_LED_OFF :
+ ((status == 1)?
+ TPACPI_LED_ON :
+ TPACPI_LED_BLINK);
+ tpacpi_led_state_cache[led] = led_s;
+ return led_s;
+ default:
+ return -ENXIO;
+ }
+
+ /* not reached */
+}
+
+static int led_set_status(unsigned int led, enum led_status_t ledstatus)
+{
+ /* off, on, blink. Index is led_status_t */
+ static const int const led_sled_arg1[] = { 0, 1, 3 };
+ static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
+ static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
+ static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+ int rc = 0;
+
+ switch (led_supported) {
+ case TPACPI_LED_570:
+ /* 570 */
+ led = 1 << led;
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_sled_arg1[ledstatus]))
+ rc = -EIO;
+ break;
+ case TPACPI_LED_OLD:
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+ led = 1 << led;
+ rc = ec_write(TPACPI_LED_EC_HLMS, led);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLBL,
+ led * led_exp_hlbl[ledstatus]);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLCL,
+ led * led_exp_hlcl[ledstatus]);
+ break;
+ case TPACPI_LED_NEW:
+ /* all others */
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_led_arg1[ledstatus]))
+ rc = -EIO;
+ break;
+ default:
+ rc = -ENXIO;
+ }
+
+ if (!rc)
+ tpacpi_led_state_cache[led] = ledstatus;
+
+ return rc;
+}
+
+static void led_sysfs_set_status(unsigned int led,
+ enum led_brightness brightness)
+{
+ led_set_status(led,
+ (brightness == LED_OFF) ?
+ TPACPI_LED_OFF :
+ (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ?
+ TPACPI_LED_BLINK : TPACPI_LED_ON);
+}
+
+static void led_set_status_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ led_sysfs_set_status(data->led, data->new_brightness);
+}
+
+static void led_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ data->new_brightness = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static int led_sysfs_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on, unsigned long *delay_off)
+{
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ /* Can we choose the flash rate? */
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* yes. set them to the hardware blink rate (1 Hz) */
+ *delay_on = 500; /* ms */
+ *delay_off = 500; /* ms */
+ } else if ((*delay_on != 500) || (*delay_off != 500))
+ return -EINVAL;
+
+ data->new_brightness = TPACPI_LED_BLINK;
+ queue_work(tpacpi_wq, &data->work);
+
+ return 0;
+}
+
+static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev)
+{
+ int rc;
+
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ rc = led_get_status(data->led);
+
+ if (rc == TPACPI_LED_OFF || rc < 0)
+ rc = LED_OFF; /* no error handling in led class :( */
+ else
+ rc = LED_FULL;
+
+ return rc;
+}
+
+static void led_exit(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+ if (tpacpi_leds[i].led_classdev.name)
+ led_classdev_unregister(&tpacpi_leds[i].led_classdev);
+ }
+
+ kfree(tpacpi_leds);
+ tpacpi_leds = NULL;
+}
+
static int __init led_init(struct ibm_init_struct *iibm)
{
+ unsigned int i;
+ int rc;
+
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
TPACPI_ACPIHANDLE_INIT(led);
@@ -3613,10 +4006,41 @@ static int __init led_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
str_supported(led_supported), led_supported);
+ tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
+ GFP_KERNEL);
+ if (!tpacpi_leds) {
+ printk(TPACPI_ERR "Out of memory for LED data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+ tpacpi_leds[i].led = i;
+
+ tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set;
+ tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set;
+ if (led_supported == TPACPI_LED_570)
+ tpacpi_leds[i].led_classdev.brightness_get =
+ &led_sysfs_get;
+
+ tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i];
+
+ INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker);
+
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_leds[i].led_classdev);
+ if (rc < 0) {
+ tpacpi_leds[i].led_classdev.name = NULL;
+ led_exit();
+ return rc;
+ }
+ }
+
return (led_supported != TPACPI_LED_NONE)? 0 : 1;
}
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+#define str_led_status(s) \
+ ((s) == TPACPI_LED_OFF ? "off" : \
+ ((s) == TPACPI_LED_ON ? "on" : "blinking"))
static int led_read(char *p)
{
@@ -3632,11 +4056,11 @@ static int led_read(char *p)
/* 570 */
int i, status;
for (i = 0; i < 8; i++) {
- if (!acpi_evalf(ec_handle,
- &status, "GLED", "dd", 1 << i))
+ status = led_get_status(i);
+ if (status < 0)
return -EIO;
len += sprintf(p + len, "%d:\t\t%s\n",
- i, led_status(status));
+ i, str_led_status(status));
}
}
@@ -3646,16 +4070,11 @@ static int led_read(char *p)
return len;
}
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
static int led_write(char *buf)
{
char *cmd;
- int led, ind, ret;
+ int led, rc;
+ enum led_status_t s;
if (!led_supported)
return -ENODEV;
@@ -3665,38 +4084,18 @@ static int led_write(char *buf)
return -EINVAL;
if (strstr(cmd, "off")) {
- ind = 0;
+ s = TPACPI_LED_OFF;
} else if (strstr(cmd, "on")) {
- ind = 1;
+ s = TPACPI_LED_ON;
} else if (strstr(cmd, "blink")) {
- ind = 2;
- } else
- return -EINVAL;
-
- if (led_supported == TPACPI_LED_570) {
- /* 570 */
- led = 1 << led;
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_sled_arg1[ind]))
- return -EIO;
- } else if (led_supported == TPACPI_LED_OLD) {
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
- led = 1 << led;
- ret = ec_write(TPACPI_LED_EC_HLMS, led);
- if (ret >= 0)
- ret = ec_write(TPACPI_LED_EC_HLBL,
- led * led_exp_hlbl[ind]);
- if (ret >= 0)
- ret = ec_write(TPACPI_LED_EC_HLCL,
- led * led_exp_hlcl[ind]);
- if (ret < 0)
- return ret;
+ s = TPACPI_LED_BLINK;
} else {
- /* all others */
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_led_arg1[ind]))
- return -EIO;
+ return -EINVAL;
}
+
+ rc = led_set_status(led, s);
+ if (rc < 0)
+ return rc;
}
return 0;
@@ -3706,6 +4105,7 @@ static struct ibm_struct led_driver_data = {
.name = "led",
.read = led_read,
.write = led_write,
+ .exit = led_exit,
};
/*************************************************************************
@@ -4170,8 +4570,16 @@ static struct ibm_struct ecdump_driver_data = {
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+enum {
+ TP_EC_BACKLIGHT = 0x31,
+
+ /* TP_EC_BACKLIGHT bitmasks */
+ TP_EC_BACKLIGHT_LVLMSK = 0x1F,
+ TP_EC_BACKLIGHT_CMDMSK = 0xE0,
+ TP_EC_BACKLIGHT_MAPSW = 0x20,
+};
+
static struct backlight_device *ibm_backlight_device;
-static int brightness_offset = 0x31;
static int brightness_mode;
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
@@ -4180,16 +4588,24 @@ static struct mutex brightness_mutex;
/*
* ThinkPads can read brightness from two places: EC 0x31, or
* CMOS NVRAM byte 0x5E, bits 0-3.
+ *
+ * EC 0x31 has the following layout
+ * Bit 7: unknown function
+ * Bit 6: unknown function
+ * Bit 5: Z: honour scale changes, NZ: ignore scale changes
+ * Bit 4: must be set to zero to avoid problems
+ * Bit 3-0: backlight brightness level
+ *
+ * brightness_get_raw returns status data in the EC 0x31 layout
*/
-static int brightness_get(struct backlight_device *bd)
+static int brightness_get_raw(int *status)
{
u8 lec = 0, lcmos = 0, level = 0;
if (brightness_mode & 1) {
- if (!acpi_ec_read(brightness_offset, &lec))
+ if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
return -EIO;
- lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
- level = lec;
+ level = lec & TP_EC_BACKLIGHT_LVLMSK;
};
if (brightness_mode & 2) {
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
@@ -4199,16 +4615,27 @@ static int brightness_get(struct backlight_device *bd)
level = lcmos;
}
- if (brightness_mode == 3 && lec != lcmos) {
- printk(TPACPI_ERR
- "CMOS NVRAM (%u) and EC (%u) do not agree "
- "on display brightness level\n",
- (unsigned int) lcmos,
- (unsigned int) lec);
- return -EIO;
+ if (brightness_mode == 3) {
+ *status = lec; /* Prefer EC, CMOS is just a backing store */
+ lec &= TP_EC_BACKLIGHT_LVLMSK;
+ if (lec == lcmos)
+ tp_warned.bright_cmos_ec_unsync = 0;
+ else {
+ if (!tp_warned.bright_cmos_ec_unsync) {
+ printk(TPACPI_ERR
+ "CMOS NVRAM (%u) and EC (%u) do not "
+ "agree on display brightness level\n",
+ (unsigned int) lcmos,
+ (unsigned int) lec);
+ tp_warned.bright_cmos_ec_unsync = 1;
+ }
+ return -EIO;
+ }
+ } else {
+ *status = level;
}
- return level;
+ return 0;
}
/* May return EINTR which can always be mapped to ERESTARTSYS */
@@ -4216,19 +4643,22 @@ static int brightness_set(int value)
{
int cmos_cmd, inc, i, res;
int current_value;
+ int command_bits;
- if (value > ((tp_features.bright_16levels)? 15 : 7))
+ if (value > ((tp_features.bright_16levels)? 15 : 7) ||
+ value < 0)
return -EINVAL;
res = mutex_lock_interruptible(&brightness_mutex);
if (res < 0)
return res;
- current_value = brightness_get(NULL);
- if (current_value < 0) {
- res = current_value;
+ res = brightness_get_raw(&current_value);
+ if (res < 0)
goto errout;
- }
+
+ command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
+ current_value &= TP_EC_BACKLIGHT_LVLMSK;
cmos_cmd = value > current_value ?
TP_CMOS_BRIGHTNESS_UP :
@@ -4243,7 +4673,8 @@ static int brightness_set(int value)
goto errout;
}
if ((brightness_mode & 1) &&
- !acpi_ec_write(brightness_offset, i + inc)) {
+ !acpi_ec_write(TP_EC_BACKLIGHT,
+ (i + inc) | command_bits)) {
res = -EIO;
goto errout;;
}
@@ -4266,106 +4697,23 @@ static int brightness_update_status(struct backlight_device *bd)
bd->props.brightness : 0);
}
-static struct backlight_ops ibm_backlight_data = {
- .get_brightness = brightness_get,
- .update_status = brightness_update_status,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int __init tpacpi_query_bcll_levels(acpi_handle handle)
-{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- int rc;
-
- if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
- obj = (union acpi_object *)buffer.pointer;
- if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
- printk(TPACPI_ERR "Unknown BCLL data, "
- "please report this to %s\n", TPACPI_MAIL);
- rc = 0;
- } else {
- rc = obj->package.count;
- }
- } else {
- return 0;
- }
-
- kfree(buffer.pointer);
- return rc;
-}
-
-static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
-
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("BCLL", name, sizeof(name) - 1)) {
- if (tpacpi_query_bcll_levels(handle) == 16) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
- } else {
- return AE_OK;
- }
-}
-
-static int __init brightness_check_levels(void)
+static int brightness_get(struct backlight_device *bd)
{
- int status;
- void *found_node = NULL;
+ int status, res;
- if (!vid_handle) {
- TPACPI_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a BCLL package with 16 levels */
- status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
- brightness_find_bcll, NULL,
- &found_node);
-
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
-static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
+ res = brightness_get_raw(&status);
+ if (res < 0)
+ return 0; /* FIXME: teach backlight about error handling */
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("_BCL", name, sizeof(name) - 1)) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
+ return status & TP_EC_BACKLIGHT_LVLMSK;
}
-static int __init brightness_check_std_acpi_support(void)
-{
- int status;
- void *found_node = NULL;
-
- if (!vid_handle) {
- TPACPI_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a _BCL method, but don't execute it */
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
- brightness_find_bcl, NULL, &found_node);
+static struct backlight_ops ibm_backlight_data = {
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+};
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
+/* --------------------------------------------------------------------- */
static int __init brightness_init(struct ibm_init_struct *iibm)
{
@@ -4375,13 +4723,19 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
mutex_init(&brightness_mutex);
- if (!brightness_enable) {
- dbg_printk(TPACPI_DBG_INIT,
- "brightness support disabled by "
- "module parameter\n");
- return 1;
- } else if (brightness_enable > 1) {
- if (brightness_check_std_acpi_support()) {
+ /*
+ * We always attempt to detect acpi support, so as to switch
+ * Lenovo Vista BIOS to ACPI brightness mode even if we are not
+ * going to publish a backlight interface
+ */
+ b = tpacpi_check_std_acpi_brightness_support();
+ if (b > 0) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+ printk(TPACPI_NOTICE
+ "Lenovo BIOS switched to ACPI backlight "
+ "control mode\n");
+ }
+ if (brightness_enable > 1) {
printk(TPACPI_NOTICE
"standard ACPI backlight interface "
"available, not loading native one...\n");
@@ -4389,6 +4743,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
}
}
+ if (!brightness_enable) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "brightness support disabled by "
+ "module parameter\n");
+ return 1;
+ }
+
+ if (b > 16) {
+ printk(TPACPI_ERR
+ "Unsupported brightness interface, "
+ "please contact %s\n", TPACPI_MAIL);
+ return 1;
+ }
+ if (b == 16)
+ tp_features.bright_16levels = 1;
+
if (!brightness_mode) {
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
brightness_mode = 2;
@@ -4402,12 +4772,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
if (brightness_mode > 3)
return -EINVAL;
- tp_features.bright_16levels =
- thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
- brightness_check_levels();
-
- b = brightness_get(NULL);
- if (b < 0)
+ if (brightness_get_raw(&b) < 0)
return 1;
if (tp_features.bright_16levels)
@@ -4425,7 +4790,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
ibm_backlight_device->props.max_brightness =
(tp_features.bright_16levels)? 15 : 7;
- ibm_backlight_device->props.brightness = b;
+ ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
backlight_update_status(ibm_backlight_device);
return 0;
@@ -5046,11 +5411,11 @@ static void fan_watchdog_reset(void)
if (fan_watchdog_maxinterval > 0 &&
tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
fan_watchdog_active = 1;
- if (!schedule_delayed_work(&fan_watchdog_task,
+ if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval
* 1000))) {
printk(TPACPI_ERR
- "failed to schedule the fan watchdog, "
+ "failed to queue the fan watchdog, "
"watchdog will not trigger\n");
}
} else
@@ -5420,7 +5785,7 @@ static void fan_exit(void)
&driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task);
- flush_scheduled_work();
+ flush_workqueue(tpacpi_wq);
}
static int fan_read(char *p)
@@ -5826,10 +6191,13 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
GFP_KERNEL);
- if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+ if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
kfree(tp->model_str);
tp->model_str = NULL;
}
+
+ tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME),
+ GFP_KERNEL);
}
static int __init probe_for_thinkpad(void)
@@ -6071,6 +6439,9 @@ static void thinkpad_acpi_module_exit(void)
if (proc_dir)
remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
+ if (tpacpi_wq)
+ destroy_workqueue(tpacpi_wq);
+
kfree(thinkpad_id.bios_version_str);
kfree(thinkpad_id.ec_version_str);
kfree(thinkpad_id.model_str);
@@ -6101,6 +6472,12 @@ static int __init thinkpad_acpi_module_init(void)
TPACPI_ACPIHANDLE_INIT(ecrd);
TPACPI_ACPIHANDLE_INIT(ecwr);
+ tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME);
+ if (!tpacpi_wq) {
+ thinkpad_acpi_module_exit();
+ return -ENOMEM;
+ }
+
proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
if (!proc_dir) {
printk(TPACPI_ERR
@@ -6223,6 +6600,8 @@ static int __init thinkpad_acpi_module_init(void)
/* Please remove this in year 2009 */
MODULE_ALIAS("ibm_acpi");
+MODULE_ALIAS(TPACPI_DRVR_SHORTNAME);
+
/*
* DMI matching for module autoloading
*
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index e8503341e3b1..eed06d068fd1 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -158,6 +158,12 @@ config MTD_OF_PARTS
the partition map from the children of the flash node,
as described in Documentation/powerpc/booting-without-of.txt.
+config MTD_AR7_PARTS
+ tristate "TI AR7 partitioning support"
+ depends on MTD_PARTITIONS
+ ---help---
+ TI AR7 partitioning support
+
comment "User Modules And Translation Layers"
config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 538e33d11d46..4b77335715f0 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
# 'Users' - code which presents functionality to userspace.
diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c
new file mode 100644
index 000000000000..ecf170b55c32
--- /dev/null
+++ b/drivers/mtd/ar7part.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright © 2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * TI AR7 flash partition table.
+ * Based on ar7 map by Felix Fietkau <nbd@openwrt.org>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/bootmem.h>
+#include <linux/magic.h>
+
+#define AR7_PARTS 4
+#define ROOT_OFFSET 0xe0000
+
+#define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42)
+#define LOADER_MAGIC2 le32_to_cpu(0xfeed1281)
+
+#ifndef SQUASHFS_MAGIC
+#define SQUASHFS_MAGIC 0x73717368
+#endif
+
+struct ar7_bin_rec {
+ unsigned int checksum;
+ unsigned int length;
+ unsigned int address;
+};
+
+static struct mtd_partition ar7_parts[AR7_PARTS];
+
+static int create_mtd_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ unsigned long origin)
+{
+ struct ar7_bin_rec header;
+ unsigned int offset;
+ size_t len;
+ unsigned int pre_size = master->erasesize, post_size = 0;
+ unsigned int root_offset = ROOT_OFFSET;
+
+ int retries = 10;
+
+ ar7_parts[0].name = "loader";
+ ar7_parts[0].offset = 0;
+ ar7_parts[0].size = master->erasesize;
+ ar7_parts[0].mask_flags = MTD_WRITEABLE;
+
+ ar7_parts[1].name = "config";
+ ar7_parts[1].offset = 0;
+ ar7_parts[1].size = master->erasesize;
+ ar7_parts[1].mask_flags = 0;
+
+ do { /* Try 10 blocks starting from master->erasesize */
+ offset = pre_size;
+ master->read(master, offset,
+ sizeof(header), &len, (uint8_t *)&header);
+ if (!strncmp((char *)&header, "TIENV0.8", 8))
+ ar7_parts[1].offset = pre_size;
+ if (header.checksum == LOADER_MAGIC1)
+ break;
+ if (header.checksum == LOADER_MAGIC2)
+ break;
+ pre_size += master->erasesize;
+ } while (retries--);
+
+ pre_size = offset;
+
+ if (!ar7_parts[1].offset) {
+ ar7_parts[1].offset = master->size - master->erasesize;
+ post_size = master->erasesize;
+ }
+
+ switch (header.checksum) {
+ case LOADER_MAGIC1:
+ while (header.length) {
+ offset += sizeof(header) + header.length;
+ master->read(master, offset, sizeof(header),
+ &len, (uint8_t *)&header);
+ }
+ root_offset = offset + sizeof(header) + 4;
+ break;
+ case LOADER_MAGIC2:
+ while (header.length) {
+ offset += sizeof(header) + header.length;
+ master->read(master, offset, sizeof(header),
+ &len, (uint8_t *)&header);
+ }
+ root_offset = offset + sizeof(header) + 4 + 0xff;
+ root_offset &= ~(uint32_t)0xff;
+ break;
+ default:
+ printk(KERN_WARNING "Unknown magic: %08x\n", header.checksum);
+ break;
+ }
+
+ master->read(master, root_offset,
+ sizeof(header), &len, (u8 *)&header);
+ if (header.checksum != SQUASHFS_MAGIC) {
+ root_offset += master->erasesize - 1;
+ root_offset &= ~(master->erasesize - 1);
+ }
+
+ ar7_parts[2].name = "linux";
+ ar7_parts[2].offset = pre_size;
+ ar7_parts[2].size = master->size - pre_size - post_size;
+ ar7_parts[2].mask_flags = 0;
+
+ ar7_parts[3].name = "rootfs";
+ ar7_parts[3].offset = root_offset;
+ ar7_parts[3].size = master->size - root_offset - post_size;
+ ar7_parts[3].mask_flags = 0;
+
+ *pparts = ar7_parts;
+ return AR7_PARTS;
+}
+
+static struct mtd_part_parser ar7_parser = {
+ .owner = THIS_MODULE,
+ .parse_fn = create_mtd_partitions,
+ .name = "ar7part",
+};
+
+static int __init ar7_parser_init(void)
+{
+ return register_mtd_parser(&ar7_parser);
+}
+
+module_init(ar7_parser_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR( "Felix Fietkau <nbd@openwrt.org>, "
+ "Eugene Konev <ejka@openwrt.org>");
+MODULE_DESCRIPTION("MTD partitioning for TI AR7");
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 0080452531d6..e812df607a5c 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -384,7 +384,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
if (extp_size > 4096) {
printk(KERN_ERR
"%s: cfi_pri_intelext is too fat\n",
- __FUNCTION__);
+ __func__);
return NULL;
}
goto again;
@@ -619,6 +619,9 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
sizeof(struct cfi_intelext_blockinfo);
}
+ if (!numparts)
+ numparts = 1;
+
/* Programming Region info */
if (extp->MinorVersion >= '4') {
struct cfi_intelext_programming_regioninfo *prinfo;
@@ -641,7 +644,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
if ((1 << partshift) < mtd->erasesize) {
printk( KERN_ERR
"%s: bad number of hw partitions (%d)\n",
- __FUNCTION__, numparts);
+ __func__, numparts);
return -EINVAL;
}
@@ -1071,10 +1074,10 @@ static int __xipram xip_wait_for_operation(
chip->state = newstate;
map_write(map, CMD(0xff), adr);
(void) map_read(map, adr);
- asm volatile (".rep 8; nop; .endr");
+ xip_iprefetch();
local_irq_enable();
spin_unlock(chip->mutex);
- asm volatile (".rep 8; nop; .endr");
+ xip_iprefetch();
cond_resched();
/*
@@ -2013,7 +2016,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
#ifdef DEBUG_LOCK_BITS
printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
- __FUNCTION__, ofs, len);
+ __func__, ofs, len);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
ofs, len, NULL);
#endif
@@ -2023,7 +2026,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
#ifdef DEBUG_LOCK_BITS
printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
- __FUNCTION__, ret);
+ __func__, ret);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
ofs, len, NULL);
#endif
@@ -2037,7 +2040,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
#ifdef DEBUG_LOCK_BITS
printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
- __FUNCTION__, ofs, len);
+ __func__, ofs, len);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
ofs, len, NULL);
#endif
@@ -2047,7 +2050,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
#ifdef DEBUG_LOCK_BITS
printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
- __FUNCTION__, ret);
+ __func__, ret);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
ofs, len, NULL);
#endif
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 458d477614d6..f7fcc6389533 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -220,6 +220,28 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
mtd->flags |= MTD_POWERUP_LOCK;
}
+static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) {
+ cfi->cfiq->EraseRegionInfo[0] |= 0x0040;
+ pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name);
+ }
+}
+
+static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) {
+ cfi->cfiq->EraseRegionInfo[1] &= ~0x0040;
+ pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name);
+ }
+}
+
static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
#ifdef AMD_BOOTLOC_BUG
@@ -231,6 +253,10 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, },
{ CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, },
{ CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, },
+ { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, },
+ { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, },
+ { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, },
+ { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, },
#if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
#endif
@@ -723,10 +749,10 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
chip->erase_suspended = 1;
map_write(map, CMD(0xf0), adr);
(void) map_read(map, adr);
- asm volatile (".rep 8; nop; .endr");
+ xip_iprefetch();
local_irq_enable();
spin_unlock(chip->mutex);
- asm volatile (".rep 8; nop; .endr");
+ xip_iprefetch();
cond_resched();
/*
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index 492e2ab27420..1b720cc571f3 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -445,7 +445,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
retry:
#ifdef DEBUG_CFI_FEATURES
- printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state);
+ printk("%s: chip->state[%d]\n", __func__, chip->state);
#endif
spin_lock_bh(chip->mutex);
@@ -463,7 +463,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
#ifdef DEBUG_CFI_FEATURES
- printk("%s: 1 status[%x]\n", __FUNCTION__, map_read(map, cmd_adr));
+ printk("%s: 1 status[%x]\n", __func__, map_read(map, cmd_adr));
#endif
case FL_STATUS:
@@ -591,7 +591,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
/* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
if (map_word_bitsset(map, status, CMD(0x3a))) {
#ifdef DEBUG_CFI_FEATURES
- printk("%s: 2 status[%lx]\n", __FUNCTION__, status.x[0]);
+ printk("%s: 2 status[%lx]\n", __func__, status.x[0]);
#endif
/* clear status */
map_write(map, CMD(0x50), cmd_adr);
@@ -625,9 +625,9 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
ofs = to - (chipnum << cfi->chipshift);
#ifdef DEBUG_CFI_FEATURES
- printk("%s: map_bankwidth(map)[%x]\n", __FUNCTION__, map_bankwidth(map));
- printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
- printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
+ printk("%s: map_bankwidth(map)[%x]\n", __func__, map_bankwidth(map));
+ printk("%s: chipnum[%x] wbufsize[%x]\n", __func__, chipnum, wbufsize);
+ printk("%s: ofs[%x] len[%x]\n", __func__, ofs, len);
#endif
/* Write buffer is worth it only if more than one word to write... */
@@ -893,7 +893,8 @@ retry:
return ret;
}
-int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_staa_erase_varsize(struct mtd_info *mtd,
+ struct erase_info *instr)
{ struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
unsigned long adr, len;
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
index f651b6ef1c5d..a4463a91ce31 100644
--- a/drivers/mtd/chips/cfi_probe.c
+++ b/drivers/mtd/chips/cfi_probe.c
@@ -39,7 +39,7 @@ struct mtd_info *cfi_probe(struct map_info *map);
#define xip_allowed(base, map) \
do { \
(void) map_read(map, base); \
- asm volatile (".rep 8; nop; .endr"); \
+ xip_iprefetch(); \
local_irq_enable(); \
} while (0)
@@ -232,6 +232,11 @@ static int __xipram cfi_chip_setup(struct map_info *map,
cfi->mfr = cfi_read_query16(map, base);
cfi->id = cfi_read_query16(map, base + ofs_factor);
+ /* Get AMD/Spansion extended JEDEC ID */
+ if (cfi->mfr == CFI_MFR_AMD && (cfi->id & 0xff) == 0x7e)
+ cfi->id = cfi_read_query(map, base + 0xe * ofs_factor) << 8 |
+ cfi_read_query(map, base + 0xf * ofs_factor);
+
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
/* ... even if it's an Intel chip */
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index 2e51496c248e..72e0022a47bf 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -65,7 +65,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
#ifdef CONFIG_MTD_XIP
(void) map_read(map, base);
- asm volatile (".rep 8; nop; .endr");
+ xip_iprefetch();
local_irq_enable();
#endif
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 4be51a86a85c..aa07575eb288 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -132,6 +132,8 @@
#define M29F800AB 0x0058
#define M29W800DT 0x00D7
#define M29W800DB 0x005B
+#define M29W400DT 0x00EE
+#define M29W400DB 0x00EF
#define M29W160DT 0x22C4
#define M29W160DB 0x2249
#define M29W040B 0x00E3
@@ -160,6 +162,7 @@
#define SST49LF030A 0x001C
#define SST49LF040A 0x0051
#define SST49LF080A 0x005B
+#define SST36VF3203 0x7354
/* Toshiba */
#define TC58FVT160 0x00C2
@@ -1113,7 +1116,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x10000,8),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29F016,
.name = "Macronix MX29F016",
@@ -1125,7 +1128,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x10000,32),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29F004T,
.name = "Macronix MX29F004T",
@@ -1140,7 +1143,7 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29F004B,
.name = "Macronix MX29F004B",
@@ -1218,7 +1221,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x40000,16),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39LF512,
.name = "SST 39LF512",
@@ -1230,7 +1233,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x01000,16),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39LF010,
.name = "SST 39LF010",
@@ -1242,7 +1245,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x01000,32),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST29EE020,
.name = "SST 29EE020",
@@ -1276,7 +1279,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x01000,64),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39LF040,
.name = "SST 39LF040",
@@ -1288,7 +1291,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x01000,128),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39SF010A,
.name = "SST 39SF010A",
@@ -1300,7 +1303,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x01000,32),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39SF020A,
.name = "SST 39SF020A",
@@ -1412,6 +1415,18 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x1000,256)
}
}, {
+ .mfr_id = MANUFACTURER_SST,
+ .dev_id = SST36VF3203,
+ .name = "SST 36VF3203",
+ .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+ .uaddr = MTD_UADDR_0x0AAA_0x0555,
+ .dev_size = SIZE_4MiB,
+ .cmd_set = P_ID_AMD_STD,
+ .nr_regions = 1,
+ .regions = {
+ ERASEINFO(0x10000,64),
+ }
+ }, {
.mfr_id = MANUFACTURER_ST,
.dev_id = M29F800AB,
.name = "ST M29F800AB",
@@ -1426,7 +1441,7 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x08000,1),
ERASEINFO(0x10000,15),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
.dev_id = M29W800DT,
.name = "ST M29W800DT",
@@ -1456,6 +1471,36 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x08000,1),
ERASEINFO(0x10000,15)
}
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M29W400DT,
+ .name = "ST M29W400DT",
+ .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+ .uaddr = MTD_UADDR_0x0AAA_0x0555,
+ .dev_size = SIZE_512KiB,
+ .cmd_set = P_ID_AMD_STD,
+ .nr_regions = 4,
+ .regions = {
+ ERASEINFO(0x04000,7),
+ ERASEINFO(0x02000,1),
+ ERASEINFO(0x08000,2),
+ ERASEINFO(0x10000,1)
+ }
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M29W400DB,
+ .name = "ST M29W400DB",
+ .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+ .uaddr = MTD_UADDR_0x0AAA_0x0555,
+ .dev_size = SIZE_512KiB,
+ .cmd_set = P_ID_AMD_STD,
+ .nr_regions = 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,7)
+ }
}, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
.dev_id = M29W160DT,
@@ -1486,7 +1531,7 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x08000,1),
ERASEINFO(0x10000,31)
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_ST,
.dev_id = M29W040B,
.name = "ST M29W040B",
@@ -1498,7 +1543,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x10000,8),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_ST,
.dev_id = M50FW040,
.name = "ST M50FW040",
@@ -1510,7 +1555,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x10000,8),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_ST,
.dev_id = M50FW080,
.name = "ST M50FW080",
@@ -1522,7 +1567,7 @@ static const struct amd_flash_info jedec_table[] = {
.regions = {
ERASEINFO(0x10000,16),
}
- }, {
+ }, {
.mfr_id = MANUFACTURER_ST,
.dev_id = M50FW016,
.name = "ST M50FW016",
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index b44292abd9f7..e472a0e9de9d 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -119,7 +119,8 @@ static struct mtd_partition * newpart(char *s,
char *p;
name = ++s;
- if ((p = strchr(name, delim)) == 0)
+ p = strchr(name, delim);
+ if (!p)
{
printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
return NULL;
@@ -159,9 +160,10 @@ static struct mtd_partition * newpart(char *s,
return NULL;
}
/* more partitions follow, parse them */
- if ((parts = newpart(s + 1, &s, num_parts,
- this_part + 1, &extra_mem, extra_mem_size)) == 0)
- return NULL;
+ parts = newpart(s + 1, &s, num_parts, this_part + 1,
+ &extra_mem, extra_mem_size);
+ if (!parts)
+ return NULL;
}
else
{ /* this is the last partition: allocate space for all */
@@ -308,9 +310,6 @@ static int parse_cmdline_partitions(struct mtd_info *master,
struct cmdline_mtd_partition *part;
char *mtd_id = master->name;
- if(!cmdline)
- return -EINVAL;
-
/* parse command line */
if (!cmdline_parsed)
mtdpart_setup_real(cmdline);
@@ -341,7 +340,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
return part->num_parts;
}
}
- return -EINVAL;
+ return 0;
}
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 811d56fd890f..35ed1103dbb2 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -77,6 +77,13 @@ config MTD_M25P80
if you want to specify device partitioning or to use a device which
doesn't support the JEDEC ID instruction.
+config M25PXX_USE_FAST_READ
+ bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz"
+ depends on MTD_M25P80
+ default y
+ help
+ This option enables FAST_READ access supported by ST M25Pxx.
+
config MTD_SLRAM
tristate "Uncached system RAM"
help
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index ad1880c67518..519d942e7940 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -305,7 +305,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
}
list_add(&dev->list, &blkmtd_device_list);
INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
- dev->mtd.name + strlen("blkmtd: "),
+ dev->mtd.name + strlen("block2mtd: "),
dev->mtd.erasesize >> 10, dev->mtd.erasesize);
return dev;
@@ -366,9 +366,9 @@ static inline void kill_final_newline(char *str)
}
-#define parse_err(fmt, args...) do { \
- ERROR("block2mtd: " fmt "\n", ## args); \
- return 0; \
+#define parse_err(fmt, args...) do { \
+ ERROR(fmt, ## args); \
+ return 0; \
} while (0)
#ifndef MODULE
@@ -473,7 +473,7 @@ static void __devexit block2mtd_exit(void)
block2mtd_sync(&dev->mtd);
del_mtd_device(&dev->mtd);
INFO("mtd%d: [%s] removed", dev->mtd.index,
- dev->mtd.name + strlen("blkmtd: "));
+ dev->mtd.name + strlen("block2mtd: "));
list_del(&dev->list);
block2mtd_free_device(dev);
}
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 99fd210feaec..1d324e5c412d 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -275,7 +275,7 @@ static __u8 read8 (__u32 offset)
{
volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset);
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n",__FUNCTION__,offset,*data);
+ printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n", __func__, offset, *data);
#endif
return (*data);
}
@@ -284,7 +284,7 @@ static __u32 read32 (__u32 offset)
{
volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset);
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n",__FUNCTION__,offset,*data);
+ printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n", __func__, offset, *data);
#endif
return (*data);
}
@@ -294,7 +294,7 @@ static void write32 (__u32 x,__u32 offset)
volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset);
*data = x;
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n",__FUNCTION__,offset,*data);
+ printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, *data);
#endif
}
@@ -337,7 +337,7 @@ static inline int erase_block (__u32 offset)
__u32 status;
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x\n",__FUNCTION__,offset);
+ printk (KERN_DEBUG "%s(): 0x%.8x\n", __func__, offset);
#endif
/* erase and confirm */
@@ -371,7 +371,7 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
int i,first;
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len);
+ printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len);
#endif
/* sanity checks */
@@ -442,7 +442,7 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf)
{
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,len);
+ printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len);
#endif
/* sanity checks */
@@ -488,7 +488,7 @@ static inline int write_dword (__u32 offset,__u32 x)
__u32 status;
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n",__FUNCTION__,offset,x);
+ printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, x);
#endif
/* setup writing */
@@ -524,7 +524,7 @@ static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen
int i,n;
#ifdef LART_DEBUG
- printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len);
+ printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len);
#endif
*retlen = 0;
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 98df5bcc02f3..25efd331ef28 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -33,7 +33,7 @@
/* Flash opcodes. */
#define OPCODE_WREN 0x06 /* Write enable */
#define OPCODE_RDSR 0x05 /* Read status register */
-#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */
+#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
@@ -52,7 +52,15 @@
/* Define max times to check status register before we give up. */
#define MAX_READY_WAIT_COUNT 100000
+#define CMD_SIZE 4
+#ifdef CONFIG_M25PXX_USE_FAST_READ
+#define OPCODE_READ OPCODE_FAST_READ
+#define FAST_READ_DUMMY_BYTE 1
+#else
+#define OPCODE_READ OPCODE_NORM_READ
+#define FAST_READ_DUMMY_BYTE 0
+#endif
#ifdef CONFIG_MTD_PARTITIONS
#define mtd_has_partitions() (1)
@@ -68,7 +76,7 @@ struct m25p {
struct mtd_info mtd;
unsigned partitioned:1;
u8 erase_opcode;
- u8 command[4];
+ u8 command[CMD_SIZE + FAST_READ_DUMMY_BYTE];
};
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@@ -151,7 +159,7 @@ static int wait_till_ready(struct m25p *flash)
static int erase_sector(struct m25p *flash, u32 offset)
{
DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n",
- flash->spi->dev.bus_id, __FUNCTION__,
+ flash->spi->dev.bus_id, __func__,
flash->mtd.erasesize / 1024, offset);
/* Wait until finished previous write command. */
@@ -167,7 +175,7 @@ static int erase_sector(struct m25p *flash, u32 offset)
flash->command[2] = offset >> 8;
flash->command[3] = offset;
- spi_write(flash->spi, flash->command, sizeof(flash->command));
+ spi_write(flash->spi, flash->command, CMD_SIZE);
return 0;
}
@@ -188,7 +196,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
u32 addr,len;
DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
- flash->spi->dev.bus_id, __FUNCTION__, "at",
+ flash->spi->dev.bus_id, __func__, "at",
(u32)instr->addr, instr->len);
/* sanity checks */
@@ -240,7 +248,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
struct spi_message m;
DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
- flash->spi->dev.bus_id, __FUNCTION__, "from",
+ flash->spi->dev.bus_id, __func__, "from",
(u32)from, len);
/* sanity checks */
@@ -253,8 +261,12 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
spi_message_init(&m);
memset(t, 0, (sizeof t));
+ /* NOTE:
+ * OPCODE_FAST_READ (if available) is faster.
+ * Should add 1 byte DUMMY_BYTE.
+ */
t[0].tx_buf = flash->command;
- t[0].len = sizeof(flash->command);
+ t[0].len = CMD_SIZE + FAST_READ_DUMMY_BYTE;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf;
@@ -287,7 +299,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
spi_sync(flash->spi, &m);
- *retlen = m.actual_length - sizeof(flash->command);
+ *retlen = m.actual_length - CMD_SIZE - FAST_READ_DUMMY_BYTE;
mutex_unlock(&flash->lock);
@@ -308,7 +320,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
struct spi_message m;
DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
- flash->spi->dev.bus_id, __FUNCTION__, "to",
+ flash->spi->dev.bus_id, __func__, "to",
(u32)to, len);
if (retlen)
@@ -325,7 +337,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
memset(t, 0, (sizeof t));
t[0].tx_buf = flash->command;
- t[0].len = sizeof(flash->command);
+ t[0].len = CMD_SIZE;
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
@@ -354,7 +366,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
spi_sync(flash->spi, &m);
- *retlen = m.actual_length - sizeof(flash->command);
+ *retlen = m.actual_length - CMD_SIZE;
} else {
u32 i;
@@ -364,7 +376,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
t[1].len = page_size;
spi_sync(flash->spi, &m);
- *retlen = m.actual_length - sizeof(flash->command);
+ *retlen = m.actual_length - CMD_SIZE;
/* write everything in PAGESIZE chunks */
for (i = page_size; i < len; i += page_size) {
@@ -387,8 +399,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
spi_sync(flash->spi, &m);
if (retlen)
- *retlen += m.actual_length
- - sizeof(flash->command);
+ *retlen += m.actual_length - CMD_SIZE;
}
}
@@ -435,6 +446,7 @@ static struct flash_info __devinitdata m25p_data [] = {
{ "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, },
{ "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
+ { "at25df641", 0x1f4800, 64 * 1024, 128, SECT_4K, },
{ "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, },
{ "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index e427c82d5f4c..bf485ff49457 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/mtdram.h>
static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 180298b92a7a..5f960182da95 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -282,7 +282,7 @@ static int phram_setup(const char *val, struct kernel_param *kp)
}
module_param_call(phram, phram_setup, NULL, NULL, 000);
-MODULE_PARM_DESC(phram,"Memory region to map. \"map=<name>,<start>,<length>\"");
+MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
static int __init init_phram(void)
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index c815d0f38577..4a79b187b568 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -136,8 +136,6 @@ typedef struct partition_t {
#endif
} partition_t;
-void ftl_freepart(partition_t *part);
-
/* Partition state flags */
#define FTL_FORMATTED 0x01
@@ -1014,7 +1012,7 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev,
/*====================================================================*/
-void ftl_freepart(partition_t *part)
+static void ftl_freepart(partition_t *part)
{
vfree(part->VirtualBlockMap);
part->VirtualBlockMap = NULL;
@@ -1069,7 +1067,7 @@ static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
kfree(dev);
}
-struct mtd_blktrans_ops ftl_tr = {
+static struct mtd_blktrans_ops ftl_tr = {
.name = "ftl",
.major = FTL_MAJOR,
.part_bits = PART_BITS,
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index b8917beeb650..c551d2f0779c 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -41,11 +41,6 @@
char inftlmountrev[]="$Revision: 1.18 $";
-extern int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
- size_t *retlen, uint8_t *buf);
-extern int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
- size_t *retlen, uint8_t *buf);
-
/*
* find_boot_record: Find the INFTL Media Header and its Spare copy which
* contains the various device information of the INFTL partition and
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 12c253664eb2..1bd69aa9e22a 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -21,6 +21,9 @@ config MTD_PHYSMAP
particular board as well as the bus width, either statically
with config options or at run-time.
+ To compile this driver as a module, choose M here: the
+ module will be called physmap.
+
config MTD_PHYSMAP_START
hex "Physical start address of flash mapping"
depends on MTD_PHYSMAP
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
index fc3b2672d1e2..1f492062f8ca 100644
--- a/drivers/mtd/maps/bast-flash.c
+++ b/drivers/mtd/maps/bast-flash.c
@@ -137,7 +137,7 @@ static int bast_flash_probe(struct platform_device *pdev)
if (info->map.size > AREA_MAXSIZE)
info->map.size = AREA_MAXSIZE;
- pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__,
+ pr_debug("%s: area %08lx, size %ld\n", __func__,
info->map.phys, info->map.size);
info->area = request_mem_region(res->start, info->map.size,
@@ -149,7 +149,7 @@ static int bast_flash_probe(struct platform_device *pdev)
}
info->map.virt = ioremap(res->start, info->map.size);
- pr_debug("%s: virt at %08x\n", __FUNCTION__, (int)info->map.virt);
+ pr_debug("%s: virt at %08x\n", __func__, (int)info->map.virt);
if (info->map.virt == 0) {
printk(KERN_ERR PFX "failed to ioremap() region\n");
@@ -223,3 +223,4 @@ module_exit(bast_flash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("BAST MTD Map driver");
+MODULE_ALIAS("platform:bast-nor");
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 688ef495888a..59d8fb49270a 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -28,6 +28,9 @@
#define ROM_PROBE_STEP_SIZE (64*1024)
+#define DEV_CK804 1
+#define DEV_MCP55 2
+
struct ck804xrom_window {
void __iomem *virt;
unsigned long phys;
@@ -45,8 +48,9 @@ struct ck804xrom_map_info {
char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
};
-
-/* The 2 bits controlling the window size are often set to allow reading
+/*
+ * The following applies to ck804 only:
+ * The 2 bits controlling the window size are often set to allow reading
* the BIOS, but too small to allow writing, since the lock registers are
* 4MiB lower in the address space than the data.
*
@@ -58,10 +62,17 @@ struct ck804xrom_map_info {
* If only the 7 Bit is set, it is a 4MiB window. Otherwise, a
* 64KiB window.
*
+ * The following applies to mcp55 only:
+ * The 15 bits controlling the window size are distributed as follows:
+ * byte @0x88: bit 0..7
+ * byte @0x8c: bit 8..15
+ * word @0x90: bit 16..30
+ * If all bits are enabled, we have a 16? MiB window
+ * Please set win_size_bits to 0x7fffffff if you actually want to do something
*/
static uint win_size_bits = 0;
module_param(win_size_bits, uint, 0);
-MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x88 byte, normally set by BIOS.");
+MODULE_PARM_DESC(win_size_bits, "ROM window size bits override, normally set by BIOS.");
static struct ck804xrom_window ck804xrom_window = {
.maps = LIST_HEAD_INIT(ck804xrom_window.maps),
@@ -102,10 +113,11 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
u8 byte;
+ u16 word;
struct ck804xrom_window *window = &ck804xrom_window;
struct ck804xrom_map_info *map = NULL;
unsigned long map_top;
@@ -113,26 +125,42 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
/* Remember the pci dev I find the window in */
window->pdev = pci_dev_get(pdev);
- /* Enable the selected rom window. This is often incorrectly
- * set up by the BIOS, and the 4MiB offset for the lock registers
- * requires the full 5MiB of window space.
- *
- * This 'write, then read' approach leaves the bits for
- * other uses of the hardware info.
- */
- pci_read_config_byte(pdev, 0x88, &byte);
- pci_write_config_byte(pdev, 0x88, byte | win_size_bits );
-
-
- /* Assume the rom window is properly setup, and find it's size */
- pci_read_config_byte(pdev, 0x88, &byte);
-
- if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6)))
- window->phys = 0xffb00000; /* 5MiB */
- else if ((byte & (1<<7)) == (1<<7))
- window->phys = 0xffc00000; /* 4MiB */
- else
- window->phys = 0xffff0000; /* 64KiB */
+ switch (ent->driver_data) {
+ case DEV_CK804:
+ /* Enable the selected rom window. This is often incorrectly
+ * set up by the BIOS, and the 4MiB offset for the lock registers
+ * requires the full 5MiB of window space.
+ *
+ * This 'write, then read' approach leaves the bits for
+ * other uses of the hardware info.
+ */
+ pci_read_config_byte(pdev, 0x88, &byte);
+ pci_write_config_byte(pdev, 0x88, byte | win_size_bits );
+
+ /* Assume the rom window is properly setup, and find it's size */
+ pci_read_config_byte(pdev, 0x88, &byte);
+
+ if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6)))
+ window->phys = 0xffb00000; /* 5MiB */
+ else if ((byte & (1<<7)) == (1<<7))
+ window->phys = 0xffc00000; /* 4MiB */
+ else
+ window->phys = 0xffff0000; /* 64KiB */
+ break;
+
+ case DEV_MCP55:
+ pci_read_config_byte(pdev, 0x88, &byte);
+ pci_write_config_byte(pdev, 0x88, byte | (win_size_bits & 0xff));
+
+ pci_read_config_byte(pdev, 0x8c, &byte);
+ pci_write_config_byte(pdev, 0x8c, byte | ((win_size_bits & 0xff00) >> 8));
+
+ pci_read_config_word(pdev, 0x90, &word);
+ pci_write_config_word(pdev, 0x90, word | ((win_size_bits & 0x7fff0000) >> 16));
+
+ window->phys = 0xff000000; /* 16MiB, hardcoded for now */
+ break;
+ }
window->size = 0xffffffffUL - window->phys + 1UL;
@@ -303,8 +331,15 @@ static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
}
static struct pci_device_id ck804xrom_pci_tbl[] = {
- { PCI_VENDOR_ID_NVIDIA, 0x0051,
- PCI_ANY_ID, PCI_ANY_ID, }, /* nvidia ck804 */
+ { PCI_VENDOR_ID_NVIDIA, 0x0051, PCI_ANY_ID, PCI_ANY_ID, DEV_CK804 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0360, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0361, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0362, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0363, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0364, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0365, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0366, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_VENDOR_ID_NVIDIA, 0x0367, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
{ 0, }
};
@@ -332,7 +367,7 @@ static int __init init_ck804xrom(void)
break;
}
if (pdev) {
- retVal = ck804xrom_init_one(pdev, &ck804xrom_pci_tbl[0]);
+ retVal = ck804xrom_init_one(pdev, id);
pci_dev_put(pdev);
return retVal;
}
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
index 6946d802e6f6..325c8880c437 100644
--- a/drivers/mtd/maps/integrator-flash.c
+++ b/drivers/mtd/maps/integrator-flash.c
@@ -190,6 +190,7 @@ static struct platform_driver armflash_driver = {
.remove = armflash_remove,
.driver = {
.name = "armflash",
+ .owner = THIS_MODULE,
},
};
@@ -209,3 +210,4 @@ module_exit(armflash_exit);
MODULE_AUTHOR("ARM Ltd");
MODULE_DESCRIPTION("ARM Integrator CFI map driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:armflash");
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index c26488a1793a..c8396b8574c4 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -253,6 +253,7 @@ static struct platform_driver ixp2000_flash_driver = {
.remove = ixp2000_flash_remove,
.driver = {
.name = "IXP2000-Flash",
+ .owner = THIS_MODULE,
},
};
@@ -270,4 +271,4 @@ module_init(ixp2000_flash_init);
module_exit(ixp2000_flash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-
+MODULE_ALIAS("platform:IXP2000-Flash");
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c
index 7a828e3e6446..01f19a4714b5 100644
--- a/drivers/mtd/maps/ixp4xx.c
+++ b/drivers/mtd/maps/ixp4xx.c
@@ -275,6 +275,7 @@ static struct platform_driver ixp4xx_flash_driver = {
.remove = ixp4xx_flash_remove,
.driver = {
.name = "IXP4XX-Flash",
+ .owner = THIS_MODULE,
},
};
@@ -295,3 +296,4 @@ module_exit(ixp4xx_flash_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems");
MODULE_AUTHOR("Deepak Saxena");
+MODULE_ALIAS("platform:IXP4XX-Flash");
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
index e8d9ae535673..240b0e2d095d 100644
--- a/drivers/mtd/maps/omap_nor.c
+++ b/drivers/mtd/maps/omap_nor.c
@@ -70,7 +70,7 @@ static void omap_set_vpp(struct map_info *map, int enable)
}
}
-static int __devinit omapflash_probe(struct platform_device *pdev)
+static int __init omapflash_probe(struct platform_device *pdev)
{
int err;
struct omapflash_info *info;
@@ -130,7 +130,7 @@ out_free_info:
return err;
}
-static int __devexit omapflash_remove(struct platform_device *pdev)
+static int __exit omapflash_remove(struct platform_device *pdev)
{
struct omapflash_info *info = platform_get_drvdata(pdev);
@@ -152,16 +152,16 @@ static int __devexit omapflash_remove(struct platform_device *pdev)
}
static struct platform_driver omapflash_driver = {
- .probe = omapflash_probe,
- .remove = __devexit_p(omapflash_remove),
+ .remove = __exit_p(omapflash_remove),
.driver = {
.name = "omapflash",
+ .owner = THIS_MODULE,
},
};
static int __init omapflash_init(void)
{
- return platform_driver_register(&omapflash_driver);
+ return platform_driver_probe(&omapflash_driver, omapflash_probe);
}
static void __exit omapflash_exit(void)
@@ -174,4 +174,4 @@ module_exit(omapflash_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards");
-
+MODULE_ALIAS("platform:omapflash");
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index eaeb56a4070a..1912d968718b 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -33,7 +33,7 @@ MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
#undef DEBUG
#define DEBUG(n, format, arg...) \
if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
}
#else
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index bc4649a17b9d..183255fcfdcb 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -242,6 +242,7 @@ static struct platform_driver physmap_flash_driver = {
.shutdown = physmap_flash_shutdown,
.driver = {
.name = "physmap-flash",
+ .owner = THIS_MODULE,
},
};
@@ -319,3 +320,10 @@ module_exit(physmap_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Generic configurable MTD map driver");
+
+/* legacy platform drivers can't hotplug or coldplg */
+#ifndef PHYSMAP_COMPAT
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:physmap-flash");
+#endif
+
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index 894c0b271289..3eb2643b2328 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -47,6 +47,7 @@ struct platram_info {
struct mtd_info *mtd;
struct map_info map;
struct mtd_partition *partitions;
+ bool free_partitions;
struct resource *area;
struct platdata_mtd_ram *pdata;
};
@@ -98,7 +99,8 @@ static int platram_remove(struct platform_device *pdev)
#ifdef CONFIG_MTD_PARTITIONS
if (info->partitions) {
del_mtd_partitions(info->mtd);
- kfree(info->partitions);
+ if (info->free_partitions)
+ kfree(info->partitions);
}
#endif
del_mtd_device(info->mtd);
@@ -176,7 +178,8 @@ static int platram_probe(struct platform_device *pdev)
info->map.phys = res->start;
info->map.size = (res->end - res->start) + 1;
- info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pdev->name;
+ info->map.name = pdata->mapname != NULL ?
+ (char *)pdata->mapname : (char *)pdev->name;
info->map.bankwidth = pdata->bankwidth;
/* register our usage of the memory area */
@@ -203,9 +206,19 @@ static int platram_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "initialised map, probing for mtd\n");
- /* probe for the right mtd map driver */
+ /* probe for the right mtd map driver
+ * supplied by the platform_data struct */
+
+ if (pdata->map_probes) {
+ const char **map_probes = pdata->map_probes;
+
+ for ( ; !info->mtd && *map_probes; map_probes++)
+ info->mtd = do_map_probe(*map_probes , &info->map);
+ }
+ /* fallback to map_ram */
+ else
+ info->mtd = do_map_probe("map_ram", &info->map);
- info->mtd = do_map_probe("map_ram" , &info->map);
if (info->mtd == NULL) {
dev_err(&pdev->dev, "failed to probe for map_ram\n");
err = -ENOMEM;
@@ -220,19 +233,21 @@ static int platram_probe(struct platform_device *pdev)
* to add this device whole */
#ifdef CONFIG_MTD_PARTITIONS
- if (pdata->nr_partitions > 0) {
- const char **probes = { NULL };
-
- if (pdata->probes)
- probes = (const char **)pdata->probes;
-
- err = parse_mtd_partitions(info->mtd, probes,
+ if (!pdata->nr_partitions) {
+ /* try to probe using the supplied probe type */
+ if (pdata->probes) {
+ err = parse_mtd_partitions(info->mtd, pdata->probes,
&info->partitions, 0);
- if (err > 0) {
- err = add_mtd_partitions(info->mtd, info->partitions,
- err);
+ info->free_partitions = 1;
+ if (err > 0)
+ err = add_mtd_partitions(info->mtd,
+ info->partitions, err);
}
}
+ /* use the static mapping */
+ else
+ err = add_mtd_partitions(info->mtd, pdata->partitions,
+ pdata->nr_partitions);
#endif /* CONFIG_MTD_PARTITIONS */
if (add_mtd_device(info->mtd)) {
@@ -240,7 +255,9 @@ static int platram_probe(struct platform_device *pdev)
err = -ENOMEM;
}
- dev_info(&pdev->dev, "registered mtd device\n");
+ if (!err)
+ dev_info(&pdev->dev, "registered mtd device\n");
+
return err;
exit_free:
@@ -251,6 +268,9 @@ static int platram_probe(struct platform_device *pdev)
/* device driver info */
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:mtd-ram");
+
static struct platform_driver platram_driver = {
.probe = platram_probe,
.remove = platram_remove,
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
index 02bde8c982ec..f43ba2815cbb 100644
--- a/drivers/mtd/maps/pmcmsp-flash.c
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -46,7 +46,7 @@ static struct mtd_partition **msp_parts;
static struct map_info *msp_maps;
static int fcnt;
-#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__)
+#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__)
int __init init_msp_flash(void)
{
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index f904e6bd02e0..c7d5a52a2d55 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -456,6 +456,7 @@ static struct platform_driver sa1100_mtd_driver = {
.shutdown = sa1100_mtd_shutdown,
.driver = {
.name = "flash",
+ .owner = THIS_MODULE,
},
};
@@ -475,3 +476,4 @@ module_exit(sa1100_mtd_exit);
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("SA1100 CFI map driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:flash");
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
index 12fe53c0d2fc..917dc778f24e 100644
--- a/drivers/mtd/maps/sharpsl-flash.c
+++ b/drivers/mtd/maps/sharpsl-flash.c
@@ -92,7 +92,7 @@ int __init init_sharpsl(void)
parts = sharpsl_partitions;
nb_parts = ARRAY_SIZE(sharpsl_partitions);
- printk(KERN_NOTICE "Using %s partision definition\n", part_type);
+ printk(KERN_NOTICE "Using %s partition definition\n", part_type);
add_mtd_partitions(mymtd, parts, nb_parts);
return 0;
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
index 37e4ded9b600..521734057314 100644
--- a/drivers/mtd/maps/tqm8xxl.c
+++ b/drivers/mtd/maps/tqm8xxl.c
@@ -124,7 +124,7 @@ int __init init_tqm_mtd(void)
//request maximum flash size address space
start_scan_addr = ioremap(flash_addr, flash_size);
if (!start_scan_addr) {
- printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
+ printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __func__, flash_addr);
return -EIO;
}
@@ -132,7 +132,7 @@ int __init init_tqm_mtd(void)
if(mtd_size >= flash_size)
break;
- printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
+ printk(KERN_INFO "%s: chip probing count %d\n", __func__, idx);
map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if(map_banks[idx] == NULL) {
@@ -178,7 +178,7 @@ int __init init_tqm_mtd(void)
mtd_size += mtd_banks[idx]->size;
num_banks++;
- printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
+ printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __func__, num_banks,
mtd_banks[idx]->name, mtd_banks[idx]->size);
}
}
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index d3cf05012b46..5a680e1e61f1 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -35,7 +35,7 @@
#define OOPS_PAGE_SIZE 4096
-struct mtdoops_context {
+static struct mtdoops_context {
int mtd_index;
struct work_struct work_erase;
struct work_struct work_write;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 959fb86cda01..5076faf9ca66 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -278,6 +278,54 @@ config MTD_NAND_AT91
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 processors.
+choice
+ prompt "ECC management for NAND Flash / SmartMedia on AT91"
+ depends on MTD_NAND_AT91
+
+config MTD_NAND_AT91_ECC_HW
+ bool "Hardware ECC"
+ depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260
+ help
+ Uses hardware ECC provided by the at91sam9260/at91sam9263 chip
+ instead of software ECC.
+ The hardware ECC controller is capable of single bit error
+ correction and 2-bit random detection per page.
+
+ NB : hardware and software ECC schemes are incompatible.
+ If you switch from one to another, you'll have to erase your
+ mtd partition.
+
+ If unsure, say Y
+
+config MTD_NAND_AT91_ECC_SOFT
+ bool "Software ECC"
+ help
+ Uses software ECC.
+
+ NB : hardware and software ECC schemes are incompatible.
+ If you switch from one to another, you'll have to erase your
+ mtd partition.
+
+config MTD_NAND_AT91_ECC_NONE
+ bool "No ECC (testing only, DANGEROUS)"
+ depends on DEBUG_KERNEL
+ help
+ No ECC will be used.
+ It's not a good idea and it should be reserved for testing
+ purpose only.
+
+ If unsure, say N
+
+ endchoice
+
+endchoice
+
+config MTD_NAND_PXA3xx
+ bool "Support for NAND flash devices on PXA3xx"
+ depends on MTD_NAND && PXA3xx
+ help
+ This enables the driver for the NAND flash device found on
+ PXA3xx processors
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
@@ -330,4 +378,12 @@ config MTD_NAND_FSL_ELBC
Enabling this option will enable you to use this to control
external NAND devices.
+config MTD_NAND_FSL_UPM
+ tristate "Support for NAND on Freescale UPM"
+ depends on MTD_NAND && OF_GPIO && (PPC_83xx || PPC_85xx)
+ select FSL_LBC
+ help
+ Enables support for NAND Flash chips wired onto Freescale PowerPC
+ processor localbus with User-Programmable Machine support.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 80d575eeee96..a6e74a46992a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -27,10 +27,12 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
+obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_ALAUDA) += alauda.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index c9fb2acf4056..414ceaecdb3a 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -9,6 +9,15 @@
* Derived from drivers/mtd/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
*
+ *
+ * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+ * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007
+ *
+ * Derived from Das U-Boot source code
+ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
+ *
* 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.
@@ -29,11 +38,59 @@
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
+#ifdef CONFIG_MTD_NAND_AT91_ECC_HW
+#define hard_ecc 1
+#else
+#define hard_ecc 0
+#endif
+
+#ifdef CONFIG_MTD_NAND_AT91_ECC_NONE
+#define no_ecc 1
+#else
+#define no_ecc 0
+#endif
+
+/* Register access macros */
+#define ecc_readl(add, reg) \
+ __raw_readl(add + AT91_ECC_##reg)
+#define ecc_writel(add, reg, value) \
+ __raw_writel((value), add + AT91_ECC_##reg)
+
+#include <asm/arch/at91_ecc.h> /* AT91SAM9260/3 ECC registers */
+
+/* oob layout for large page size
+ * bad block info is on bytes 0 and 1
+ * the bytes have to be consecutives to avoid
+ * several NAND_CMD_RNDOUT during read
+ */
+static struct nand_ecclayout at91_oobinfo_large = {
+ .eccbytes = 4,
+ .eccpos = {60, 61, 62, 63},
+ .oobfree = {
+ {2, 58}
+ },
+};
+
+/* oob layout for small page size
+ * bad block info is on bytes 4 and 5
+ * the bytes have to be consecutives to avoid
+ * several NAND_CMD_RNDOUT during read
+ */
+static struct nand_ecclayout at91_oobinfo_small = {
+ .eccbytes = 4,
+ .eccpos = {0, 1, 2, 3},
+ .oobfree = {
+ {6, 10}
+ },
+};
+
struct at91_nand_host {
struct nand_chip nand_chip;
struct mtd_info mtd;
void __iomem *io_base;
struct at91_nand_data *board;
+ struct device *dev;
+ void __iomem *ecc;
};
/*
@@ -44,6 +101,12 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv;
+ if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) {
+ if (ctrl & NAND_NCE)
+ at91_set_gpio_value(host->board->enable_pin, 0);
+ else
+ at91_set_gpio_value(host->board->enable_pin, 1);
+ }
if (cmd == NAND_CMD_NONE)
return;
@@ -82,8 +145,217 @@ static void at91_nand_disable(struct at91_nand_host *host)
at91_set_gpio_value(host->board->enable_pin, 1);
}
+/*
+ * write oob for small pages
+ */
+static int at91_nand_write_oob_512(struct mtd_info *mtd,
+ struct nand_chip *chip, int page)
+{
+ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+ int eccsize = chip->ecc.size, length = mtd->oobsize;
+ int len, pos, status = 0;
+ const uint8_t *bufpoi = chip->oob_poi;
+
+ pos = eccsize + chunk;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
+ len = min_t(int, length, chunk);
+ chip->write_buf(mtd, bufpoi, len);
+ bufpoi += len;
+ length -= len;
+ if (length > 0)
+ chip->write_buf(mtd, bufpoi, length);
+
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+
+}
+
+/*
+ * read oob for small pages
+ */
+static int at91_nand_read_oob_512(struct mtd_info *mtd,
+ struct nand_chip *chip, int page, int sndcmd)
+{
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
+ }
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return sndcmd;
+}
+
+/*
+ * Calculate HW ECC
+ *
+ * function called after a write
+ *
+ * mtd: MTD block structure
+ * dat: raw data (unused)
+ * ecc_code: buffer for ECC
+ */
+static int at91_nand_calculate(struct mtd_info *mtd,
+ const u_char *dat, unsigned char *ecc_code)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct at91_nand_host *host = nand_chip->priv;
+ uint32_t *eccpos = nand_chip->ecc.layout->eccpos;
+ unsigned int ecc_value;
+
+ /* get the first 2 ECC bytes */
+ ecc_value = ecc_readl(host->ecc, PR);
+
+ ecc_code[eccpos[0]] = ecc_value & 0xFF;
+ ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF;
+
+ /* get the last 2 ECC bytes */
+ ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY;
+
+ ecc_code[eccpos[2]] = ecc_value & 0xFF;
+ ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF;
+
+ return 0;
+}
+
+/*
+ * HW ECC read page function
+ *
+ * mtd: mtd info structure
+ * chip: nand chip info structure
+ * buf: buffer to store read data
+ */
+static int at91_nand_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf)
+{
+ int eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+ uint8_t *ecc_pos;
+ int stat;
+
+ /* read the page */
+ chip->read_buf(mtd, p, eccsize);
+
+ /* move to ECC position if needed */
+ if (eccpos[0] != 0) {
+ /* This only works on large pages
+ * because the ECC controller waits for
+ * NAND_CMD_RNDOUTSTART after the
+ * NAND_CMD_RNDOUT.
+ * anyway, for small pages, the eccpos[0] == 0
+ */
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+ mtd->writesize + eccpos[0], -1);
+ }
+
+ /* the ECC controller needs to read the ECC just after the data */
+ ecc_pos = oob + eccpos[0];
+ chip->read_buf(mtd, ecc_pos, eccbytes);
+
+ /* check if there's an error */
+ stat = chip->ecc.correct(mtd, p, oob, NULL);
+
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+
+ /* get back to oob start (end of page) */
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+
+ /* read the oob */
+ chip->read_buf(mtd, oob, mtd->oobsize);
+
+ return 0;
+}
+
+/*
+ * HW ECC Correction
+ *
+ * function called after a read
+ *
+ * mtd: MTD block structure
+ * dat: raw data read from the chip
+ * read_ecc: ECC from the chip (unused)
+ * isnull: unused
+ *
+ * Detect and correct a 1 bit error for a page
+ */
+static int at91_nand_correct(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *isnull)
+{
+ struct nand_chip *nand_chip = mtd->priv;
+ struct at91_nand_host *host = nand_chip->priv;
+ unsigned int ecc_status;
+ unsigned int ecc_word, ecc_bit;
+
+ /* get the status from the Status Register */
+ ecc_status = ecc_readl(host->ecc, SR);
+
+ /* if there's no error */
+ if (likely(!(ecc_status & AT91_ECC_RECERR)))
+ return 0;
+
+ /* get error bit offset (4 bits) */
+ ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR;
+ /* get word address (12 bits) */
+ ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR;
+ ecc_word >>= 4;
+
+ /* if there are multiple errors */
+ if (ecc_status & AT91_ECC_MULERR) {
+ /* check if it is a freshly erased block
+ * (filled with 0xff) */
+ if ((ecc_bit == AT91_ECC_BITADDR)
+ && (ecc_word == (AT91_ECC_WORDADDR >> 4))) {
+ /* the block has just been erased, return OK */
+ return 0;
+ }
+ /* it doesn't seems to be a freshly
+ * erased block.
+ * We can't correct so many errors */
+ dev_dbg(host->dev, "at91_nand : multiple errors detected."
+ " Unable to correct.\n");
+ return -EIO;
+ }
+
+ /* if there's a single bit error : we can correct it */
+ if (ecc_status & AT91_ECC_ECCERR) {
+ /* there's nothing much to do here.
+ * the bit error is on the ECC itself.
+ */
+ dev_dbg(host->dev, "at91_nand : one bit error on ECC code."
+ " Nothing to correct\n");
+ return 0;
+ }
+
+ dev_dbg(host->dev, "at91_nand : one bit error on data."
+ " (word offset in the page :"
+ " 0x%x bit offset : 0x%x)\n",
+ ecc_word, ecc_bit);
+ /* correct the error */
+ if (nand_chip->options & NAND_BUSWIDTH_16) {
+ /* 16 bits words */
+ ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit);
+ } else {
+ /* 8 bits words */
+ dat[ecc_word] ^= (1 << ecc_bit);
+ }
+ dev_dbg(host->dev, "at91_nand : error corrected\n");
+ return 1;
+}
+
+/*
+ * Enable HW ECC : unsused
+ */
+static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; }
+
#ifdef CONFIG_MTD_PARTITIONS
-const char *part_probes[] = { "cmdlinepart", NULL };
+static const char *part_probes[] = { "cmdlinepart", NULL };
#endif
/*
@@ -94,6 +366,8 @@ static int __init at91_nand_probe(struct platform_device *pdev)
struct at91_nand_host *host;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
+ struct resource *regs;
+ struct resource *mem;
int res;
#ifdef CONFIG_MTD_PARTITIONS
@@ -108,8 +382,13 @@ static int __init at91_nand_probe(struct platform_device *pdev)
return -ENOMEM;
}
- host->io_base = ioremap(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ printk(KERN_ERR "at91_nand: can't get I/O resource mem\n");
+ return -ENXIO;
+ }
+
+ host->io_base = ioremap(mem->start, mem->end - mem->start + 1);
if (host->io_base == NULL) {
printk(KERN_ERR "at91_nand: ioremap failed\n");
kfree(host);
@@ -119,6 +398,7 @@ static int __init at91_nand_probe(struct platform_device *pdev)
mtd = &host->mtd;
nand_chip = &host->nand_chip;
host->board = pdev->dev.platform_data;
+ host->dev = &pdev->dev;
nand_chip->priv = host; /* link the private data structures */
mtd->priv = nand_chip;
@@ -132,7 +412,32 @@ static int __init at91_nand_probe(struct platform_device *pdev)
if (host->board->rdy_pin)
nand_chip->dev_ready = at91_nand_device_ready;
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!regs && hard_ecc) {
+ printk(KERN_ERR "at91_nand: can't get I/O resource "
+ "regs\nFalling back on software ECC\n");
+ }
+
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+ if (no_ecc)
+ nand_chip->ecc.mode = NAND_ECC_NONE;
+ if (hard_ecc && regs) {
+ host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
+ if (host->ecc == NULL) {
+ printk(KERN_ERR "at91_nand: ioremap failed\n");
+ res = -EIO;
+ goto err_ecc_ioremap;
+ }
+ nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+ nand_chip->ecc.calculate = at91_nand_calculate;
+ nand_chip->ecc.correct = at91_nand_correct;
+ nand_chip->ecc.hwctl = at91_nand_hwctl;
+ nand_chip->ecc.read_page = at91_nand_read_page;
+ nand_chip->ecc.bytes = 4;
+ nand_chip->ecc.prepad = 0;
+ nand_chip->ecc.postpad = 0;
+ }
+
nand_chip->chip_delay = 20; /* 20us command delay time */
if (host->board->bus_width_16) /* 16-bit bus width */
@@ -149,8 +454,53 @@ static int __init at91_nand_probe(struct platform_device *pdev)
}
}
- /* Scan to find existance of the device */
- if (nand_scan(mtd, 1)) {
+ /* first scan to find the device and get the page size */
+ if (nand_scan_ident(mtd, 1)) {
+ res = -ENXIO;
+ goto out;
+ }
+
+ if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) {
+ /* ECC is calculated for the whole page (1 step) */
+ nand_chip->ecc.size = mtd->writesize;
+
+ /* set ECC page size and oob layout */
+ switch (mtd->writesize) {
+ case 512:
+ nand_chip->ecc.layout = &at91_oobinfo_small;
+ nand_chip->ecc.read_oob = at91_nand_read_oob_512;
+ nand_chip->ecc.write_oob = at91_nand_write_oob_512;
+ ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528);
+ break;
+ case 1024:
+ nand_chip->ecc.layout = &at91_oobinfo_large;
+ ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056);
+ break;
+ case 2048:
+ nand_chip->ecc.layout = &at91_oobinfo_large;
+ ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112);
+ break;
+ case 4096:
+ nand_chip->ecc.layout = &at91_oobinfo_large;
+ ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224);
+ break;
+ default:
+ /* page size not handled by HW ECC */
+ /* switching back to soft ECC */
+ nand_chip->ecc.mode = NAND_ECC_SOFT;
+ nand_chip->ecc.calculate = NULL;
+ nand_chip->ecc.correct = NULL;
+ nand_chip->ecc.hwctl = NULL;
+ nand_chip->ecc.read_page = NULL;
+ nand_chip->ecc.postpad = 0;
+ nand_chip->ecc.prepad = 0;
+ nand_chip->ecc.bytes = 0;
+ break;
+ }
+ }
+
+ /* second phase scan */
+ if (nand_scan_tail(mtd)) {
res = -ENXIO;
goto out;
}
@@ -179,9 +529,15 @@ static int __init at91_nand_probe(struct platform_device *pdev)
if (!res)
return res;
+#ifdef CONFIG_MTD_PARTITIONS
release:
+#endif
nand_release(mtd);
+
out:
+ iounmap(host->ecc);
+
+err_ecc_ioremap:
at91_nand_disable(host);
platform_set_drvdata(pdev, NULL);
iounmap(host->io_base);
@@ -202,6 +558,7 @@ static int __devexit at91_nand_remove(struct platform_device *pdev)
at91_nand_disable(host);
iounmap(host->io_base);
+ iounmap(host->ecc);
kfree(host);
return 0;
@@ -233,4 +590,5 @@ module_exit(at91_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200");
+MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9");
+MODULE_ALIAS("platform:at91_nand");
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 747042ab094a..e87a57297328 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -1,6 +1,6 @@
/* linux/drivers/mtd/nand/bf5xx_nand.c
*
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2008 Analog Devices Inc.
* http://blackfin.uclinux.org/
* Bryan Wu <bryan.wu@analog.com>
*
@@ -74,7 +74,7 @@ static int hardware_ecc = 1;
static int hardware_ecc;
#endif
-static unsigned short bfin_nfc_pin_req[] =
+static const unsigned short bfin_nfc_pin_req[] =
{P_NAND_CE,
P_NAND_RB,
P_NAND_D0,
@@ -581,12 +581,6 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
bfin_write_NFC_IRQSTAT(val);
SSYNC();
- if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
- return -EFAULT;
- }
-
/* DMA initialization */
if (bf5xx_nand_dma_init(info))
err = -ENXIO;
@@ -654,6 +648,12 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "(%p)\n", pdev);
+ if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ return -EFAULT;
+ }
+
if (!plat) {
dev_err(&pdev->dev, "no platform specific information\n");
goto exit_error;
@@ -803,3 +803,4 @@ module_exit(bf5xx_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 8dab69657b19..3370a800fd36 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -279,7 +279,7 @@ static int is_geode(void)
#ifdef CONFIG_MTD_PARTITIONS
-const char *part_probes[] = { "cmdlinepart", NULL };
+static const char *part_probes[] = { "cmdlinepart", NULL };
#endif
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 378b7aa63812..4b69aacdf5ca 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -184,11 +184,11 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
in_be32(&lbc->fbar), in_be32(&lbc->fpar),
in_be32(&lbc->fbcr), priv->bank);
+ ctrl->irq_status = 0;
/* execute special operation */
out_be32(&lbc->lsor, priv->bank);
/* wait for FCM complete flag or timeout */
- ctrl->irq_status = 0;
wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
FCM_TIMEOUT_MSECS * HZ/1000);
ctrl->status = ctrl->irq_status;
@@ -346,19 +346,20 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
ctrl->column = column;
ctrl->oob = 0;
- fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
- (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
-
if (priv->page_size) {
+ fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) |
+ (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT);
+
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CA << FIR_OP1_SHIFT) |
(FIR_OP_PA << FIR_OP2_SHIFT) |
(FIR_OP_WB << FIR_OP3_SHIFT) |
(FIR_OP_CW1 << FIR_OP4_SHIFT));
-
- fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
} else {
+ fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
+ (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+
out_be32(&lbc->fir,
(FIR_OP_CW0 << FIR_OP0_SHIFT) |
(FIR_OP_CM2 << FIR_OP1_SHIFT) |
@@ -480,7 +481,7 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
unsigned int bufsize = mtd->writesize + mtd->oobsize;
- if (len < 0) {
+ if (len <= 0) {
dev_err(ctrl->dev, "write_buf of %d bytes", len);
ctrl->status = 0;
return;
@@ -495,6 +496,15 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
}
memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+ /*
+ * This is workaround for the weird elbc hangs during nand write,
+ * Scott Wood says: "...perhaps difference in how long it takes a
+ * write to make it through the localbus compared to a write to IMMR
+ * is causing problems, and sync isn't helping for some reason."
+ * Reading back the last byte helps though.
+ */
+ in_8(&ctrl->addr[ctrl->index] + len - 1);
+
ctrl->index += len;
}
@@ -666,7 +676,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
/* adjust Option Register and ECC to match Flash page size */
if (mtd->writesize == 512) {
priv->page_size = 0;
- clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS);
+ clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
} else if (mtd->writesize == 2048) {
priv->page_size = 1;
setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
@@ -687,11 +697,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
return -1;
}
- /* The default u-boot configuration on MPC8313ERDB causes errors;
- * more delay is needed. This should be safe for other boards
- * as well.
- */
- setbits32(&lbc->bank[priv->bank].or, 0x70);
return 0;
}
@@ -779,6 +784,8 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
nand_release(&priv->mtd);
+ kfree(priv->mtd.name);
+
if (priv->vbase)
iounmap(priv->vbase);
@@ -839,6 +846,12 @@ static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
goto err;
}
+ priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", res.start);
+ if (!priv->mtd.name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
ret = fsl_elbc_chip_init(priv);
if (ret)
goto err;
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
new file mode 100644
index 000000000000..1ebfd87f00b4
--- /dev/null
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -0,0 +1,291 @@
+/*
+ * Freescale UPM NAND driver.
+ *
+ * Copyright © 2007-2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <asm/fsl_lbc.h>
+
+struct fsl_upm_nand {
+ struct device *dev;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int last_ctrl;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
+
+ struct fsl_upm upm;
+ uint8_t upm_addr_offset;
+ uint8_t upm_cmd_offset;
+ void __iomem *io_base;
+ int rnb_gpio;
+ const uint32_t *wait_pattern;
+ const uint32_t *wait_write;
+ int chip_delay;
+};
+
+#define to_fsl_upm_nand(mtd) container_of(mtd, struct fsl_upm_nand, mtd)
+
+static int fun_chip_ready(struct mtd_info *mtd)
+{
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+
+ if (gpio_get_value(fun->rnb_gpio))
+ return 1;
+
+ dev_vdbg(fun->dev, "busy\n");
+ return 0;
+}
+
+static void fun_wait_rnb(struct fsl_upm_nand *fun)
+{
+ int cnt = 1000000;
+
+ if (fun->rnb_gpio >= 0) {
+ while (--cnt && !fun_chip_ready(&fun->mtd))
+ cpu_relax();
+ }
+
+ if (!cnt)
+ dev_err(fun->dev, "tired waiting for RNB\n");
+}
+
+static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+
+ if (!(ctrl & fun->last_ctrl)) {
+ fsl_upm_end_pattern(&fun->upm);
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
+ }
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_ALE)
+ fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
+ else if (ctrl & NAND_CLE)
+ fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
+ }
+
+ fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd);
+
+ if (fun->wait_pattern)
+ fun_wait_rnb(fun);
+}
+
+static uint8_t fun_read_byte(struct mtd_info *mtd)
+{
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+
+ return in_8(fun->chip.IO_ADDR_R);
+}
+
+static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ int i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = in_8(fun->chip.IO_ADDR_R);
+}
+
+static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ out_8(fun->chip.IO_ADDR_W, buf[i]);
+ if (fun->wait_write)
+ fun_wait_rnb(fun);
+ }
+}
+
+static int __devinit fun_chip_init(struct fsl_upm_nand *fun)
+{
+ int ret;
+#ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_types[] = { "cmdlinepart", NULL, };
+#endif
+
+ fun->chip.IO_ADDR_R = fun->io_base;
+ fun->chip.IO_ADDR_W = fun->io_base;
+ fun->chip.cmd_ctrl = fun_cmd_ctrl;
+ fun->chip.chip_delay = fun->chip_delay;
+ fun->chip.read_byte = fun_read_byte;
+ fun->chip.read_buf = fun_read_buf;
+ fun->chip.write_buf = fun_write_buf;
+ fun->chip.ecc.mode = NAND_ECC_SOFT;
+
+ if (fun->rnb_gpio >= 0)
+ fun->chip.dev_ready = fun_chip_ready;
+
+ fun->mtd.priv = &fun->chip;
+ fun->mtd.owner = THIS_MODULE;
+
+ ret = nand_scan(&fun->mtd, 1);
+ if (ret)
+ return ret;
+
+ fun->mtd.name = fun->dev->bus_id;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0);
+ if (ret > 0)
+ return add_mtd_partitions(&fun->mtd, fun->parts, ret);
+#endif
+ return add_mtd_device(&fun->mtd);
+}
+
+static int __devinit fun_probe(struct of_device *ofdev,
+ const struct of_device_id *ofid)
+{
+ struct fsl_upm_nand *fun;
+ struct resource io_res;
+ const uint32_t *prop;
+ int ret;
+ int size;
+
+ fun = kzalloc(sizeof(*fun), GFP_KERNEL);
+ if (!fun)
+ return -ENOMEM;
+
+ ret = of_address_to_resource(ofdev->node, 0, &io_res);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't get IO base\n");
+ goto err1;
+ }
+
+ ret = fsl_upm_find(io_res.start, &fun->upm);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't find UPM\n");
+ goto err1;
+ }
+
+ prop = of_get_property(ofdev->node, "fsl,upm-addr-offset", &size);
+ if (!prop || size != sizeof(uint32_t)) {
+ dev_err(&ofdev->dev, "can't get UPM address offset\n");
+ ret = -EINVAL;
+ goto err2;
+ }
+ fun->upm_addr_offset = *prop;
+
+ prop = of_get_property(ofdev->node, "fsl,upm-cmd-offset", &size);
+ if (!prop || size != sizeof(uint32_t)) {
+ dev_err(&ofdev->dev, "can't get UPM command offset\n");
+ ret = -EINVAL;
+ goto err2;
+ }
+ fun->upm_cmd_offset = *prop;
+
+ fun->rnb_gpio = of_get_gpio(ofdev->node, 0);
+ if (fun->rnb_gpio >= 0) {
+ ret = gpio_request(fun->rnb_gpio, ofdev->dev.bus_id);
+ if (ret) {
+ dev_err(&ofdev->dev, "can't request RNB gpio\n");
+ goto err2;
+ }
+ gpio_direction_input(fun->rnb_gpio);
+ } else if (fun->rnb_gpio == -EINVAL) {
+ dev_err(&ofdev->dev, "specified RNB gpio is invalid\n");
+ goto err2;
+ }
+
+ fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
+ io_res.end - io_res.start + 1);
+ if (!fun->io_base) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ fun->dev = &ofdev->dev;
+ fun->last_ctrl = NAND_CLE;
+ fun->wait_pattern = of_get_property(ofdev->node, "fsl,wait-pattern",
+ NULL);
+ fun->wait_write = of_get_property(ofdev->node, "fsl,wait-write", NULL);
+
+ prop = of_get_property(ofdev->node, "chip-delay", NULL);
+ if (prop)
+ fun->chip_delay = *prop;
+ else
+ fun->chip_delay = 50;
+
+ ret = fun_chip_init(fun);
+ if (ret)
+ goto err2;
+
+ dev_set_drvdata(&ofdev->dev, fun);
+
+ return 0;
+err2:
+ if (fun->rnb_gpio >= 0)
+ gpio_free(fun->rnb_gpio);
+err1:
+ kfree(fun);
+
+ return ret;
+}
+
+static int __devexit fun_remove(struct of_device *ofdev)
+{
+ struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
+
+ nand_release(&fun->mtd);
+
+ if (fun->rnb_gpio >= 0)
+ gpio_free(fun->rnb_gpio);
+
+ kfree(fun);
+
+ return 0;
+}
+
+static struct of_device_id of_fun_match[] = {
+ { .compatible = "fsl,upm-nand" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_fun_match);
+
+static struct of_platform_driver of_fun_driver = {
+ .name = "fsl,upm-nand",
+ .match_table = of_fun_match,
+ .probe = fun_probe,
+ .remove = __devexit_p(fun_remove),
+};
+
+static int __init fun_module_init(void)
+{
+ return of_register_platform_driver(&of_fun_driver);
+}
+module_init(fun_module_init);
+
+static void __exit fun_module_exit(void)
+{
+ of_unregister_platform_driver(&of_fun_driver);
+}
+module_exit(fun_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
+ "LocalBus User-Programmable Machine");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 7acb1a0e7409..ba1bdf787323 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2229,6 +2229,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
+ int tmp_id, tmp_manf;
/* Select the device */
chip->select_chip(mtd, 0);
@@ -2240,6 +2241,26 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
+ /* Try again to make sure, as some systems the bus-hold or other
+ * interface concerns can cause random data which looks like a
+ * possibly credible NAND flash to appear. If the two results do
+ * not match, ignore the device completely.
+ */
+
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+ /* Read manufacturer and device IDs */
+
+ tmp_manf = chip->read_byte(mtd);
+ tmp_id = chip->read_byte(mtd);
+
+ if (tmp_manf != *maf_id || tmp_id != dev_id) {
+ printk(KERN_INFO "%s: second ID read did not match "
+ "%02x,%02x against %02x,%02x\n", __func__,
+ *maf_id, dev_id, tmp_manf, tmp_id);
+ return ERR_PTR(-ENODEV);
+ }
+
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 1c0e89f00e8d..955959eb02d4 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -317,3 +317,5 @@ module_exit(ndfc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
MODULE_DESCRIPTION("Platform driver for NDFC");
+MODULE_ALIAS("platform:ndfc-chip");
+MODULE_ALIAS("platform:ndfc-nand");
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index ec5ad28b237e..59e05a1c50cf 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -169,3 +169,4 @@ module_exit(orion_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tzachi Perelstein");
MODULE_DESCRIPTION("NAND glue for Orion platforms");
+MODULE_ALIAS("platform:orion_nand");
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index f6d5c2adc4fd..f674c5427b17 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -54,6 +54,7 @@ static int __init plat_nand_probe(struct platform_device *pdev)
data->chip.priv = &data;
data->mtd.priv = &data->chip;
data->mtd.owner = THIS_MODULE;
+ data->mtd.name = pdev->dev.bus_id;
data->chip.IO_ADDR_R = data->io_base;
data->chip.IO_ADDR_W = data->io_base;
@@ -150,3 +151,4 @@ module_exit(plat_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vitaly Wool");
MODULE_DESCRIPTION("Simple generic NAND driver");
+MODULE_ALIAS("platform:gen_nand");
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
new file mode 100644
index 000000000000..fceb468ccdec
--- /dev/null
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -0,0 +1,1249 @@
+/*
+ * drivers/mtd/nand/pxa3xx_nand.c
+ *
+ * Copyright © 2005 Intel Corporation
+ * Copyright © 2006 Marvell International 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.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/dma.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa3xx_nand.h>
+
+#define CHIP_DELAY_TIMEOUT (2 * HZ/10)
+
+/* registers and bit definitions */
+#define NDCR (0x00) /* Control register */
+#define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */
+#define NDTR1CS0 (0x0C) /* Timing Parameter 1 for CS0 */
+#define NDSR (0x14) /* Status Register */
+#define NDPCR (0x18) /* Page Count Register */
+#define NDBDR0 (0x1C) /* Bad Block Register 0 */
+#define NDBDR1 (0x20) /* Bad Block Register 1 */
+#define NDDB (0x40) /* Data Buffer */
+#define NDCB0 (0x48) /* Command Buffer0 */
+#define NDCB1 (0x4C) /* Command Buffer1 */
+#define NDCB2 (0x50) /* Command Buffer2 */
+
+#define NDCR_SPARE_EN (0x1 << 31)
+#define NDCR_ECC_EN (0x1 << 30)
+#define NDCR_DMA_EN (0x1 << 29)
+#define NDCR_ND_RUN (0x1 << 28)
+#define NDCR_DWIDTH_C (0x1 << 27)
+#define NDCR_DWIDTH_M (0x1 << 26)
+#define NDCR_PAGE_SZ (0x1 << 24)
+#define NDCR_NCSX (0x1 << 23)
+#define NDCR_ND_MODE (0x3 << 21)
+#define NDCR_NAND_MODE (0x0)
+#define NDCR_CLR_PG_CNT (0x1 << 20)
+#define NDCR_CLR_ECC (0x1 << 19)
+#define NDCR_RD_ID_CNT_MASK (0x7 << 16)
+#define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK)
+
+#define NDCR_RA_START (0x1 << 15)
+#define NDCR_PG_PER_BLK (0x1 << 14)
+#define NDCR_ND_ARB_EN (0x1 << 12)
+
+#define NDSR_MASK (0xfff)
+#define NDSR_RDY (0x1 << 11)
+#define NDSR_CS0_PAGED (0x1 << 10)
+#define NDSR_CS1_PAGED (0x1 << 9)
+#define NDSR_CS0_CMDD (0x1 << 8)
+#define NDSR_CS1_CMDD (0x1 << 7)
+#define NDSR_CS0_BBD (0x1 << 6)
+#define NDSR_CS1_BBD (0x1 << 5)
+#define NDSR_DBERR (0x1 << 4)
+#define NDSR_SBERR (0x1 << 3)
+#define NDSR_WRDREQ (0x1 << 2)
+#define NDSR_RDDREQ (0x1 << 1)
+#define NDSR_WRCMDREQ (0x1)
+
+#define NDCB0_AUTO_RS (0x1 << 25)
+#define NDCB0_CSEL (0x1 << 24)
+#define NDCB0_CMD_TYPE_MASK (0x7 << 21)
+#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK)
+#define NDCB0_NC (0x1 << 20)
+#define NDCB0_DBC (0x1 << 19)
+#define NDCB0_ADDR_CYC_MASK (0x7 << 16)
+#define NDCB0_ADDR_CYC(x) (((x) << 16) & NDCB0_ADDR_CYC_MASK)
+#define NDCB0_CMD2_MASK (0xff << 8)
+#define NDCB0_CMD1_MASK (0xff)
+#define NDCB0_ADDR_CYC_SHIFT (16)
+
+/* dma-able I/O address for the NAND data and commands */
+#define NDCB0_DMA_ADDR (0x43100048)
+#define NDDB_DMA_ADDR (0x43100040)
+
+/* macros for registers read/write */
+#define nand_writel(info, off, val) \
+ __raw_writel((val), (info)->mmio_base + (off))
+
+#define nand_readl(info, off) \
+ __raw_readl((info)->mmio_base + (off))
+
+/* error code and state */
+enum {
+ ERR_NONE = 0,
+ ERR_DMABUSERR = -1,
+ ERR_SENDCMD = -2,
+ ERR_DBERR = -3,
+ ERR_BBERR = -4,
+};
+
+enum {
+ STATE_READY = 0,
+ STATE_CMD_HANDLE,
+ STATE_DMA_READING,
+ STATE_DMA_WRITING,
+ STATE_DMA_DONE,
+ STATE_PIO_READING,
+ STATE_PIO_WRITING,
+};
+
+struct pxa3xx_nand_timing {
+ unsigned int tCH; /* Enable signal hold time */
+ unsigned int tCS; /* Enable signal setup time */
+ unsigned int tWH; /* ND_nWE high duration */
+ unsigned int tWP; /* ND_nWE pulse time */
+ unsigned int tRH; /* ND_nRE high duration */
+ unsigned int tRP; /* ND_nRE pulse width */
+ unsigned int tR; /* ND_nWE high to ND_nRE low for read */
+ unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */
+ unsigned int tAR; /* ND_ALE low to ND_nRE low delay */
+};
+
+struct pxa3xx_nand_cmdset {
+ uint16_t read1;
+ uint16_t read2;
+ uint16_t program;
+ uint16_t read_status;
+ uint16_t read_id;
+ uint16_t erase;
+ uint16_t reset;
+ uint16_t lock;
+ uint16_t unlock;
+ uint16_t lock_status;
+};
+
+struct pxa3xx_nand_flash {
+ struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
+ struct pxa3xx_nand_cmdset *cmdset;
+
+ uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
+ uint32_t page_size; /* Page size in bytes (PAGE_SZ) */
+ uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */
+ uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */
+ uint32_t num_blocks; /* Number of physical blocks in Flash */
+ uint32_t chip_id;
+
+ /* NOTE: these are automatically calculated, do not define */
+ size_t oob_size;
+ size_t read_id_bytes;
+
+ unsigned int col_addr_cycles;
+ unsigned int row_addr_cycles;
+};
+
+struct pxa3xx_nand_info {
+ struct nand_chip nand_chip;
+
+ struct platform_device *pdev;
+ struct pxa3xx_nand_flash *flash_info;
+
+ struct clk *clk;
+ void __iomem *mmio_base;
+
+ unsigned int buf_start;
+ unsigned int buf_count;
+
+ /* DMA information */
+ int drcmr_dat;
+ int drcmr_cmd;
+
+ unsigned char *data_buff;
+ dma_addr_t data_buff_phys;
+ size_t data_buff_size;
+ int data_dma_ch;
+ struct pxa_dma_desc *data_desc;
+ dma_addr_t data_desc_addr;
+
+ uint32_t reg_ndcr;
+
+ /* saved column/page_addr during CMD_SEQIN */
+ int seqin_column;
+ int seqin_page_addr;
+
+ /* relate to the command */
+ unsigned int state;
+
+ int use_ecc; /* use HW ECC ? */
+ int use_dma; /* use DMA ? */
+
+ size_t data_size; /* data size in FIFO */
+ int retcode;
+ struct completion cmd_complete;
+
+ /* generated NDCBx register values */
+ uint32_t ndcb0;
+ uint32_t ndcb1;
+ uint32_t ndcb2;
+};
+
+static int use_dma = 1;
+module_param(use_dma, bool, 0444);
+MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");
+
+static struct pxa3xx_nand_cmdset smallpage_cmdset = {
+ .read1 = 0x0000,
+ .read2 = 0x0050,
+ .program = 0x1080,
+ .read_status = 0x0070,
+ .read_id = 0x0090,
+ .erase = 0xD060,
+ .reset = 0x00FF,
+ .lock = 0x002A,
+ .unlock = 0x2423,
+ .lock_status = 0x007A,
+};
+
+static struct pxa3xx_nand_cmdset largepage_cmdset = {
+ .read1 = 0x3000,
+ .read2 = 0x0050,
+ .program = 0x1080,
+ .read_status = 0x0070,
+ .read_id = 0x0090,
+ .erase = 0xD060,
+ .reset = 0x00FF,
+ .lock = 0x002A,
+ .unlock = 0x2423,
+ .lock_status = 0x007A,
+};
+
+static struct pxa3xx_nand_timing samsung512MbX16_timing = {
+ .tCH = 10,
+ .tCS = 0,
+ .tWH = 20,
+ .tWP = 40,
+ .tRH = 30,
+ .tRP = 40,
+ .tR = 11123,
+ .tWHR = 110,
+ .tAR = 10,
+};
+
+static struct pxa3xx_nand_flash samsung512MbX16 = {
+ .timing = &samsung512MbX16_timing,
+ .cmdset = &smallpage_cmdset,
+ .page_per_block = 32,
+ .page_size = 512,
+ .flash_width = 16,
+ .dfc_width = 16,
+ .num_blocks = 4096,
+ .chip_id = 0x46ec,
+};
+
+static struct pxa3xx_nand_timing micron_timing = {
+ .tCH = 10,
+ .tCS = 25,
+ .tWH = 15,
+ .tWP = 25,
+ .tRH = 15,
+ .tRP = 25,
+ .tR = 25000,
+ .tWHR = 60,
+ .tAR = 10,
+};
+
+static struct pxa3xx_nand_flash micron1GbX8 = {
+ .timing = &micron_timing,
+ .cmdset = &largepage_cmdset,
+ .page_per_block = 64,
+ .page_size = 2048,
+ .flash_width = 8,
+ .dfc_width = 8,
+ .num_blocks = 1024,
+ .chip_id = 0xa12c,
+};
+
+static struct pxa3xx_nand_flash micron1GbX16 = {
+ .timing = &micron_timing,
+ .cmdset = &largepage_cmdset,
+ .page_per_block = 64,
+ .page_size = 2048,
+ .flash_width = 16,
+ .dfc_width = 16,
+ .num_blocks = 1024,
+ .chip_id = 0xb12c,
+};
+
+static struct pxa3xx_nand_flash *builtin_flash_types[] = {
+ &samsung512MbX16,
+ &micron1GbX8,
+ &micron1GbX16,
+};
+
+#define NDTR0_tCH(c) (min((c), 7) << 19)
+#define NDTR0_tCS(c) (min((c), 7) << 16)
+#define NDTR0_tWH(c) (min((c), 7) << 11)
+#define NDTR0_tWP(c) (min((c), 7) << 8)
+#define NDTR0_tRH(c) (min((c), 7) << 3)
+#define NDTR0_tRP(c) (min((c), 7) << 0)
+
+#define NDTR1_tR(c) (min((c), 65535) << 16)
+#define NDTR1_tWHR(c) (min((c), 15) << 4)
+#define NDTR1_tAR(c) (min((c), 15) << 0)
+
+/* convert nano-seconds to nand flash controller clock cycles */
+#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1)
+
+static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
+ struct pxa3xx_nand_timing *t)
+{
+ unsigned long nand_clk = clk_get_rate(info->clk);
+ uint32_t ndtr0, ndtr1;
+
+ ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
+ NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
+ NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
+ NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |
+ NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |
+ NDTR0_tRP(ns2cycle(t->tRP, nand_clk));
+
+ ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |
+ NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
+ NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
+
+ nand_writel(info, NDTR0CS0, ndtr0);
+ nand_writel(info, NDTR1CS0, ndtr1);
+}
+
+#define WAIT_EVENT_TIMEOUT 10
+
+static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event)
+{
+ int timeout = WAIT_EVENT_TIMEOUT;
+ uint32_t ndsr;
+
+ while (timeout--) {
+ ndsr = nand_readl(info, NDSR) & NDSR_MASK;
+ if (ndsr & event) {
+ nand_writel(info, NDSR, ndsr);
+ return 0;
+ }
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
+ uint16_t cmd, int column, int page_addr)
+{
+ struct pxa3xx_nand_flash *f = info->flash_info;
+ struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+
+ /* calculate data size */
+ switch (f->page_size) {
+ case 2048:
+ info->data_size = (info->use_ecc) ? 2088 : 2112;
+ break;
+ case 512:
+ info->data_size = (info->use_ecc) ? 520 : 528;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* generate values for NDCBx registers */
+ info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+ info->ndcb1 = 0;
+ info->ndcb2 = 0;
+ info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles);
+
+ if (f->col_addr_cycles == 2) {
+ /* large block, 2 cycles for column address
+ * row address starts from 3rd cycle
+ */
+ info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
+ if (f->row_addr_cycles == 3)
+ info->ndcb2 = (page_addr >> 16) & 0xff;
+ } else
+ /* small block, 1 cycles for column address
+ * row address starts from 2nd cycle
+ */
+ info->ndcb1 = (page_addr << 8) | (column & 0xff);
+
+ if (cmd == cmdset->program)
+ info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
+
+ return 0;
+}
+
+static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
+ uint16_t cmd, int page_addr)
+{
+ info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+ info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
+ info->ndcb1 = page_addr;
+ info->ndcb2 = 0;
+ return 0;
+}
+
+static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
+{
+ struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;
+
+ info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
+ info->ndcb1 = 0;
+ info->ndcb2 = 0;
+
+ if (cmd == cmdset->read_id) {
+ info->ndcb0 |= NDCB0_CMD_TYPE(3);
+ info->data_size = 8;
+ } else if (cmd == cmdset->read_status) {
+ info->ndcb0 |= NDCB0_CMD_TYPE(4);
+ info->data_size = 8;
+ } else if (cmd == cmdset->reset || cmd == cmdset->lock ||
+ cmd == cmdset->unlock) {
+ info->ndcb0 |= NDCB0_CMD_TYPE(5);
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+{
+ uint32_t ndcr;
+
+ ndcr = nand_readl(info, NDCR);
+ nand_writel(info, NDCR, ndcr & ~int_mask);
+}
+
+static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+{
+ uint32_t ndcr;
+
+ ndcr = nand_readl(info, NDCR);
+ nand_writel(info, NDCR, ndcr | int_mask);
+}
+
+/* NOTE: it is a must to set ND_RUN firstly, then write command buffer
+ * otherwise, it does not work
+ */
+static int write_cmd(struct pxa3xx_nand_info *info)
+{
+ uint32_t ndcr;
+
+ /* clear status bits and run */
+ nand_writel(info, NDSR, NDSR_MASK);
+
+ ndcr = info->reg_ndcr;
+
+ ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
+ ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
+ ndcr |= NDCR_ND_RUN;
+
+ nand_writel(info, NDCR, ndcr);
+
+ if (wait_for_event(info, NDSR_WRCMDREQ)) {
+ printk(KERN_ERR "timed out writing command\n");
+ return -ETIMEDOUT;
+ }
+
+ nand_writel(info, NDCB0, info->ndcb0);
+ nand_writel(info, NDCB0, info->ndcb1);
+ nand_writel(info, NDCB0, info->ndcb2);
+ return 0;
+}
+
+static int handle_data_pio(struct pxa3xx_nand_info *info)
+{
+ int ret, timeout = CHIP_DELAY_TIMEOUT;
+
+ switch (info->state) {
+ case STATE_PIO_WRITING:
+ __raw_writesl(info->mmio_base + NDDB, info->data_buff,
+ info->data_size << 2);
+
+ enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+
+ ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
+ if (!ret) {
+ printk(KERN_ERR "program command time out\n");
+ return -1;
+ }
+ break;
+ case STATE_PIO_READING:
+ __raw_readsl(info->mmio_base + NDDB, info->data_buff,
+ info->data_size << 2);
+ break;
+ default:
+ printk(KERN_ERR "%s: invalid state %d\n", __func__,
+ info->state);
+ return -EINVAL;
+ }
+
+ info->state = STATE_READY;
+ return 0;
+}
+
+static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out)
+{
+ struct pxa_dma_desc *desc = info->data_desc;
+ int dma_len = ALIGN(info->data_size, 32);
+
+ desc->ddadr = DDADR_STOP;
+ desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
+
+ if (dir_out) {
+ desc->dsadr = info->data_buff_phys;
+ desc->dtadr = NDDB_DMA_ADDR;
+ desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
+ } else {
+ desc->dtadr = info->data_buff_phys;
+ desc->dsadr = NDDB_DMA_ADDR;
+ desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
+ }
+
+ DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch;
+ DDADR(info->data_dma_ch) = info->data_desc_addr;
+ DCSR(info->data_dma_ch) |= DCSR_RUN;
+}
+
+static void pxa3xx_nand_data_dma_irq(int channel, void *data)
+{
+ struct pxa3xx_nand_info *info = data;
+ uint32_t dcsr;
+
+ dcsr = DCSR(channel);
+ DCSR(channel) = dcsr;
+
+ if (dcsr & DCSR_BUSERR) {
+ info->retcode = ERR_DMABUSERR;
+ complete(&info->cmd_complete);
+ }
+
+ if (info->state == STATE_DMA_WRITING) {
+ info->state = STATE_DMA_DONE;
+ enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+ } else {
+ info->state = STATE_READY;
+ complete(&info->cmd_complete);
+ }
+}
+
+static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+{
+ struct pxa3xx_nand_info *info = devid;
+ unsigned int status;
+
+ status = nand_readl(info, NDSR);
+
+ if (status & (NDSR_RDDREQ | NDSR_DBERR)) {
+ if (status & NDSR_DBERR)
+ info->retcode = ERR_DBERR;
+
+ disable_int(info, NDSR_RDDREQ | NDSR_DBERR);
+
+ if (info->use_dma) {
+ info->state = STATE_DMA_READING;
+ start_data_dma(info, 0);
+ } else {
+ info->state = STATE_PIO_READING;
+ complete(&info->cmd_complete);
+ }
+ } else if (status & NDSR_WRDREQ) {
+ disable_int(info, NDSR_WRDREQ);
+ if (info->use_dma) {
+ info->state = STATE_DMA_WRITING;
+ start_data_dma(info, 1);
+ } else {
+ info->state = STATE_PIO_WRITING;
+ complete(&info->cmd_complete);
+ }
+ } else if (status & (NDSR_CS0_BBD | NDSR_CS0_CMDD)) {
+ if (status & NDSR_CS0_BBD)
+ info->retcode = ERR_BBERR;
+
+ disable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+ info->state = STATE_READY;
+ complete(&info->cmd_complete);
+ }
+ nand_writel(info, NDSR, status);
+ return IRQ_HANDLED;
+}
+
+static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event)
+{
+ uint32_t ndcr;
+ int ret, timeout = CHIP_DELAY_TIMEOUT;
+
+ if (write_cmd(info)) {
+ info->retcode = ERR_SENDCMD;
+ goto fail_stop;
+ }
+
+ info->state = STATE_CMD_HANDLE;
+
+ enable_int(info, event);
+
+ ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
+ if (!ret) {
+ printk(KERN_ERR "command execution timed out\n");
+ info->retcode = ERR_SENDCMD;
+ goto fail_stop;
+ }
+
+ if (info->use_dma == 0 && info->data_size > 0)
+ if (handle_data_pio(info))
+ goto fail_stop;
+
+ return 0;
+
+fail_stop:
+ ndcr = nand_readl(info, NDCR);
+ nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+ udelay(10);
+ return -ETIMEDOUT;
+}
+
+static int pxa3xx_nand_dev_ready(struct mtd_info *mtd)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0;
+}
+
+static inline int is_buf_blank(uint8_t *buf, size_t len)
+{
+ for (; len > 0; len--)
+ if (*buf++ != 0xff)
+ return 0;
+ return 1;
+}
+
+static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ struct pxa3xx_nand_flash *flash_info = info->flash_info;
+ struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;
+ int ret;
+
+ info->use_dma = (use_dma) ? 1 : 0;
+ info->use_ecc = 0;
+ info->data_size = 0;
+ info->state = STATE_READY;
+
+ init_completion(&info->cmd_complete);
+
+ switch (command) {
+ case NAND_CMD_READOOB:
+ /* disable HW ECC to get all the OOB data */
+ info->buf_count = mtd->writesize + mtd->oobsize;
+ info->buf_start = mtd->writesize + column;
+
+ if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
+ break;
+
+ pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
+
+ /* We only are OOB, so if the data has error, does not matter */
+ if (info->retcode == ERR_DBERR)
+ info->retcode = ERR_NONE;
+ break;
+
+ case NAND_CMD_READ0:
+ info->use_ecc = 1;
+ info->retcode = ERR_NONE;
+ info->buf_start = column;
+ info->buf_count = mtd->writesize + mtd->oobsize;
+ memset(info->data_buff, 0xFF, info->buf_count);
+
+ if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
+ break;
+
+ pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);
+
+ if (info->retcode == ERR_DBERR) {
+ /* for blank page (all 0xff), HW will calculate its ECC as
+ * 0, which is different from the ECC information within
+ * OOB, ignore such double bit errors
+ */
+ if (is_buf_blank(info->data_buff, mtd->writesize))
+ info->retcode = ERR_NONE;
+ }
+ break;
+ case NAND_CMD_SEQIN:
+ info->buf_start = column;
+ info->buf_count = mtd->writesize + mtd->oobsize;
+ memset(info->data_buff, 0xff, info->buf_count);
+
+ /* save column/page_addr for next CMD_PAGEPROG */
+ info->seqin_column = column;
+ info->seqin_page_addr = page_addr;
+ break;
+ case NAND_CMD_PAGEPROG:
+ info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
+
+ if (prepare_read_prog_cmd(info, cmdset->program,
+ info->seqin_column, info->seqin_page_addr))
+ break;
+
+ pxa3xx_nand_do_cmd(info, NDSR_WRDREQ);
+ break;
+ case NAND_CMD_ERASE1:
+ if (prepare_erase_cmd(info, cmdset->erase, page_addr))
+ break;
+
+ pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+ break;
+ case NAND_CMD_ERASE2:
+ break;
+ case NAND_CMD_READID:
+ case NAND_CMD_STATUS:
+ info->use_dma = 0; /* force PIO read */
+ info->buf_start = 0;
+ info->buf_count = (command == NAND_CMD_READID) ?
+ flash_info->read_id_bytes : 1;
+
+ if (prepare_other_cmd(info, (command == NAND_CMD_READID) ?
+ cmdset->read_id : cmdset->read_status))
+ break;
+
+ pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
+ break;
+ case NAND_CMD_RESET:
+ if (prepare_other_cmd(info, cmdset->reset))
+ break;
+
+ ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD);
+ if (ret == 0) {
+ int timeout = 2;
+ uint32_t ndcr;
+
+ while (timeout--) {
+ if (nand_readl(info, NDSR) & NDSR_RDY)
+ break;
+ msleep(10);
+ }
+
+ ndcr = nand_readl(info, NDCR);
+ nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+ }
+ break;
+ default:
+ printk(KERN_ERR "non-supported command.\n");
+ break;
+ }
+
+ if (info->retcode == ERR_DBERR) {
+ printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
+ info->retcode = ERR_NONE;
+ }
+}
+
+static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ char retval = 0xFF;
+
+ if (info->buf_start < info->buf_count)
+ /* Has just send a new command? */
+ retval = info->data_buff[info->buf_start++];
+
+ return retval;
+}
+
+static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ u16 retval = 0xFFFF;
+
+ if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
+ retval = *((u16 *)(info->data_buff+info->buf_start));
+ info->buf_start += 2;
+ }
+ return retval;
+}
+
+static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+ memcpy(buf, info->data_buff + info->buf_start, real_len);
+ info->buf_start += real_len;
+}
+
+static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
+
+ memcpy(info->data_buff + info->buf_start, buf, real_len);
+ info->buf_start += real_len;
+}
+
+static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ return 0;
+}
+
+static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+ return;
+}
+
+static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+
+ /* pxa3xx_nand_send_command has waited for command complete */
+ if (this->state == FL_WRITING || this->state == FL_ERASING) {
+ if (info->retcode == ERR_NONE)
+ return 0;
+ else {
+ /*
+ * any error make it return 0x01 which will tell
+ * the caller the erase and write fail
+ */
+ return 0x01;
+ }
+ }
+
+ return 0;
+}
+
+static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+ return;
+}
+
+static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd,
+ const uint8_t *dat, uint8_t *ecc_code)
+{
+ return 0;
+}
+
+static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd,
+ uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+ struct pxa3xx_nand_info *info = mtd->priv;
+ /*
+ * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we
+ * consider it as a ecc error which will tell the caller the
+ * read fail We have distinguish all the errors, but the
+ * nand_read_ecc only check this function return value
+ */
+ if (info->retcode != ERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+static int __readid(struct pxa3xx_nand_info *info, uint32_t *id)
+{
+ struct pxa3xx_nand_flash *f = info->flash_info;
+ struct pxa3xx_nand_cmdset *cmdset = f->cmdset;
+ uint32_t ndcr;
+ uint8_t id_buff[8];
+
+ if (prepare_other_cmd(info, cmdset->read_id)) {
+ printk(KERN_ERR "failed to prepare command\n");
+ return -EINVAL;
+ }
+
+ /* Send command */
+ if (write_cmd(info))
+ goto fail_timeout;
+
+ /* Wait for CMDDM(command done successfully) */
+ if (wait_for_event(info, NDSR_RDDREQ))
+ goto fail_timeout;
+
+ __raw_readsl(info->mmio_base + NDDB, id_buff, 2);
+ *id = id_buff[0] | (id_buff[1] << 8);
+ return 0;
+
+fail_timeout:
+ ndcr = nand_readl(info, NDCR);
+ nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
+ udelay(10);
+ return -ETIMEDOUT;
+}
+
+static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
+ struct pxa3xx_nand_flash *f)
+{
+ struct platform_device *pdev = info->pdev;
+ struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
+ uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
+
+ if (f->page_size != 2048 && f->page_size != 512)
+ return -EINVAL;
+
+ if (f->flash_width != 16 && f->flash_width != 8)
+ return -EINVAL;
+
+ /* calculate flash information */
+ f->oob_size = (f->page_size == 2048) ? 64 : 16;
+ f->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
+
+ /* calculate addressing information */
+ f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
+
+ if (f->num_blocks * f->page_per_block > 65536)
+ f->row_addr_cycles = 3;
+ else
+ f->row_addr_cycles = 2;
+
+ ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
+ ndcr |= (f->col_addr_cycles == 2) ? NDCR_RA_START : 0;
+ ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
+ ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
+ ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
+ ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
+
+ ndcr |= NDCR_RD_ID_CNT(f->read_id_bytes);
+ ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+
+ info->reg_ndcr = ndcr;
+
+ pxa3xx_nand_set_timing(info, f->timing);
+ info->flash_info = f;
+ return 0;
+}
+
+static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info)
+{
+ struct pxa3xx_nand_flash *f;
+ uint32_t id;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) {
+
+ f = builtin_flash_types[i];
+
+ if (pxa3xx_nand_config_flash(info, f))
+ continue;
+
+ if (__readid(info, &id))
+ continue;
+
+ if (id == f->chip_id)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+/* the maximum possible buffer size for large page with OOB data
+ * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
+ * data buffer and the DMA descriptor
+ */
+#define MAX_BUFF_SIZE PAGE_SIZE
+
+static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+{
+ struct platform_device *pdev = info->pdev;
+ int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
+
+ if (use_dma == 0) {
+ info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+ if (info->data_buff == NULL)
+ return -ENOMEM;
+ return 0;
+ }
+
+ info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
+ &info->data_buff_phys, GFP_KERNEL);
+ if (info->data_buff == NULL) {
+ dev_err(&pdev->dev, "failed to allocate dma buffer\n");
+ return -ENOMEM;
+ }
+
+ info->data_buff_size = MAX_BUFF_SIZE;
+ info->data_desc = (void *)info->data_buff + data_desc_offset;
+ info->data_desc_addr = info->data_buff_phys + data_desc_offset;
+
+ info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
+ pxa3xx_nand_data_dma_irq, info);
+ if (info->data_dma_ch < 0) {
+ dev_err(&pdev->dev, "failed to request data dma\n");
+ dma_free_coherent(&pdev->dev, info->data_buff_size,
+ info->data_buff, info->data_buff_phys);
+ return info->data_dma_ch;
+ }
+
+ return 0;
+}
+
+static struct nand_ecclayout hw_smallpage_ecclayout = {
+ .eccbytes = 6,
+ .eccpos = {8, 9, 10, 11, 12, 13 },
+ .oobfree = { {2, 6} }
+};
+
+static struct nand_ecclayout hw_largepage_ecclayout = {
+ .eccbytes = 24,
+ .eccpos = {
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63},
+ .oobfree = { {2, 38} }
+};
+
+static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
+ struct pxa3xx_nand_info *info)
+{
+ struct pxa3xx_nand_flash *f = info->flash_info;
+ struct nand_chip *this = &info->nand_chip;
+
+ this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0;
+
+ this->waitfunc = pxa3xx_nand_waitfunc;
+ this->select_chip = pxa3xx_nand_select_chip;
+ this->dev_ready = pxa3xx_nand_dev_ready;
+ this->cmdfunc = pxa3xx_nand_cmdfunc;
+ this->read_word = pxa3xx_nand_read_word;
+ this->read_byte = pxa3xx_nand_read_byte;
+ this->read_buf = pxa3xx_nand_read_buf;
+ this->write_buf = pxa3xx_nand_write_buf;
+ this->verify_buf = pxa3xx_nand_verify_buf;
+
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.hwctl = pxa3xx_nand_ecc_hwctl;
+ this->ecc.calculate = pxa3xx_nand_ecc_calculate;
+ this->ecc.correct = pxa3xx_nand_ecc_correct;
+ this->ecc.size = f->page_size;
+
+ if (f->page_size == 2048)
+ this->ecc.layout = &hw_largepage_ecclayout;
+ else
+ this->ecc.layout = &hw_smallpage_ecclayout;
+
+ this->chip_delay = 25;
+}
+
+static int pxa3xx_nand_probe(struct platform_device *pdev)
+{
+ struct pxa3xx_nand_platform_data *pdata;
+ struct pxa3xx_nand_info *info;
+ struct nand_chip *this;
+ struct mtd_info *mtd;
+ struct resource *r;
+ int ret = 0, irq;
+
+ pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -ENODEV;
+ }
+
+ mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),
+ GFP_KERNEL);
+ if (!mtd) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ info = (struct pxa3xx_nand_info *)(&mtd[1]);
+ info->pdev = pdev;
+
+ this = &info->nand_chip;
+ mtd->priv = info;
+
+ info->clk = clk_get(&pdev->dev, "NANDCLK");
+ if (IS_ERR(info->clk)) {
+ dev_err(&pdev->dev, "failed to get nand clock\n");
+ ret = PTR_ERR(info->clk);
+ goto fail_free_mtd;
+ }
+ clk_enable(info->clk);
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no resource defined for data DMA\n");
+ ret = -ENXIO;
+ goto fail_put_clk;
+ }
+ info->drcmr_dat = r->start;
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no resource defined for command DMA\n");
+ ret = -ENXIO;
+ goto fail_put_clk;
+ }
+ info->drcmr_cmd = r->start;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no IRQ resource defined\n");
+ ret = -ENXIO;
+ goto fail_put_clk;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no IO memory resource defined\n");
+ ret = -ENODEV;
+ goto fail_put_clk;
+ }
+
+ r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "failed to request memory resource\n");
+ ret = -EBUSY;
+ goto fail_put_clk;
+ }
+
+ info->mmio_base = ioremap(r->start, r->end - r->start + 1);
+ if (info->mmio_base == NULL) {
+ dev_err(&pdev->dev, "ioremap() failed\n");
+ ret = -ENODEV;
+ goto fail_free_res;
+ }
+
+ ret = pxa3xx_nand_init_buff(info);
+ if (ret)
+ goto fail_free_io;
+
+ ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,
+ pdev->name, info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ goto fail_free_buf;
+ }
+
+ ret = pxa3xx_nand_detect_flash(info);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to detect flash\n");
+ ret = -ENODEV;
+ goto fail_free_irq;
+ }
+
+ pxa3xx_nand_init_mtd(mtd, info);
+
+ platform_set_drvdata(pdev, mtd);
+
+ if (nand_scan(mtd, 1)) {
+ dev_err(&pdev->dev, "failed to scan nand\n");
+ ret = -ENXIO;
+ goto fail_free_irq;
+ }
+
+ return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
+
+fail_free_irq:
+ free_irq(IRQ_NAND, info);
+fail_free_buf:
+ if (use_dma) {
+ pxa_free_dma(info->data_dma_ch);
+ dma_free_coherent(&pdev->dev, info->data_buff_size,
+ info->data_buff, info->data_buff_phys);
+ } else
+ kfree(info->data_buff);
+fail_free_io:
+ iounmap(info->mmio_base);
+fail_free_res:
+ release_mem_region(r->start, r->end - r->start + 1);
+fail_put_clk:
+ clk_disable(info->clk);
+ clk_put(info->clk);
+fail_free_mtd:
+ kfree(mtd);
+ return ret;
+}
+
+static int pxa3xx_nand_remove(struct platform_device *pdev)
+{
+ struct mtd_info *mtd = platform_get_drvdata(pdev);
+ struct pxa3xx_nand_info *info = mtd->priv;
+
+ platform_set_drvdata(pdev, NULL);
+
+ del_mtd_device(mtd);
+ del_mtd_partitions(mtd);
+ free_irq(IRQ_NAND, info);
+ if (use_dma) {
+ pxa_free_dma(info->data_dma_ch);
+ dma_free_writecombine(&pdev->dev, info->data_buff_size,
+ info->data_buff, info->data_buff_phys);
+ } else
+ kfree(info->data_buff);
+ kfree(mtd);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
+ struct pxa3xx_nand_info *info = mtd->priv;
+
+ if (info->state != STATE_READY) {
+ dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int pxa3xx_nand_resume(struct platform_device *pdev)
+{
+ struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev);
+ struct pxa3xx_nand_info *info = mtd->priv;
+
+ clk_enable(info->clk);
+
+ return pxa3xx_nand_config_flash(info);
+}
+#else
+#define pxa3xx_nand_suspend NULL
+#define pxa3xx_nand_resume NULL
+#endif
+
+static struct platform_driver pxa3xx_nand_driver = {
+ .driver = {
+ .name = "pxa3xx-nand",
+ },
+ .probe = pxa3xx_nand_probe,
+ .remove = pxa3xx_nand_remove,
+ .suspend = pxa3xx_nand_suspend,
+ .resume = pxa3xx_nand_resume,
+};
+
+static int __init pxa3xx_nand_init(void)
+{
+ return platform_driver_register(&pxa3xx_nand_driver);
+}
+module_init(pxa3xx_nand_init);
+
+static void __exit pxa3xx_nand_exit(void)
+{
+ platform_driver_unregister(&pxa3xx_nand_driver);
+}
+module_exit(pxa3xx_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PXA3xx NAND controller driver");
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index 0f6ac250f434..26f88215bc47 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -478,6 +478,7 @@ static int __init rtc_from4_init(void)
struct nand_chip *this;
unsigned short bcr1, bcr2, wcr2;
int i;
+ int ret;
/* Allocate memory for MTD device structure and private data */
rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
@@ -537,6 +538,22 @@ static int __init rtc_from4_init(void)
this->ecc.hwctl = rtc_from4_enable_hwecc;
this->ecc.calculate = rtc_from4_calculate_ecc;
this->ecc.correct = rtc_from4_correct_data;
+
+ /* We could create the decoder on demand, if memory is a concern.
+ * This way we have it handy, if an error happens
+ *
+ * Symbolsize is 10 (bits)
+ * Primitve polynomial is x^10+x^3+1
+ * first consecutive root is 0
+ * primitve element to generate roots = 1
+ * generator polinomial degree = 6
+ */
+ rs_decoder = init_rs(10, 0x409, 0, 1, 6);
+ if (!rs_decoder) {
+ printk(KERN_ERR "Could not create a RS decoder\n");
+ ret = -ENOMEM;
+ goto err_1;
+ }
#else
printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
@@ -549,8 +566,8 @@ static int __init rtc_from4_init(void)
/* Scan to find existence of the device */
if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) {
- kfree(rtc_from4_mtd);
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_2;
}
/* Perform 'device recovery' for each chip in case there was a power loss. */
@@ -566,28 +583,19 @@ static int __init rtc_from4_init(void)
#endif
/* Register the partitions */
- add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
+ ret = add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
+ if (ret)
+ goto err_3;
-#ifdef RTC_FROM4_HWECC
- /* We could create the decoder on demand, if memory is a concern.
- * This way we have it handy, if an error happens
- *
- * Symbolsize is 10 (bits)
- * Primitve polynomial is x^10+x^3+1
- * first consecutive root is 0
- * primitve element to generate roots = 1
- * generator polinomial degree = 6
- */
- rs_decoder = init_rs(10, 0x409, 0, 1, 6);
- if (!rs_decoder) {
- printk(KERN_ERR "Could not create a RS decoder\n");
- nand_release(rtc_from4_mtd);
- kfree(rtc_from4_mtd);
- return -ENOMEM;
- }
-#endif
/* Return happy */
return 0;
+err_3:
+ nand_release(rtc_from4_mtd);
+err_2:
+ free_rs(rs_decoder);
+err_1:
+ kfree(rtc_from4_mtd);
+ return ret;
}
module_init(rtc_from4_init);
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 9260ad947524..b34a460ab679 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -119,8 +119,7 @@ struct s3c2410_nand_info {
void __iomem *sel_reg;
int sel_bit;
int mtd_count;
-
- unsigned long save_nfconf;
+ unsigned long save_sel;
enum s3c_cpu_type cpu_type;
};
@@ -358,6 +357,14 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
if (diff0 == 0 && diff1 == 0 && diff2 == 0)
return 0; /* ECC is ok */
+ /* sometimes people do not think about using the ECC, so check
+ * to see if we have an 0xff,0xff,0xff read ECC and then ignore
+ * the error, on the assumption that this is an un-eccd page.
+ */
+ if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff
+ && info->platform->ignore_unset_ecc)
+ return 0;
+
/* Can we correct this ECC (ie, one row and column change).
* Note, this is similar to the 256 error code on smartmedia */
@@ -473,7 +480,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
- pr_debug("%s: returning ecc %06lx\n", __func__, ecc);
+ pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff);
return 0;
}
@@ -644,9 +651,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = 512;
- chip->ecc.bytes = 3;
- chip->ecc.layout = &nand_hw_eccoob;
switch (info->cpu_type) {
case TYPE_S3C2410:
@@ -668,6 +672,40 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
} else {
chip->ecc.mode = NAND_ECC_SOFT;
}
+
+ if (set->ecc_layout != NULL)
+ chip->ecc.layout = set->ecc_layout;
+
+ if (set->disable_ecc)
+ chip->ecc.mode = NAND_ECC_NONE;
+}
+
+/* s3c2410_nand_update_chip
+ *
+ * post-probe chip update, to change any items, such as the
+ * layout for large page nand
+ */
+
+static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+ struct s3c2410_nand_mtd *nmtd)
+{
+ struct nand_chip *chip = &nmtd->chip;
+
+ printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift);
+
+ if (hardware_ecc) {
+ /* change the behaviour depending on wether we are using
+ * the large or small page nand device */
+
+ if (chip->page_shift > 10) {
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+ } else {
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 3;
+ chip->ecc.layout = &nand_hw_eccoob;
+ }
+ }
}
/* s3c2410_nand_probe
@@ -776,9 +814,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
s3c2410_nand_init_chip(info, nmtd, sets);
- nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1);
+ nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
+ (sets) ? sets->nr_chips : 1);
if (nmtd->scan_res == 0) {
+ s3c2410_nand_update_chip(info, nmtd);
+ nand_scan_tail(&nmtd->mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
}
@@ -810,15 +851,14 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
struct s3c2410_nand_info *info = platform_get_drvdata(dev);
if (info) {
- info->save_nfconf = readl(info->regs + S3C2410_NFCONF);
+ info->save_sel = readl(info->sel_reg);
/* For the moment, we must ensure nFCE is high during
* the time we are suspended. This really should be
* handled by suspending the MTDs we are using, but
* that is currently not the case. */
- writel(info->save_nfconf | info->sel_bit,
- info->regs + S3C2410_NFCONF);
+ writel(info->save_sel | info->sel_bit, info->sel_reg);
if (!allow_clk_stop(info))
clk_disable(info->clk);
@@ -830,7 +870,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
static int s3c24xx_nand_resume(struct platform_device *dev)
{
struct s3c2410_nand_info *info = platform_get_drvdata(dev);
- unsigned long nfconf;
+ unsigned long sel;
if (info) {
clk_enable(info->clk);
@@ -838,10 +878,10 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
/* Restore the state of the nFCE line. */
- nfconf = readl(info->regs + S3C2410_NFCONF);
- nfconf &= ~info->sel_bit;
- nfconf |= info->save_nfconf & info->sel_bit;
- writel(nfconf, info->regs + S3C2410_NFCONF);
+ sel = readl(info->sel_reg);
+ sel &= ~info->sel_bit;
+ sel |= info->save_sel & info->sel_bit;
+ writel(sel, info->sel_reg);
if (allow_clk_stop(info))
clk_disable(info->clk);
@@ -927,3 +967,6 @@ module_exit(s3c2410_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
+MODULE_ALIAS("platform:s3c2410-nand");
+MODULE_ALIAS("platform:s3c2412-nand");
+MODULE_ALIAS("platform:s3c2440-nand");
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 0513cbc8834d..345e6eff89ce 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -33,11 +33,6 @@
char nftlmountrev[]="$Revision: 1.41 $";
-extern int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
- size_t *retlen, uint8_t *buf);
-extern int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
- size_t *retlen, uint8_t *buf);
-
/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
* various device information of the NFTL partition and Bad Unit Table. Update
* the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index f86e06934cd8..4f80c2fd89af 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -72,3 +72,5 @@ int __devinit of_mtd_parse_partitions(struct device *dev,
return nr_parts;
}
EXPORT_SYMBOL(of_mtd_parse_partitions);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 8d7d21be1541..5d7965f7e9ce 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -329,6 +329,21 @@ static int onenand_wait(struct mtd_info *mtd, int state)
printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
if (ctrl & ONENAND_CTRL_LOCK)
printk(KERN_ERR "onenand_wait: it's locked error.\n");
+ if (state == FL_READING) {
+ /*
+ * A power loss while writing can result in a page
+ * becoming unreadable. When the device is mounted
+ * again, reading that page gives controller errors.
+ * Upper level software like JFFS2 treat -EIO as fatal,
+ * refusing to mount at all. That means it is necessary
+ * to treat the error as an ECC error to allow recovery.
+ * Note that typically in this case, the eraseblock can
+ * still be erased and rewritten i.e. it has not become
+ * a bad block.
+ */
+ mtd->ecc_stats.failed++;
+ return -EBADMSG;
+ }
return -EIO;
}
@@ -1336,7 +1351,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
}
/* Reject writes, which are not page aligned */
- if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
+ if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n");
return -EINVAL;
}
@@ -1466,7 +1481,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
}
/* Reject writes, which are not page aligned */
- if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
+ if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
return -EINVAL;
}
@@ -2052,7 +2067,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
*
* Check lock status
*/
-static void onenand_check_lock_status(struct onenand_chip *this)
+static int onenand_check_lock_status(struct onenand_chip *this)
{
unsigned int value, block, status;
unsigned int end;
@@ -2070,9 +2085,13 @@ static void onenand_check_lock_status(struct onenand_chip *this)
/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
- if (!(status & ONENAND_WP_US))
+ if (!(status & ONENAND_WP_US)) {
printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
+ return 0;
+ }
}
+
+ return 1;
}
/**
@@ -2081,9 +2100,11 @@ static void onenand_check_lock_status(struct onenand_chip *this)
*
* Unlock all blocks
*/
-static int onenand_unlock_all(struct mtd_info *mtd)
+static void onenand_unlock_all(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
+ loff_t ofs = 0;
+ size_t len = this->chipsize;
if (this->options & ONENAND_HAS_UNLOCK_ALL) {
/* Set start block address */
@@ -2099,23 +2120,19 @@ static int onenand_unlock_all(struct mtd_info *mtd)
& ONENAND_CTRL_ONGO)
continue;
+ /* Check lock status */
+ if (onenand_check_lock_status(this))
+ return;
+
/* Workaround for all block unlock in DDP */
if (ONENAND_IS_DDP(this)) {
- /* 1st block on another chip */
- loff_t ofs = this->chipsize >> 1;
- size_t len = mtd->erasesize;
-
- onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+ /* All blocks on another chip */
+ ofs = this->chipsize >> 1;
+ len = this->chipsize >> 1;
}
-
- onenand_check_lock_status(this);
-
- return 0;
}
- onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK);
-
- return 0;
+ onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
}
#ifdef CONFIG_MTD_ONENAND_OTP
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index aecdd50a1781..2f53b51c6805 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,9 +17,6 @@
#include <linux/mtd/onenand.h>
#include <linux/mtd/compatmac.h>
-extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops);
-
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
* @param buf the buffer to search
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index 823fba4e6d2f..c84e45465499 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -823,7 +823,7 @@ static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev)
kfree(part);
}
-struct mtd_blktrans_ops rfd_ftl_tr = {
+static struct mtd_blktrans_ops rfd_ftl_tr = {
.name = "rfd",
.major = RFD_FTL_MAJOR,
.part_bits = PART_BITS,
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index b9daf159a4a7..3f063108e95f 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -24,8 +24,13 @@ config MTD_UBI_WL_THRESHOLD
erase counter value and the lowest erase counter value of eraseblocks
of UBI devices. When this threshold is exceeded, UBI starts performing
wear leveling by means of moving data from eraseblock with low erase
- counter to eraseblocks with high erase counter. Leave the default
- value if unsure.
+ counter to eraseblocks with high erase counter.
+
+ The default value should be OK for SLC NAND flashes, NOR flashes and
+ other flashes which have eraseblock life-cycle 100000 or more.
+ However, in case of MLC NAND flashes which typically have eraseblock
+ life-cycle less then 10000, the threshold should be lessened (e.g.,
+ to 128 or 256, although it does not have to be power of 2).
config MTD_UBI_BEB_RESERVE
int "Percentage of reserved eraseblocks for bad eraseblocks handling"
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 275960462970..961416ac0616 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -606,8 +606,16 @@ static int io_init(struct ubi_device *ubi)
ubi->ro_mode = 1;
}
- dbg_msg("leb_size %d", ubi->leb_size);
- dbg_msg("ro_mode %d", ubi->ro_mode);
+ ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
+ ubi->peb_size, ubi->peb_size >> 10);
+ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
+ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
+ if (ubi->hdrs_min_io_size != ubi->min_io_size)
+ ubi_msg("sub-page size: %d",
+ ubi->hdrs_min_io_size);
+ ubi_msg("VID header offset: %d (aligned %d)",
+ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
+ ubi_msg("data offset: %d", ubi->leb_start);
/*
* Note, ideally, we have to initialize ubi->bad_peb_count here. But
@@ -755,8 +763,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
mutex_init(&ubi->volumes_mutex);
spin_lock_init(&ubi->volumes_lock);
- dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
- mtd->index, ubi_num, vid_hdr_offset);
+ ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
err = io_init(ubi);
if (err)
@@ -804,15 +811,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
ubi_msg("MTD device name: \"%s\"", mtd->name);
ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
- ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
- ubi->peb_size, ubi->peb_size >> 10);
- ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
ubi_msg("number of good PEBs: %d", ubi->good_peb_count);
ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count);
- ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
- ubi_msg("VID header offset: %d (aligned %d)",
- ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
- ubi_msg("data offset: %d", ubi->leb_start);
ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots);
ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD);
ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
@@ -950,8 +950,7 @@ static int __init ubi_init(void)
BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
if (mtd_devs > UBI_MAX_DEVICES) {
- printk(KERN_ERR "UBI error: too many MTD devices, "
- "maximum is %d\n", UBI_MAX_DEVICES);
+ ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES);
return -EINVAL;
}
@@ -959,25 +958,25 @@ static int __init ubi_init(void)
ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
if (IS_ERR(ubi_class)) {
err = PTR_ERR(ubi_class);
- printk(KERN_ERR "UBI error: cannot create UBI class\n");
+ ubi_err("cannot create UBI class");
goto out;
}
err = class_create_file(ubi_class, &ubi_version);
if (err) {
- printk(KERN_ERR "UBI error: cannot create sysfs file\n");
+ ubi_err("cannot create sysfs file");
goto out_class;
}
err = misc_register(&ubi_ctrl_cdev);
if (err) {
- printk(KERN_ERR "UBI error: cannot register device\n");
+ ubi_err("cannot register device");
goto out_version;
}
ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
- sizeof(struct ubi_wl_entry),
- 0, 0, NULL);
+ sizeof(struct ubi_wl_entry),
+ 0, 0, NULL);
if (!ubi_wl_entry_slab)
goto out_dev_unreg;
@@ -1000,8 +999,7 @@ static int __init ubi_init(void)
mutex_unlock(&ubi_devices_mutex);
if (err < 0) {
put_mtd_device(mtd);
- printk(KERN_ERR "UBI error: cannot attach mtd%d\n",
- mtd->index);
+ ubi_err("cannot attach mtd%d", mtd->index);
goto out_detach;
}
}
@@ -1023,7 +1021,7 @@ out_version:
out_class:
class_destroy(ubi_class);
out:
- printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err);
+ ubi_err("UBI error: cannot initialize UBI, error %d", err);
return err;
}
module_init(ubi_init);
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 51c40b17f1ec..8ea99d8c9e1f 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -41,7 +41,7 @@
/* Generic debugging message */
#define dbg_msg(fmt, ...) \
printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
- current->pid, __FUNCTION__, ##__VA_ARGS__)
+ current->pid, __func__, ##__VA_ARGS__)
#define ubi_dbg_dump_stack() dump_stack()
@@ -99,8 +99,10 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
/* Initialization and build messages */
#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define UBI_IO_DEBUG 1
#else
#define dbg_bld(fmt, ...) ({})
+#define UBI_IO_DEBUG 0
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index d397219238d3..e909b390069a 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -291,11 +291,12 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
/*
* In case of dynamic volume, MTD device size is just volume size. In
* case of a static volume the size is equivalent to the amount of data
- * bytes, which is zero at this moment and will be changed after volume
- * update.
+ * bytes.
*/
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+ else
+ mtd->size = vol->used_bytes;
if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n");
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index db3efdef2433..4ac11df7b048 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -631,6 +631,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
dbg_io("read EC header from PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+ if (UBI_IO_DEBUG)
+ verbose = 1;
err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
if (err) {
@@ -904,6 +906,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
dbg_io("read VID header from PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+ if (UBI_IO_DEBUG)
+ verbose = 1;
p = (char *)vid_hdr - ubi->vid_hdr_shift;
err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 05aa3e7daba1..96d410e106ab 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -42,6 +42,7 @@
#include <linux/err.h>
#include <linux/crc32.h>
+#include <asm/div64.h>
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
@@ -92,27 +93,6 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
}
/**
- * commit_to_mean_value - commit intermediate results to the final mean erase
- * counter value.
- * @si: scanning information
- *
- * This is a helper function which calculates partial mean erase counter mean
- * value and adds it to the resulting mean value. As we can work only in
- * integer arithmetic and we want to calculate the mean value of erase counter
- * accurately, we first sum erase counter values in @si->ec_sum variable and
- * count these components in @si->ec_count. If this temporary @si->ec_sum is
- * going to overflow, we calculate the partial mean value
- * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec.
- */
-static void commit_to_mean_value(struct ubi_scan_info *si)
-{
- si->ec_sum /= si->ec_count;
- if (si->ec_sum % si->ec_count >= si->ec_count / 2)
- si->mean_ec += 1;
- si->mean_ec += si->ec_sum;
-}
-
-/**
* validate_vid_hdr - check that volume identifier header is correct and
* consistent.
* @vid_hdr: the volume identifier header to check
@@ -901,15 +881,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
adjust_mean_ec:
if (!ec_corr) {
- if (si->ec_sum + ec < ec) {
- commit_to_mean_value(si);
- si->ec_sum = 0;
- si->ec_count = 0;
- } else {
- si->ec_sum += ec;
- si->ec_count += 1;
- }
-
+ si->ec_sum += ec;
+ si->ec_count += 1;
if (ec > si->max_ec)
si->max_ec = ec;
if (ec < si->min_ec)
@@ -965,9 +938,11 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
dbg_msg("scanning is finished");
- /* Finish mean erase counter calculations */
- if (si->ec_count)
- commit_to_mean_value(si);
+ /* Calculate mean erase counter */
+ if (si->ec_count) {
+ do_div(si->ec_sum, si->ec_count);
+ si->mean_ec = si->ec_sum;
+ }
if (si->is_empty)
ubi_msg("empty MTD device detected");
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 46d444af471a..966b9b682a42 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -124,7 +124,7 @@ struct ubi_scan_info {
int max_ec;
unsigned long long max_sqnum;
int mean_ec;
- int ec_sum;
+ uint64_t ec_sum;
int ec_count;
};
diff --git a/include/mtd/ubi-header.h b/drivers/mtd/ubi/ubi-media.h
index 292f916ea564..c3185d9fd048 100644
--- a/include/mtd/ubi-header.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -24,11 +24,11 @@
/*
* This file defines the layout of UBI headers and all the other UBI on-flash
- * data structures. May be included by user-space.
+ * data structures.
*/
-#ifndef __UBI_HEADER_H__
-#define __UBI_HEADER_H__
+#ifndef __UBI_MEDIA_H__
+#define __UBI_MEDIA_H__
#include <asm/byteorder.h>
@@ -369,4 +369,4 @@ struct ubi_vtbl_record {
__be32 crc;
} __attribute__ ((packed));
-#endif /* !__UBI_HEADER_H__ */
+#endif /* !__UBI_MEDIA_H__ */
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index a548c1d28fa8..67dcbd11c15c 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -37,10 +37,9 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
-
-#include <mtd/ubi-header.h>
#include <linux/mtd/ubi.h>
+#include "ubi-media.h"
#include "scan.h"
#include "debug.h"
@@ -54,10 +53,10 @@
#define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__)
/* UBI warning messages */
#define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \
- __FUNCTION__, ##__VA_ARGS__)
+ __func__, ##__VA_ARGS__)
/* UBI error messages */
#define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \
- __FUNCTION__, ##__VA_ARGS__)
+ __func__, ##__VA_ARGS__)
/* Lowest number PEBs reserved for bad PEB handling */
#define MIN_RESEVED_PEBS 2
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 015e16325973..f90a86ba7e2f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -469,7 +469,7 @@ config SNI_82596
config KORINA
tristate "Korina (IDT RC32434) Ethernet support"
- depends on NET_ETHERNET && MIKROTIK_RB500
+ depends on NET_ETHERNET && MIKROTIK_RB532
help
If you have a Mikrotik RouterBoard 500 or IDT RC32434
based system say Y. Otherwise say N.
@@ -2011,7 +2011,7 @@ config E1000_DISABLE_PACKET_SPLIT
config E1000E
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
- depends on PCI
+ depends on PCI && (!SPARC32 || BROKEN)
---help---
This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
ethernet family of adapters. For PCI or PCI-X e1000 adapters,
@@ -2278,6 +2278,7 @@ config TSI108_ETH
config GELIC_NET
tristate "PS3 Gigabit Ethernet driver"
depends on PPC_PS3
+ select PS3_SYS_MANAGER
help
This driver supports the network device on the PS3 game
console. This driver has built-in support for Ethernet.
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 978e20a1791b..1e39e78f1778 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -1248,3 +1248,4 @@ module_exit(at91ether_exit)
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver");
MODULE_AUTHOR("Andrew Victor");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 91a6590d107b..ecd8fc6146e9 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -897,6 +897,7 @@ static struct platform_driver ep93xx_eth_driver = {
.remove = ep93xx_eth_remove,
.driver = {
.name = "ep93xx-eth",
+ .owner = THIS_MODULE,
},
};
@@ -914,3 +915,4 @@ static void __exit ep93xx_eth_cleanup_module(void)
module_init(ep93xx_eth_init_module);
module_exit(ep93xx_eth_cleanup_module);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-eth");
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 5586fc624688..0afe522b8f7b 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -91,6 +91,144 @@
#include "atlx.c"
/*
+ * This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define ATL1_MAX_NIC 4
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET }
+
+/*
+ * Interrupt Moderate Timer in units of 2 us
+ *
+ * Valid Range: 10-65535
+ *
+ * Default Value: 100 (200us)
+ */
+static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_int_mod_timer;
+module_param_array_named(int_mod_timer, int_mod_timer, int,
+ &num_int_mod_timer, 0);
+MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer");
+
+#define DEFAULT_INT_MOD_CNT 100 /* 200us */
+#define MAX_INT_MOD_CNT 65000
+#define MIN_INT_MOD_CNT 50
+
+struct atl1_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct atl1_opt_list {
+ int i;
+ char *str;
+ } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt,
+ struct pci_dev *pdev)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ dev_info(&pdev->dev, "%s enabled\n", opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ dev_info(&pdev->dev, "%s disabled\n", opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ dev_info(&pdev->dev, "%s set to %i\n", opt->name,
+ *value);
+ return 0;
+ }
+ break;
+ case list_option:{
+ int i;
+ struct atl1_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ dev_info(&pdev->dev, "%s\n",
+ ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ dev_info(&pdev->dev, "invalid %s specified (%i) %s\n",
+ opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/*
+ * atl1_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ */
+void __devinit atl1_check_options(struct atl1_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int bd = adapter->bd_number;
+ if (bd >= ATL1_MAX_NIC) {
+ dev_notice(&pdev->dev, "no configuration for board#%i\n", bd);
+ dev_notice(&pdev->dev, "using defaults for all values\n");
+ }
+ { /* Interrupt Moderate Timer */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "Interrupt Moderator Timer",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_INT_MOD_CNT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r = {.min = MIN_INT_MOD_CNT,
+ .max = MAX_INT_MOD_CNT} }
+ };
+ int val;
+ if (num_int_mod_timer > bd) {
+ val = int_mod_timer[bd];
+ atl1_validate_option(&val, &opt, pdev);
+ adapter->imt = (u16) val;
+ } else
+ adapter->imt = (u16) (opt.def);
+ }
+}
+
+/*
* atl1_pci_tbl - PCI Device ID Table
*/
static const struct pci_device_id atl1_pci_tbl[] = {
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index 4186326d1b94..f06b854e2501 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -253,181 +253,4 @@ static void atlx_restore_vlan(struct atlx_adapter *adapter)
atlx_vlan_rx_register(adapter->netdev, adapter->vlgrp);
}
-/*
- * This is the only thing that needs to be changed to adjust the
- * maximum number of ports that the driver can manage.
- */
-#define ATL1_MAX_NIC 4
-
-#define OPTION_UNSET -1
-#define OPTION_DISABLED 0
-#define OPTION_ENABLED 1
-
-#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET }
-
-/*
- * Interrupt Moderate Timer in units of 2 us
- *
- * Valid Range: 10-65535
- *
- * Default Value: 100 (200us)
- */
-static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
-static int num_int_mod_timer;
-module_param_array_named(int_mod_timer, int_mod_timer, int,
- &num_int_mod_timer, 0);
-MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer");
-
-/*
- * flash_vendor
- *
- * Valid Range: 0-2
- *
- * 0 - Atmel
- * 1 - SST
- * 2 - ST
- *
- * Default Value: 0
- */
-static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
-static int num_flash_vendor;
-module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0);
-MODULE_PARM_DESC(flash_vendor, "SPI flash vendor");
-
-#define DEFAULT_INT_MOD_CNT 100 /* 200us */
-#define MAX_INT_MOD_CNT 65000
-#define MIN_INT_MOD_CNT 50
-
-#define FLASH_VENDOR_DEFAULT 0
-#define FLASH_VENDOR_MIN 0
-#define FLASH_VENDOR_MAX 2
-
-struct atl1_option {
- enum { enable_option, range_option, list_option } type;
- char *name;
- char *err;
- int def;
- union {
- struct { /* range_option info */
- int min;
- int max;
- } r;
- struct { /* list_option info */
- int nr;
- struct atl1_opt_list {
- int i;
- char *str;
- } *p;
- } l;
- } arg;
-};
-
-static int __devinit atl1_validate_option(int *value, struct atl1_option *opt,
- struct pci_dev *pdev)
-{
- if (*value == OPTION_UNSET) {
- *value = opt->def;
- return 0;
- }
-
- switch (opt->type) {
- case enable_option:
- switch (*value) {
- case OPTION_ENABLED:
- dev_info(&pdev->dev, "%s enabled\n", opt->name);
- return 0;
- case OPTION_DISABLED:
- dev_info(&pdev->dev, "%s disabled\n", opt->name);
- return 0;
- }
- break;
- case range_option:
- if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
- dev_info(&pdev->dev, "%s set to %i\n", opt->name,
- *value);
- return 0;
- }
- break;
- case list_option:{
- int i;
- struct atl1_opt_list *ent;
-
- for (i = 0; i < opt->arg.l.nr; i++) {
- ent = &opt->arg.l.p[i];
- if (*value == ent->i) {
- if (ent->str[0] != '\0')
- dev_info(&pdev->dev, "%s\n",
- ent->str);
- return 0;
- }
- }
- }
- break;
-
- default:
- break;
- }
-
- dev_info(&pdev->dev, "invalid %s specified (%i) %s\n",
- opt->name, *value, opt->err);
- *value = opt->def;
- return -1;
-}
-
-/*
- * atl1_check_options - Range Checking for Command Line Parameters
- * @adapter: board private structure
- *
- * This routine checks all command line parameters for valid user
- * input. If an invalid value is given, or if no user specified
- * value exists, a default value is used. The final value is stored
- * in a variable in the adapter structure.
- */
-void __devinit atl1_check_options(struct atl1_adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
- int bd = adapter->bd_number;
- if (bd >= ATL1_MAX_NIC) {
- dev_notice(&pdev->dev, "no configuration for board#%i\n", bd);
- dev_notice(&pdev->dev, "using defaults for all values\n");
- }
- { /* Interrupt Moderate Timer */
- struct atl1_option opt = {
- .type = range_option,
- .name = "Interrupt Moderator Timer",
- .err = "using default of "
- __MODULE_STRING(DEFAULT_INT_MOD_CNT),
- .def = DEFAULT_INT_MOD_CNT,
- .arg = {.r = {.min = MIN_INT_MOD_CNT,
- .max = MAX_INT_MOD_CNT} }
- };
- int val;
- if (num_int_mod_timer > bd) {
- val = int_mod_timer[bd];
- atl1_validate_option(&val, &opt, pdev);
- adapter->imt = (u16) val;
- } else
- adapter->imt = (u16) (opt.def);
- }
-
- { /* Flash Vendor */
- struct atl1_option opt = {
- .type = range_option,
- .name = "SPI Flash Vendor",
- .err = "using default of "
- __MODULE_STRING(FLASH_VENDOR_DEFAULT),
- .def = DEFAULT_INT_MOD_CNT,
- .arg = {.r = {.min = FLASH_VENDOR_MIN,
- .max = FLASH_VENDOR_MAX} }
- };
- int val;
- if (num_flash_vendor > bd) {
- val = flash_vendor[bd];
- atl1_validate_option(&val, &opt, pdev);
- adapter->hw.flash_vendor = (u8) val;
- } else
- adapter->hw.flash_vendor = (u8) (opt.def);
- }
-}
-
#endif /* ATLX_C */
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 194949afacd0..0b4adf4a0f7d 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -1005,3 +1005,4 @@ module_exit(axdrv_exit);
MODULE_DESCRIPTION("AX88796 10/100 Ethernet platform driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ax88796");
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 717dcc1aa1e9..4fec8581bfd7 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -47,6 +47,7 @@
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRV_DESC);
+MODULE_ALIAS("platform:bfin_mac");
#if defined(CONFIG_BFIN_MAC_USE_L1)
# define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size)
@@ -1089,8 +1090,9 @@ static struct platform_driver bfin_mac_driver = {
.resume = bfin_mac_resume,
.suspend = bfin_mac_suspend,
.driver = {
- .name = DRV_NAME,
- },
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
};
static int __init bfin_mac_init(void)
@@ -1106,3 +1108,4 @@ static void __exit bfin_mac_cleanup(void)
}
module_exit(bfin_mac_cleanup);
+
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 9da7ff437031..2b5740b3d182 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -42,6 +42,7 @@
MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cpmac");
static int debug_level = 8;
static int dumb_switch;
@@ -1103,6 +1104,7 @@ static int __devexit cpmac_remove(struct platform_device *pdev)
static struct platform_driver cpmac_driver = {
.driver.name = "cpmac",
+ .driver.owner = THIS_MODULE,
.probe = cpmac_probe,
.remove = __devexit_p(cpmac_remove),
};
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index d63cc93f055d..e6fe2614ea6d 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -1418,3 +1418,4 @@ module_exit(dm9000_cleanup);
MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dm9000");
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 01c88664bad3..462351ca2c81 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1326,12 +1326,10 @@ struct e1000_info e1000_82571_info = {
.mac = e1000_82571,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
- | FLAG_HAS_STATS_PTC_PRC
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
- | FLAG_HAS_STATS_ICR_ICT
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_RESET_OVERWRITES_LAA /* errata */
| FLAG_TARC_SPEED_MODE_BIT /* errata */
@@ -1347,12 +1345,10 @@ struct e1000_info e1000_82572_info = {
.mac = e1000_82572,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
- | FLAG_HAS_STATS_PTC_PRC
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
- | FLAG_HAS_STATS_ICR_ICT
| FLAG_TARC_SPEED_MODE_BIT, /* errata */
.pba = 38,
.get_variants = e1000_get_variants_82571,
@@ -1365,11 +1361,9 @@ struct e1000_info e1000_82573_info = {
.mac = e1000_82573,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
- | FLAG_HAS_STATS_PTC_PRC
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
| FLAG_RX_CSUM_ENABLED
- | FLAG_HAS_STATS_ICR_ICT
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_ERT
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 572cfd44397a..2a53875cddbf 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -184,6 +184,7 @@
#define E1000_SWFW_EEP_SM 0x1
#define E1000_SWFW_PHY0_SM 0x2
#define E1000_SWFW_PHY1_SM 0x4
+#define E1000_SWFW_CSR_SM 0x8
/* Device Control */
#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
@@ -527,8 +528,10 @@
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
/* NVM Control */
#define E1000_EECD_SK 0x00000001 /* NVM Clock */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 5a89dff52264..38bfd0d261fe 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -64,11 +64,14 @@ struct e1000_info;
/* Tx/Rx descriptor defines */
#define E1000_DEFAULT_TXD 256
#define E1000_MAX_TXD 4096
-#define E1000_MIN_TXD 80
+#define E1000_MIN_TXD 64
#define E1000_DEFAULT_RXD 256
#define E1000_MAX_RXD 4096
-#define E1000_MIN_RXD 80
+#define E1000_MIN_RXD 64
+
+#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
/* Early Receive defines */
#define E1000_ERT_2048 0x100
@@ -147,6 +150,18 @@ struct e1000_ring {
struct e1000_queue_stats stats;
};
+/* PHY register snapshot values */
+struct e1000_phy_regs {
+ u16 bmcr; /* basic mode control register */
+ u16 bmsr; /* basic mode status register */
+ u16 advertise; /* auto-negotiation advertisement */
+ u16 lpa; /* link partner ability register */
+ u16 expansion; /* auto-negotiation expansion reg */
+ u16 ctrl1000; /* 1000BASE-T control register */
+ u16 stat1000; /* 1000BASE-T status register */
+ u16 estatus; /* extended status register */
+};
+
/* board specific private data structure */
struct e1000_adapter {
struct timer_list watchdog_timer;
@@ -202,8 +217,8 @@ struct e1000_adapter {
/* Tx stats */
u64 tpt_old;
u64 colc_old;
- u64 gotcl_old;
- u32 gotcl;
+ u32 gotc;
+ u64 gotc_old;
u32 tx_timeout_count;
u32 tx_fifo_head;
u32 tx_head_addr;
@@ -227,8 +242,8 @@ struct e1000_adapter {
u64 hw_csum_err;
u64 hw_csum_good;
u64 rx_hdr_split;
- u64 gorcl_old;
- u32 gorcl;
+ u32 gorc;
+ u64 gorc_old;
u32 alloc_rx_buff_failed;
u32 rx_dma_failed;
@@ -250,6 +265,9 @@ struct e1000_adapter {
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
+ /* Snapshot of PHY registers */
+ struct e1000_phy_regs phy_regs;
+
struct e1000_ring test_tx_ring;
struct e1000_ring test_rx_ring;
u32 test_icr;
@@ -286,8 +304,6 @@ struct e1000_info {
#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5)
#define FLAG_HAS_SWSM_ON_LOAD (1 << 6)
#define FLAG_HAS_JUMBO_FRAMES (1 << 7)
-#define FLAG_HAS_STATS_ICR_ICT (1 << 9)
-#define FLAG_HAS_STATS_PTC_PRC (1 << 10)
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
#define FLAG_IS_QUAD_PORT_A (1 << 12)
#define FLAG_IS_QUAD_PORT (1 << 13)
@@ -433,6 +449,8 @@ extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
extern s32 e1000e_check_downshift(struct e1000_hw *hw);
static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index d59a99ae44be..dc552d7d6fac 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -41,6 +41,7 @@
#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F
#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
@@ -48,6 +49,7 @@
#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000
#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
@@ -85,6 +87,9 @@
/* Kumeran Mode Control Register (Page 193, Register 16) */
#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY 0x5
+
/* Power Management Control Register (Page 193, Register 20) */
#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
/* 1=Enable SERDES Electrical Idle */
@@ -270,6 +275,7 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
u16 mask;
mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ mask |= E1000_SWFW_CSR_SM;
return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
}
@@ -286,6 +292,8 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
u16 mask;
mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ mask |= E1000_SWFW_CSR_SM;
+
e1000_release_swfw_sync_80003es2lan(hw, mask);
}
@@ -410,20 +418,27 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
u32 page_select;
u16 temp;
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ return ret_val;
+
/* Select Configuration Page */
- if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
page_select = GG82563_PHY_PAGE_SELECT;
- else
+ } else {
/*
* Use Alternative Page Select register to access
* registers 30 and 31
*/
page_select = GG82563_PHY_PAGE_SELECT_ALT;
+ }
temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
- ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
- if (ret_val)
+ ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
+ if (ret_val) {
+ e1000_release_phy_80003es2lan(hw);
return ret_val;
+ }
/*
* The "ready" bit in the MDIC register may be incorrectly set
@@ -433,20 +448,21 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
udelay(200);
/* ...and verify the command was successful. */
- ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+ ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
ret_val = -E1000_ERR_PHY;
+ e1000_release_phy_80003es2lan(hw);
return ret_val;
}
udelay(200);
- ret_val = e1000e_read_phy_reg_m88(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
udelay(200);
+ e1000_release_phy_80003es2lan(hw);
return ret_val;
}
@@ -467,20 +483,27 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
u32 page_select;
u16 temp;
+ ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ return ret_val;
+
/* Select Configuration Page */
- if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
page_select = GG82563_PHY_PAGE_SELECT;
- else
+ } else {
/*
* Use Alternative Page Select register to access
* registers 30 and 31
*/
page_select = GG82563_PHY_PAGE_SELECT_ALT;
+ }
temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
- ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
- if (ret_val)
+ ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
+ if (ret_val) {
+ e1000_release_phy_80003es2lan(hw);
return ret_val;
+ }
/*
@@ -491,18 +514,20 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
udelay(200);
/* ...and verify the command was successful. */
- ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+ ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
- if (((u16)offset >> GG82563_PAGE_SHIFT) != temp)
+ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ e1000_release_phy_80003es2lan(hw);
return -E1000_ERR_PHY;
+ }
udelay(200);
- ret_val = e1000e_write_phy_reg_m88(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
udelay(200);
+ e1000_release_phy_80003es2lan(hw);
return ret_val;
}
@@ -882,10 +907,10 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
u32 ctrl_ext;
- u16 data;
+ u32 i = 0;
+ u16 data, data2;
- ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
- &data);
+ ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data);
if (ret_val)
return ret_val;
@@ -893,8 +918,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
- ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
- data);
+ ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, data);
if (ret_val)
return ret_val;
@@ -954,6 +978,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+ &data);
+ if (ret_val)
+ return ret_val;
+ data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+ data);
+ if (ret_val)
+ return ret_val;
+
ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
if (ret_val)
return ret_val;
@@ -983,9 +1019,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
- if (ret_val)
- return ret_val;
+ do {
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
+ &data2);
+ if (ret_val)
+ return ret_val;
+ i++;
+ } while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY));
data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
@@ -1074,7 +1119,8 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
{
s32 ret_val;
u32 tipg;
- u16 reg_data;
+ u32 i = 0;
+ u16 reg_data, reg_data2;
reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
@@ -1088,9 +1134,16 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
ew32(TIPG, tipg);
- ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
- if (ret_val)
- return ret_val;
+ do {
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data2);
+ if (ret_val)
+ return ret_val;
+ i++;
+ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
if (duplex == HALF_DUPLEX)
reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
@@ -1112,8 +1165,9 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
{
s32 ret_val;
- u16 reg_data;
+ u16 reg_data, reg_data2;
u32 tipg;
+ u32 i = 0;
reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
@@ -1127,9 +1181,16 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
ew32(TIPG, tipg);
- ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
- if (ret_val)
- return ret_val;
+ do {
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data2);
+ if (ret_val)
+ return ret_val;
+ i++;
+ } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
@@ -1231,12 +1292,10 @@ struct e1000_info e1000_es2_info = {
.mac = e1000_80003es2lan,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
- | FLAG_HAS_STATS_PTC_PRC
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
- | FLAG_HAS_STATS_ICR_ICT
| FLAG_RX_NEEDS_RESTART /* errata */
| FLAG_TARC_SET_BIT_ZERO /* errata */
| FLAG_APME_CHECK_PORT_B
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 6d1b257bbda6..ce045acce63e 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -46,8 +46,8 @@ struct e1000_stats {
static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_packets", E1000_STAT(stats.gprc) },
{ "tx_packets", E1000_STAT(stats.gptc) },
- { "rx_bytes", E1000_STAT(stats.gorcl) },
- { "tx_bytes", E1000_STAT(stats.gotcl) },
+ { "rx_bytes", E1000_STAT(stats.gorc) },
+ { "tx_bytes", E1000_STAT(stats.gotc) },
{ "rx_broadcast", E1000_STAT(stats.bprc) },
{ "tx_broadcast", E1000_STAT(stats.bptc) },
{ "rx_multicast", E1000_STAT(stats.mprc) },
@@ -83,7 +83,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
{ "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
- { "rx_long_byte_count", E1000_STAT(stats.gorcl) },
+ { "rx_long_byte_count", E1000_STAT(stats.gorc) },
{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
{ "rx_header_split", E1000_STAT(rx_hdr_split) },
@@ -1770,6 +1770,47 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
return 0;
}
+static int e1000_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->itr_setting <= 3)
+ ec->rx_coalesce_usecs = adapter->itr_setting;
+ else
+ ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+ return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+ ((ec->rx_coalesce_usecs > 3) &&
+ (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+ (ec->rx_coalesce_usecs == 2))
+ return -EINVAL;
+
+ if (ec->rx_coalesce_usecs <= 3) {
+ adapter->itr = 20000;
+ adapter->itr_setting = ec->rx_coalesce_usecs;
+ } else {
+ adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+ adapter->itr_setting = adapter->itr & ~3;
+ }
+
+ if (adapter->itr_setting != 0)
+ ew32(ITR, 1000000000 / (adapter->itr * 256));
+ else
+ ew32(ITR, 0);
+
+ return 0;
+}
+
static int e1000_nway_reset(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1845,6 +1886,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.phys_id = e1000_phys_id,
.get_ethtool_stats = e1000_get_ethtool_stats,
.get_sset_count = e1000e_get_sset_count,
+ .get_coalesce = e1000_get_coalesce,
+ .set_coalesce = e1000_set_coalesce,
};
void e1000e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 53f1ac6327fa..a930e6d9cf02 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -592,10 +592,8 @@ struct e1000_hw_stats {
u64 bprc;
u64 mprc;
u64 gptc;
- u64 gorcl;
- u64 gorch;
- u64 gotcl;
- u64 gotch;
+ u64 gorc;
+ u64 gotc;
u64 rnbc;
u64 ruc;
u64 rfc;
@@ -604,10 +602,8 @@ struct e1000_hw_stats {
u64 mgprc;
u64 mgpdc;
u64 mgptc;
- u64 torl;
- u64 torh;
- u64 totl;
- u64 toth;
+ u64 tor;
+ u64 tot;
u64 tpr;
u64 tpt;
u64 ptc64;
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index c8dc47fd132a..8991ab8911e2 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -46,7 +46,7 @@
#include "e1000.h"
-#define DRV_VERSION "0.2.0"
+#define DRV_VERSION "0.2.1"
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -466,10 +466,10 @@ next_desc:
if (cleaned_count)
adapter->alloc_rx_buf(adapter, cleaned_count);
- adapter->total_rx_packets += total_rx_packets;
adapter->total_rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ adapter->total_rx_packets += total_rx_packets;
adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -606,8 +606,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
}
adapter->total_tx_bytes += total_tx_bytes;
adapter->total_tx_packets += total_tx_packets;
- adapter->net_stats.tx_packets += total_tx_packets;
adapter->net_stats.tx_bytes += total_tx_bytes;
+ adapter->net_stats.tx_packets += total_tx_packets;
return cleaned;
}
@@ -775,10 +775,10 @@ next_desc:
if (cleaned_count)
adapter->alloc_rx_buf(adapter, cleaned_count);
- adapter->total_rx_packets += total_rx_packets;
adapter->total_rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ adapter->total_rx_packets += total_rx_packets;
adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -2506,56 +2506,27 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.crcerrs += er32(CRCERRS);
adapter->stats.gprc += er32(GPRC);
- adapter->stats.gorcl += er32(GORCL);
- adapter->stats.gorch += er32(GORCH);
+ adapter->stats.gorc += er32(GORCL);
+ er32(GORCH); /* Clear gorc */
adapter->stats.bprc += er32(BPRC);
adapter->stats.mprc += er32(MPRC);
adapter->stats.roc += er32(ROC);
- if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
- adapter->stats.prc64 += er32(PRC64);
- adapter->stats.prc127 += er32(PRC127);
- adapter->stats.prc255 += er32(PRC255);
- adapter->stats.prc511 += er32(PRC511);
- adapter->stats.prc1023 += er32(PRC1023);
- adapter->stats.prc1522 += er32(PRC1522);
- adapter->stats.symerrs += er32(SYMERRS);
- adapter->stats.sec += er32(SEC);
- }
-
adapter->stats.mpc += er32(MPC);
adapter->stats.scc += er32(SCC);
adapter->stats.ecol += er32(ECOL);
adapter->stats.mcc += er32(MCC);
adapter->stats.latecol += er32(LATECOL);
adapter->stats.dc += er32(DC);
- adapter->stats.rlec += er32(RLEC);
adapter->stats.xonrxc += er32(XONRXC);
adapter->stats.xontxc += er32(XONTXC);
adapter->stats.xoffrxc += er32(XOFFRXC);
adapter->stats.xofftxc += er32(XOFFTXC);
- adapter->stats.fcruc += er32(FCRUC);
adapter->stats.gptc += er32(GPTC);
- adapter->stats.gotcl += er32(GOTCL);
- adapter->stats.gotch += er32(GOTCH);
+ adapter->stats.gotc += er32(GOTCL);
+ er32(GOTCH); /* Clear gotc */
adapter->stats.rnbc += er32(RNBC);
adapter->stats.ruc += er32(RUC);
- adapter->stats.rfc += er32(RFC);
- adapter->stats.rjc += er32(RJC);
- adapter->stats.torl += er32(TORL);
- adapter->stats.torh += er32(TORH);
- adapter->stats.totl += er32(TOTL);
- adapter->stats.toth += er32(TOTH);
- adapter->stats.tpr += er32(TPR);
-
- if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
- adapter->stats.ptc64 += er32(PTC64);
- adapter->stats.ptc127 += er32(PTC127);
- adapter->stats.ptc255 += er32(PTC255);
- adapter->stats.ptc511 += er32(PTC511);
- adapter->stats.ptc1023 += er32(PTC1023);
- adapter->stats.ptc1522 += er32(PTC1522);
- }
adapter->stats.mptc += er32(MPTC);
adapter->stats.bptc += er32(BPTC);
@@ -2574,19 +2545,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.tsctc += er32(TSCTC);
adapter->stats.tsctfc += er32(TSCTFC);
- adapter->stats.iac += er32(IAC);
-
- if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) {
- adapter->stats.icrxoc += er32(ICRXOC);
- adapter->stats.icrxptc += er32(ICRXPTC);
- adapter->stats.icrxatc += er32(ICRXATC);
- adapter->stats.ictxptc += er32(ICTXPTC);
- adapter->stats.ictxatc += er32(ICTXATC);
- adapter->stats.ictxqec += er32(ICTXQEC);
- adapter->stats.ictxqmtc += er32(ICTXQMTC);
- adapter->stats.icrxdmtc += er32(ICRXDMTC);
- }
-
/* Fill out the OS statistics structure */
adapter->net_stats.multicast = adapter->stats.mprc;
adapter->net_stats.collisions = adapter->stats.colc;
@@ -2633,6 +2591,54 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
}
+/**
+ * e1000_phy_read_status - Update the PHY register status snapshot
+ * @adapter: board private structure
+ **/
+static void e1000_phy_read_status(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_phy_regs *phy = &adapter->phy_regs;
+ int ret_val;
+ unsigned long irq_flags;
+
+
+ spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+
+ if ((er32(STATUS) & E1000_STATUS_LU) &&
+ (adapter->hw.phy.media_type == e1000_media_type_copper)) {
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr);
+ ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr);
+ ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise);
+ ret_val |= e1e_rphy(hw, PHY_LP_ABILITY, &phy->lpa);
+ ret_val |= e1e_rphy(hw, PHY_AUTONEG_EXP, &phy->expansion);
+ ret_val |= e1e_rphy(hw, PHY_1000T_CTRL, &phy->ctrl1000);
+ ret_val |= e1e_rphy(hw, PHY_1000T_STATUS, &phy->stat1000);
+ ret_val |= e1e_rphy(hw, PHY_EXT_STATUS, &phy->estatus);
+ if (ret_val)
+ ndev_warn(adapter->netdev,
+ "Error reading PHY register\n");
+ } else {
+ /*
+ * Do not read PHY registers if link is not up
+ * Set values to typical power-on defaults
+ */
+ phy->bmcr = (BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_FULLDPLX);
+ phy->bmsr = (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL |
+ BMSR_10HALF | BMSR_ESTATEN | BMSR_ANEGCAPABLE |
+ BMSR_ERCAP);
+ phy->advertise = (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_ALL | ADVERTISE_CSMA);
+ phy->lpa = 0;
+ phy->expansion = EXPANSION_ENABLENPAGE;
+ phy->ctrl1000 = ADVERTISE_1000FULL;
+ phy->stat1000 = 0;
+ phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
+ }
+
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+}
+
static void e1000_print_link_info(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -2745,6 +2751,7 @@ static void e1000_watchdog_task(struct work_struct *work)
if (!netif_carrier_ok(netdev)) {
bool txb2b = 1;
/* update snapshot of PHY registers on LSC */
+ e1000_phy_read_status(adapter);
mac->ops.get_link_up_info(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
@@ -2842,10 +2849,10 @@ link_up:
mac->collision_delta = adapter->stats.colc - adapter->colc_old;
adapter->colc_old = adapter->stats.colc;
- adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
- adapter->gorcl_old = adapter->stats.gorcl;
- adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
- adapter->gotcl_old = adapter->stats.gotcl;
+ adapter->gorc = adapter->stats.gorc - adapter->gorc_old;
+ adapter->gorc_old = adapter->stats.gorc;
+ adapter->gotc = adapter->stats.gotc - adapter->gotc_old;
+ adapter->gotc_old = adapter->stats.gotc;
e1000e_update_adaptive(&adapter->hw);
@@ -3500,7 +3507,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct mii_ioctl_data *data = if_mii(ifr);
- unsigned long irq_flags;
if (adapter->hw.phy.media_type != e1000_media_type_copper)
return -EOPNOTSUPP;
@@ -3512,13 +3518,40 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
case SIOCGMIIREG:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- spin_lock_irqsave(&adapter->stats_lock, irq_flags);
- if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F,
- &data->val_out)) {
- spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+ switch (data->reg_num & 0x1F) {
+ case MII_BMCR:
+ data->val_out = adapter->phy_regs.bmcr;
+ break;
+ case MII_BMSR:
+ data->val_out = adapter->phy_regs.bmsr;
+ break;
+ case MII_PHYSID1:
+ data->val_out = (adapter->hw.phy.id >> 16);
+ break;
+ case MII_PHYSID2:
+ data->val_out = (adapter->hw.phy.id & 0xFFFF);
+ break;
+ case MII_ADVERTISE:
+ data->val_out = adapter->phy_regs.advertise;
+ break;
+ case MII_LPA:
+ data->val_out = adapter->phy_regs.lpa;
+ break;
+ case MII_EXPANSION:
+ data->val_out = adapter->phy_regs.expansion;
+ break;
+ case MII_CTRL1000:
+ data->val_out = adapter->phy_regs.ctrl1000;
+ break;
+ case MII_STAT1000:
+ data->val_out = adapter->phy_regs.stat1000;
+ break;
+ case MII_ESTATUS:
+ data->val_out = adapter->phy_regs.estatus;
+ break;
+ default:
return -EIO;
}
- spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
break;
case SIOCSMIIREG:
default:
@@ -3774,6 +3807,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
+ pci_restore_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
@@ -3900,6 +3934,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
goto err_pci_reg;
pci_set_master(pdev);
+ pci_save_state(pdev);
err = -ENOMEM;
netdev = alloc_etherdev(sizeof(struct e1000_adapter));
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 3a4574caa75b..e102332a6bee 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -116,7 +116,7 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
}
/**
- * e1000_read_phy_reg_mdic - Read MDI control register
+ * e1000e_read_phy_reg_mdic - Read MDI control register
* @hw: pointer to the HW structure
* @offset: register offset to be read
* @data: pointer to the read data
@@ -124,7 +124,7 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
* Reads the MDI control register in the PHY at offset and stores the
* information read to data.
**/
-static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
{
struct e1000_phy_info *phy = &hw->phy;
u32 i, mdic = 0;
@@ -150,7 +150,7 @@ static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
* Increasing the time out as testing showed failures with
* the lower time out
*/
- for (i = 0; i < 64; i++) {
+ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
udelay(50);
mdic = er32(MDIC);
if (mdic & E1000_MDIC_READY)
@@ -170,14 +170,14 @@ static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
}
/**
- * e1000_write_phy_reg_mdic - Write MDI control register
+ * e1000e_write_phy_reg_mdic - Write MDI control register
* @hw: pointer to the HW structure
* @offset: register offset to write to
* @data: data to write to register at offset
*
* Writes data to MDI control register in the PHY at offset.
**/
-static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
{
struct e1000_phy_info *phy = &hw->phy;
u32 i, mdic = 0;
@@ -199,9 +199,13 @@ static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
ew32(MDIC, mdic);
- /* Poll the ready bit to see if the MDI read completed */
- for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
- udelay(5);
+ /*
+ * Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+ udelay(50);
mdic = er32(MDIC);
if (mdic & E1000_MDIC_READY)
break;
@@ -210,6 +214,10 @@ static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
hw_dbg(hw, "MDI Write did not complete\n");
return -E1000_ERR_PHY;
}
+ if (mdic & E1000_MDIC_ERROR) {
+ hw_dbg(hw, "MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
return 0;
}
@@ -232,9 +240,8 @@ s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
if (ret_val)
return ret_val;
- ret_val = e1000_read_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
hw->phy.ops.release_phy(hw);
@@ -258,9 +265,8 @@ s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
if (ret_val)
return ret_val;
- ret_val = e1000_write_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
hw->phy.ops.release_phy(hw);
@@ -286,18 +292,17 @@ s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
return ret_val;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
- ret_val = e1000_write_phy_reg_mdic(hw,
- IGP01E1000_PHY_PAGE_SELECT,
- (u16)offset);
+ ret_val = e1000e_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
if (ret_val) {
hw->phy.ops.release_phy(hw);
return ret_val;
}
}
- ret_val = e1000_read_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
hw->phy.ops.release_phy(hw);
@@ -322,18 +327,17 @@ s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
return ret_val;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
- ret_val = e1000_write_phy_reg_mdic(hw,
- IGP01E1000_PHY_PAGE_SELECT,
- (u16)offset);
+ ret_val = e1000e_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
if (ret_val) {
hw->phy.ops.release_phy(hw);
return ret_val;
}
}
- ret_val = e1000_write_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+ data);
hw->phy.ops.release_phy(hw);
@@ -420,7 +424,9 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ /* For newer PHYs this bit is downshift enable */
+ if (phy->type == e1000_phy_m88)
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
/*
* Options:
@@ -463,7 +469,7 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- if (phy->revision < 4) {
+ if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) {
/*
* Force TX_CLK in the Extended PHY Specific Control Register
* to 25MHz clock.
@@ -518,8 +524,11 @@ s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
return ret_val;
}
- /* Wait 15ms for MAC to configure PHY from NVM settings. */
- msleep(15);
+ /*
+ * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+ * timeout issues when LFS is enabled.
+ */
+ msleep(100);
/* disable lplu d0 during driver init */
ret_val = e1000_set_d0_lplu_state(hw, 0);
@@ -1152,9 +1161,7 @@ s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
if (!active) {
data &= ~IGP02E1000_PM_D3_LPLU;
- ret_val = e1e_wphy(hw,
- IGP02E1000_PHY_POWER_MGMT,
- data);
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
if (ret_val)
return ret_val;
/*
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 9ff7538b7595..f9bc21c74b59 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -2611,7 +2611,7 @@ static int ehea_stop(struct net_device *dev)
return ret;
}
-void ehea_purge_sq(struct ehea_qp *orig_qp)
+static void ehea_purge_sq(struct ehea_qp *orig_qp)
{
struct ehea_qp qp = *orig_qp;
struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2625,7 +2625,7 @@ void ehea_purge_sq(struct ehea_qp *orig_qp)
}
}
-void ehea_flush_sq(struct ehea_port *port)
+static void ehea_flush_sq(struct ehea_port *port)
{
int i;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 8c4214b0ee1f..35f66d4a4595 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -96,6 +96,7 @@
#define DEV_HAS_PAUSEFRAME_TX_V2 0x10000 /* device supports tx pause frames version 2 */
#define DEV_HAS_PAUSEFRAME_TX_V3 0x20000 /* device supports tx pause frames version 3 */
#define DEV_NEED_TX_LIMIT 0x40000 /* device needs to limit tx */
+#define DEV_HAS_GEAR_MODE 0x80000 /* device supports gear mode */
enum {
NvRegIrqStatus = 0x000,
@@ -174,11 +175,13 @@ enum {
NvRegReceiverStatus = 0x98,
#define NVREG_RCVSTAT_BUSY 0x01
- NvRegRandomSeed = 0x9c,
-#define NVREG_RNDSEED_MASK 0x00ff
-#define NVREG_RNDSEED_FORCE 0x7f00
-#define NVREG_RNDSEED_FORCE2 0x2d00
-#define NVREG_RNDSEED_FORCE3 0x7400
+ NvRegSlotTime = 0x9c,
+#define NVREG_SLOTTIME_LEGBF_ENABLED 0x80000000
+#define NVREG_SLOTTIME_10_100_FULL 0x00007f00
+#define NVREG_SLOTTIME_1000_FULL 0x0003ff00
+#define NVREG_SLOTTIME_HALF 0x0000ff00
+#define NVREG_SLOTTIME_DEFAULT 0x00007f00
+#define NVREG_SLOTTIME_MASK 0x000000ff
NvRegTxDeferral = 0xA0,
#define NVREG_TX_DEFERRAL_DEFAULT 0x15050f
@@ -201,6 +204,11 @@ enum {
NvRegPhyInterface = 0xC0,
#define PHY_RGMII 0x10000000
+ NvRegBackOffControl = 0xC4,
+#define NVREG_BKOFFCTRL_DEFAULT 0x70000000
+#define NVREG_BKOFFCTRL_SEED_MASK 0x000003ff
+#define NVREG_BKOFFCTRL_SELECT 24
+#define NVREG_BKOFFCTRL_GEAR 12
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
@@ -352,6 +360,7 @@ union ring_type {
#define NV_TX_LASTPACKET (1<<16)
#define NV_TX_RETRYERROR (1<<19)
+#define NV_TX_RETRYCOUNT_MASK (0xF<<20)
#define NV_TX_FORCED_INTERRUPT (1<<24)
#define NV_TX_DEFERRED (1<<26)
#define NV_TX_CARRIERLOST (1<<27)
@@ -362,6 +371,7 @@ union ring_type {
#define NV_TX2_LASTPACKET (1<<29)
#define NV_TX2_RETRYERROR (1<<18)
+#define NV_TX2_RETRYCOUNT_MASK (0xF<<19)
#define NV_TX2_FORCED_INTERRUPT (1<<30)
#define NV_TX2_DEFERRED (1<<25)
#define NV_TX2_CARRIERLOST (1<<26)
@@ -473,16 +483,22 @@ union ring_type {
#define DESC_VER_3 3
/* PHY defines */
-#define PHY_OUI_MARVELL 0x5043
-#define PHY_OUI_CICADA 0x03f1
-#define PHY_OUI_VITESSE 0x01c1
-#define PHY_OUI_REALTEK 0x0732
+#define PHY_OUI_MARVELL 0x5043
+#define PHY_OUI_CICADA 0x03f1
+#define PHY_OUI_VITESSE 0x01c1
+#define PHY_OUI_REALTEK 0x0732
+#define PHY_OUI_REALTEK2 0x0020
#define PHYID1_OUI_MASK 0x03ff
#define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00
#define PHYID2_OUI_SHFT 10
#define PHYID2_MODEL_MASK 0x03f0
-#define PHY_MODEL_MARVELL_E3016 0x220
+#define PHY_MODEL_REALTEK_8211 0x0110
+#define PHY_REV_MASK 0x0001
+#define PHY_REV_REALTEK_8211B 0x0000
+#define PHY_REV_REALTEK_8211C 0x0001
+#define PHY_MODEL_REALTEK_8201 0x0200
+#define PHY_MODEL_MARVELL_E3016 0x0220
#define PHY_MARVELL_E3016_INITMASK 0x0300
#define PHY_CICADA_INIT1 0x0f000
#define PHY_CICADA_INIT2 0x0e00
@@ -509,10 +525,18 @@ union ring_type {
#define PHY_REALTEK_INIT_REG1 0x1f
#define PHY_REALTEK_INIT_REG2 0x19
#define PHY_REALTEK_INIT_REG3 0x13
+#define PHY_REALTEK_INIT_REG4 0x14
+#define PHY_REALTEK_INIT_REG5 0x18
+#define PHY_REALTEK_INIT_REG6 0x11
#define PHY_REALTEK_INIT1 0x0000
#define PHY_REALTEK_INIT2 0x8e00
#define PHY_REALTEK_INIT3 0x0001
#define PHY_REALTEK_INIT4 0xad17
+#define PHY_REALTEK_INIT5 0xfb54
+#define PHY_REALTEK_INIT6 0xf5c7
+#define PHY_REALTEK_INIT7 0x1000
+#define PHY_REALTEK_INIT8 0x0003
+#define PHY_REALTEK_INIT_MSK1 0x0003
#define PHY_GIGABIT 0x0100
@@ -691,6 +715,7 @@ struct fe_priv {
int wolenabled;
unsigned int phy_oui;
unsigned int phy_model;
+ unsigned int phy_rev;
u16 gigabit;
int intr_test;
int recover_error;
@@ -704,6 +729,7 @@ struct fe_priv {
u32 txrxctl_bits;
u32 vlanctl_bits;
u32 driver_data;
+ u32 device_id;
u32 register_size;
int rx_csum;
u32 mac_in_use;
@@ -814,6 +840,16 @@ enum {
};
static int dma_64bit = NV_DMA_64BIT_ENABLED;
+/*
+ * Crossover Detection
+ * Realtek 8201 phy + some OEM boards do not work properly.
+ */
+enum {
+ NV_CROSSOVER_DETECTION_DISABLED,
+ NV_CROSSOVER_DETECTION_ENABLED
+};
+static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED;
+
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
return netdev_priv(dev);
@@ -1078,25 +1114,53 @@ static int phy_init(struct net_device *dev)
}
}
if (np->phy_oui == PHY_OUI_REALTEK) {
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
+ if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
+ np->phy_rev == PHY_REV_REALTEK_8211B) {
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
}
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
+ if (np->phy_model == PHY_MODEL_REALTEK_8201) {
+ if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
+ phy_reserved |= PHY_REALTEK_INIT7;
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
}
}
@@ -1236,26 +1300,71 @@ static int phy_init(struct net_device *dev)
}
}
if (np->phy_oui == PHY_OUI_REALTEK) {
- /* reset could have cleared these out, set them back */
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
- }
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
+ if (np->phy_model == PHY_MODEL_REALTEK_8211 &&
+ np->phy_rev == PHY_REV_REALTEK_8211B) {
+ /* reset could have cleared these out, set them back */
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
}
- if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
- printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
- return PHY_ERROR;
+ if (np->phy_model == PHY_MODEL_REALTEK_8201) {
+ if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
+ np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
+ phy_reserved |= PHY_REALTEK_INIT7;
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
+ if (phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ);
+ phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
+ phy_reserved |= PHY_REALTEK_INIT3;
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
}
}
@@ -1769,6 +1878,115 @@ static inline u32 nv_get_empty_tx_slots(struct fe_priv *np)
return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
}
+static void nv_legacybackoff_reseed(struct net_device *dev)
+{
+ u8 __iomem *base = get_hwbase(dev);
+ u32 reg;
+ u32 low;
+ int tx_status = 0;
+
+ reg = readl(base + NvRegSlotTime) & ~NVREG_SLOTTIME_MASK;
+ get_random_bytes(&low, sizeof(low));
+ reg |= low & NVREG_SLOTTIME_MASK;
+
+ /* Need to stop tx before change takes effect.
+ * Caller has already gained np->lock.
+ */
+ tx_status = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START;
+ if (tx_status)
+ nv_stop_tx(dev);
+ nv_stop_rx(dev);
+ writel(reg, base + NvRegSlotTime);
+ if (tx_status)
+ nv_start_tx(dev);
+ nv_start_rx(dev);
+}
+
+/* Gear Backoff Seeds */
+#define BACKOFF_SEEDSET_ROWS 8
+#define BACKOFF_SEEDSET_LFSRS 15
+
+/* Known Good seed sets */
+static const u32 main_seedset[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] = {
+ {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
+ {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 385, 761, 790, 974},
+ {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874},
+ {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 386, 761, 790, 974},
+ {266, 265, 276, 585, 397, 208, 345, 355, 365, 376, 385, 396, 771, 700, 984},
+ {266, 265, 276, 586, 397, 208, 346, 355, 365, 376, 285, 396, 771, 700, 984},
+ {366, 365, 376, 686, 497, 308, 447, 455, 466, 476, 485, 496, 871, 800, 84},
+ {466, 465, 476, 786, 597, 408, 547, 555, 566, 576, 585, 597, 971, 900, 184}};
+
+static const u32 gear_seedset[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] = {
+ {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 397},
+ {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
+ {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395},
+ {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}};
+
+static void nv_gear_backoff_reseed(struct net_device *dev)
+{
+ u8 __iomem *base = get_hwbase(dev);
+ u32 miniseed1, miniseed2, miniseed2_reversed, miniseed3, miniseed3_reversed;
+ u32 temp, seedset, combinedSeed;
+ int i;
+
+ /* Setup seed for free running LFSR */
+ /* We are going to read the time stamp counter 3 times
+ and swizzle bits around to increase randomness */
+ get_random_bytes(&miniseed1, sizeof(miniseed1));
+ miniseed1 &= 0x0fff;
+ if (miniseed1 == 0)
+ miniseed1 = 0xabc;
+
+ get_random_bytes(&miniseed2, sizeof(miniseed2));
+ miniseed2 &= 0x0fff;
+ if (miniseed2 == 0)
+ miniseed2 = 0xabc;
+ miniseed2_reversed =
+ ((miniseed2 & 0xF00) >> 8) |
+ (miniseed2 & 0x0F0) |
+ ((miniseed2 & 0x00F) << 8);
+
+ get_random_bytes(&miniseed3, sizeof(miniseed3));
+ miniseed3 &= 0x0fff;
+ if (miniseed3 == 0)
+ miniseed3 = 0xabc;
+ miniseed3_reversed =
+ ((miniseed3 & 0xF00) >> 8) |
+ (miniseed3 & 0x0F0) |
+ ((miniseed3 & 0x00F) << 8);
+
+ combinedSeed = ((miniseed1 ^ miniseed2_reversed) << 12) |
+ (miniseed2 ^ miniseed3_reversed);
+
+ /* Seeds can not be zero */
+ if ((combinedSeed & NVREG_BKOFFCTRL_SEED_MASK) == 0)
+ combinedSeed |= 0x08;
+ if ((combinedSeed & (NVREG_BKOFFCTRL_SEED_MASK << NVREG_BKOFFCTRL_GEAR)) == 0)
+ combinedSeed |= 0x8000;
+
+ /* No need to disable tx here */
+ temp = NVREG_BKOFFCTRL_DEFAULT | (0 << NVREG_BKOFFCTRL_SELECT);
+ temp |= combinedSeed & NVREG_BKOFFCTRL_SEED_MASK;
+ temp |= combinedSeed >> NVREG_BKOFFCTRL_GEAR;
+ writel(temp,base + NvRegBackOffControl);
+
+ /* Setup seeds for all gear LFSRs. */
+ get_random_bytes(&seedset, sizeof(seedset));
+ seedset = seedset % BACKOFF_SEEDSET_ROWS;
+ for (i = 1; i <= BACKOFF_SEEDSET_LFSRS; i++)
+ {
+ temp = NVREG_BKOFFCTRL_DEFAULT | (i << NVREG_BKOFFCTRL_SELECT);
+ temp |= main_seedset[seedset][i-1] & 0x3ff;
+ temp |= ((gear_seedset[seedset][i-1] & 0x3ff) << NVREG_BKOFFCTRL_GEAR);
+ writel(temp, base + NvRegBackOffControl);
+ }
+}
+
/*
* nv_start_xmit: dev->hard_start_xmit function
* Called with netif_tx_lock held.
@@ -2088,6 +2306,8 @@ static void nv_tx_done(struct net_device *dev)
dev->stats.tx_fifo_errors++;
if (flags & NV_TX_CARRIERLOST)
dev->stats.tx_carrier_errors++;
+ if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK))
+ nv_legacybackoff_reseed(dev);
dev->stats.tx_errors++;
} else {
dev->stats.tx_packets++;
@@ -2103,6 +2323,8 @@ static void nv_tx_done(struct net_device *dev)
dev->stats.tx_fifo_errors++;
if (flags & NV_TX2_CARRIERLOST)
dev->stats.tx_carrier_errors++;
+ if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK))
+ nv_legacybackoff_reseed(dev);
dev->stats.tx_errors++;
} else {
dev->stats.tx_packets++;
@@ -2144,6 +2366,15 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit)
if (flags & NV_TX2_LASTPACKET) {
if (!(flags & NV_TX2_ERROR))
dev->stats.tx_packets++;
+ else {
+ if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) {
+ if (np->driver_data & DEV_HAS_GEAR_MODE)
+ nv_gear_backoff_reseed(dev);
+ else
+ nv_legacybackoff_reseed(dev);
+ }
+ }
+
dev_kfree_skb_any(np->get_tx_ctx->skb);
np->get_tx_ctx->skb = NULL;
@@ -2905,15 +3136,14 @@ set_speed:
}
if (np->gigabit == PHY_GIGABIT) {
- phyreg = readl(base + NvRegRandomSeed);
+ phyreg = readl(base + NvRegSlotTime);
phyreg &= ~(0x3FF00);
- if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
- phyreg |= NVREG_RNDSEED_FORCE3;
- else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
- phyreg |= NVREG_RNDSEED_FORCE2;
+ if (((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) ||
+ ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100))
+ phyreg |= NVREG_SLOTTIME_10_100_FULL;
else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
- phyreg |= NVREG_RNDSEED_FORCE;
- writel(phyreg, base + NvRegRandomSeed);
+ phyreg |= NVREG_SLOTTIME_1000_FULL;
+ writel(phyreg, base + NvRegSlotTime);
}
phyreg = readl(base + NvRegPhyInterface);
@@ -4843,6 +5073,7 @@ static int nv_open(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
int ret = 1;
int oom, i;
+ u32 low;
dprintk(KERN_DEBUG "nv_open: begin\n");
@@ -4902,8 +5133,20 @@ static int nv_open(struct net_device *dev)
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
- get_random_bytes(&i, sizeof(i));
- writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
+
+ get_random_bytes(&low, sizeof(low));
+ low &= NVREG_SLOTTIME_MASK;
+ if (np->desc_ver == DESC_VER_1) {
+ writel(low|NVREG_SLOTTIME_DEFAULT, base + NvRegSlotTime);
+ } else {
+ if (!(np->driver_data & DEV_HAS_GEAR_MODE)) {
+ /* setup legacy backoff */
+ writel(NVREG_SLOTTIME_LEGBF_ENABLED|NVREG_SLOTTIME_10_100_FULL|low, base + NvRegSlotTime);
+ } else {
+ writel(NVREG_SLOTTIME_10_100_FULL, base + NvRegSlotTime);
+ nv_gear_backoff_reseed(dev);
+ }
+ }
writel(NVREG_TX_DEFERRAL_DEFAULT, base + NvRegTxDeferral);
writel(NVREG_RX_DEFERRAL_DEFAULT, base + NvRegRxDeferral);
if (poll_interval == -1) {
@@ -5110,6 +5353,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
/* copy of driver data */
np->driver_data = id->driver_data;
+ /* copy of device id */
+ np->device_id = id->device;
/* handle different descriptor versions */
if (id->driver_data & DEV_HAS_HIGH_DMA) {
@@ -5399,6 +5644,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
pci_name(pci_dev), id1, id2, phyaddr);
np->phyaddr = phyaddr;
np->phy_oui = id1 | id2;
+
+ /* Realtek hardcoded phy id1 to all zero's on certain phys */
+ if (np->phy_oui == PHY_OUI_REALTEK2)
+ np->phy_oui = PHY_OUI_REALTEK;
+ /* Setup phy revision for Realtek */
+ if (np->phy_oui == PHY_OUI_REALTEK && np->phy_model == PHY_MODEL_REALTEK_8211)
+ np->phy_rev = mii_rw(dev, phyaddr, MII_RESV1, MII_READ) & PHY_REV_MASK;
+
break;
}
if (i == 33) {
@@ -5477,6 +5730,28 @@ out:
return err;
}
+static void nv_restore_phy(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u16 phy_reserved, mii_control;
+
+ if (np->phy_oui == PHY_OUI_REALTEK &&
+ np->phy_model == PHY_MODEL_REALTEK_8201 &&
+ phy_cross == NV_CROSSOVER_DETECTION_DISABLED) {
+ mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3);
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ);
+ phy_reserved &= ~PHY_REALTEK_INIT_MSK1;
+ phy_reserved |= PHY_REALTEK_INIT8;
+ mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved);
+ mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1);
+
+ /* restart auto negotiation */
+ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
+ mii_rw(dev, np->phyaddr, MII_BMCR, mii_control);
+ }
+}
+
static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
@@ -5493,6 +5768,9 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV,
base + NvRegTransmitPoll);
+ /* restore any phy related changes */
+ nv_restore_phy(dev);
+
/* free all structures */
free_rings(dev);
iounmap(get_hwbase(dev));
@@ -5632,83 +5910,83 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{0,},
};
@@ -5744,6 +6022,8 @@ module_param(msix, int, 0);
MODULE_PARM_DESC(msix, "MSIX interrupts are enabled by setting to 1 and disabled by setting to 0.");
module_param(dma_64bit, int, 0);
MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0.");
+module_param(phy_cross, int, 0);
+MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0.");
MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index c8c3df737d73..99a4b990939f 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -98,7 +98,6 @@
#include "gianfar_mii.h"
#define TX_TIMEOUT (1*HZ)
-#define SKB_ALLOC_TIMEOUT 1000000
#undef BRIEF_GFAR_ERRORS
#undef VERBOSE_GFAR_ERRORS
@@ -115,7 +114,9 @@ static int gfar_enet_open(struct net_device *dev);
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
static int gfar_close(struct net_device *dev);
-struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
+struct sk_buff *gfar_new_skb(struct net_device *dev);
+static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+ struct sk_buff *skb);
static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -783,14 +784,21 @@ int startup_gfar(struct net_device *dev)
rxbdp = priv->rx_bd_base;
for (i = 0; i < priv->rx_ring_size; i++) {
- struct sk_buff *skb = NULL;
+ struct sk_buff *skb;
- rxbdp->status = 0;
+ skb = gfar_new_skb(dev);
- skb = gfar_new_skb(dev, rxbdp);
+ if (!skb) {
+ printk(KERN_ERR "%s: Can't allocate RX buffers\n",
+ dev->name);
+
+ goto err_rxalloc_fail;
+ }
priv->rx_skbuff[i] = skb;
+ gfar_new_rxbdp(dev, rxbdp, skb);
+
rxbdp++;
}
@@ -916,6 +924,7 @@ rx_irq_fail:
tx_irq_fail:
free_irq(priv->interruptError, dev);
err_irq_fail:
+err_rxalloc_fail:
rx_skb_fail:
free_skb_resources(priv);
tx_skb_fail:
@@ -1328,18 +1337,37 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
return IRQ_HANDLED;
}
-struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
+static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+ struct sk_buff *skb)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ u32 * status_len = (u32 *)bdp;
+ u16 flags;
+
+ bdp->bufPtr = dma_map_single(&dev->dev, skb->data,
+ priv->rx_buffer_size, DMA_FROM_DEVICE);
+
+ flags = RXBD_EMPTY | RXBD_INTERRUPT;
+
+ if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
+ flags |= RXBD_WRAP;
+
+ eieio();
+
+ *status_len = (u32)flags << 16;
+}
+
+
+struct sk_buff * gfar_new_skb(struct net_device *dev)
{
unsigned int alignamount;
struct gfar_private *priv = netdev_priv(dev);
struct sk_buff *skb = NULL;
- unsigned int timeout = SKB_ALLOC_TIMEOUT;
/* We have to allocate the skb, so keep trying till we succeed */
- while ((!skb) && timeout--)
- skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT);
+ skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT);
- if (NULL == skb)
+ if (!skb)
return NULL;
alignamount = RXBUF_ALIGNMENT -
@@ -1350,15 +1378,6 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
*/
skb_reserve(skb, alignamount);
- bdp->bufPtr = dma_map_single(&dev->dev, skb->data,
- priv->rx_buffer_size, DMA_FROM_DEVICE);
-
- bdp->length = 0;
-
- /* Mark the buffer empty */
- eieio();
- bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT);
-
return skb;
}
@@ -1544,10 +1563,31 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
bdp = priv->cur_rx;
while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
+ struct sk_buff *newskb;
rmb();
+
+ /* Add another skb for the future */
+ newskb = gfar_new_skb(dev);
+
skb = priv->rx_skbuff[priv->skb_currx];
- if ((bdp->status & RXBD_LAST) && !(bdp->status & RXBD_ERR)) {
+ /* We drop the frame if we failed to allocate a new buffer */
+ if (unlikely(!newskb || !(bdp->status & RXBD_LAST) ||
+ bdp->status & RXBD_ERR)) {
+ count_errors(bdp->status, dev);
+
+ if (unlikely(!newskb))
+ newskb = skb;
+
+ if (skb) {
+ dma_unmap_single(&priv->dev->dev,
+ bdp->bufPtr,
+ priv->rx_buffer_size,
+ DMA_FROM_DEVICE);
+
+ dev_kfree_skb_any(skb);
+ }
+ } else {
/* Increment the number of packets */
dev->stats.rx_packets++;
howmany++;
@@ -1558,23 +1598,14 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
gfar_process_frame(dev, skb, pkt_len);
dev->stats.rx_bytes += pkt_len;
- } else {
- count_errors(bdp->status, dev);
-
- if (skb)
- dev_kfree_skb_any(skb);
-
- priv->rx_skbuff[priv->skb_currx] = NULL;
}
dev->last_rx = jiffies;
- /* Clear the status flags for this buffer */
- bdp->status &= ~RXBD_STATS;
+ priv->rx_skbuff[priv->skb_currx] = newskb;
- /* Add another skb for the future */
- skb = gfar_new_skb(dev, bdp);
- priv->rx_skbuff[priv->skb_currx] = skb;
+ /* Setup the new bdp */
+ gfar_new_rxbdp(dev, bdp, newskb);
/* Update to the next pointer */
if (bdp->status & RXBD_WRAP)
@@ -1584,9 +1615,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
/* update to point at the next skb */
priv->skb_currx =
- (priv->skb_currx +
- 1) & RX_RING_MOD_MASK(priv->rx_ring_size);
-
+ (priv->skb_currx + 1) &
+ RX_RING_MOD_MASK(priv->rx_ring_size);
}
/* Update the current rxbd pointer to be the next one */
@@ -2001,12 +2031,16 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:fsl-gianfar");
+
/* Structure for a device driver */
static struct platform_driver gfar_driver = {
.probe = gfar_probe,
.remove = gfar_remove,
.driver = {
.name = "fsl-gianfar",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 378a23963495..5d2108c5ac7c 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -43,6 +43,8 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
#include "core.h"
@@ -127,10 +129,35 @@ static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE];
static inline void emac_report_timeout_error(struct emac_instance *dev,
const char *error)
{
- if (net_ratelimit())
+ if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX |
+ EMAC_FTR_440EP_PHY_CLK_FIX))
+ DBG(dev, "%s" NL, error);
+ else if (net_ratelimit())
printk(KERN_ERR "%s: %s\n", dev->ndev->name, error);
}
+/* EMAC PHY clock workaround:
+ * 440EP/440GR has more sane SDR0_MFR register implementation than 440GX,
+ * which allows controlling each EMAC clock
+ */
+static inline void emac_rx_clk_tx(struct emac_instance *dev)
+{
+#ifdef CONFIG_PPC_DCR_NATIVE
+ if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_MFR,
+ 0, SDR0_MFR_ECS >> dev->cell_index);
+#endif
+}
+
+static inline void emac_rx_clk_default(struct emac_instance *dev)
+{
+#ifdef CONFIG_PPC_DCR_NATIVE
+ if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_MFR,
+ SDR0_MFR_ECS >> dev->cell_index, 0);
+#endif
+}
+
/* PHY polling intervals */
#define PHY_POLL_LINK_ON HZ
#define PHY_POLL_LINK_OFF (HZ / 5)
@@ -524,7 +551,10 @@ static int emac_configure(struct emac_instance *dev)
rx_size = dev->rx_fifo_size_gige;
if (dev->ndev->mtu > ETH_DATA_LEN) {
- mr1 |= EMAC_MR1_JPSM;
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ mr1 |= EMAC4_MR1_JPSM;
+ else
+ mr1 |= EMAC_MR1_JPSM;
dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
} else
dev->stop_timeout = STOP_TIMEOUT_1000;
@@ -708,7 +738,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
/* Wait for management interface to become idle */
- n = 10;
+ n = 20;
while (!emac_phy_done(dev, in_be32(&p->stacr))) {
udelay(1);
if (!--n) {
@@ -733,7 +763,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
out_be32(&p->stacr, r);
/* Wait for read to complete */
- n = 100;
+ n = 200;
while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) {
udelay(1);
if (!--n) {
@@ -780,7 +810,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
/* Wait for management interface to be idle */
- n = 10;
+ n = 20;
while (!emac_phy_done(dev, in_be32(&p->stacr))) {
udelay(1);
if (!--n) {
@@ -806,7 +836,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
out_be32(&p->stacr, r);
/* Wait for write to complete */
- n = 100;
+ n = 200;
while (!emac_phy_done(dev, in_be32(&p->stacr))) {
udelay(1);
if (!--n) {
@@ -1094,9 +1124,11 @@ static int emac_open(struct net_device *ndev)
int link_poll_interval;
if (dev->phy.def->ops->poll_link(&dev->phy)) {
dev->phy.def->ops->read_link(&dev->phy);
+ emac_rx_clk_default(dev);
netif_carrier_on(dev->ndev);
link_poll_interval = PHY_POLL_LINK_ON;
} else {
+ emac_rx_clk_tx(dev);
netif_carrier_off(dev->ndev);
link_poll_interval = PHY_POLL_LINK_OFF;
}
@@ -1174,6 +1206,7 @@ static void emac_link_timer(struct work_struct *work)
if (dev->phy.def->ops->poll_link(&dev->phy)) {
if (!netif_carrier_ok(dev->ndev)) {
+ emac_rx_clk_default(dev);
/* Get new link parameters */
dev->phy.def->ops->read_link(&dev->phy);
@@ -1186,6 +1219,7 @@ static void emac_link_timer(struct work_struct *work)
link_poll_interval = PHY_POLL_LINK_ON;
} else {
if (netif_carrier_ok(dev->ndev)) {
+ emac_rx_clk_tx(dev);
netif_carrier_off(dev->ndev);
netif_tx_disable(dev->ndev);
emac_reinitialize(dev);
@@ -2237,7 +2271,7 @@ static int __devinit emac_of_bus_notify(struct notifier_block *nb,
return 0;
}
-static struct notifier_block emac_of_bus_notifier = {
+static struct notifier_block emac_of_bus_notifier __devinitdata = {
.notifier_call = emac_of_bus_notify
};
@@ -2330,6 +2364,19 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
dev->phy.mdio_read = emac_mdio_read;
dev->phy.mdio_write = emac_mdio_write;
+ /* Enable internal clock source */
+#ifdef CONFIG_PPC_DCR_NATIVE
+ if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS);
+#endif
+ /* PHY clock workaround */
+ emac_rx_clk_tx(dev);
+
+ /* Enable internal clock source on 440GX*/
+#ifdef CONFIG_PPC_DCR_NATIVE
+ if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS);
+#endif
/* Configure EMAC with defaults so we can at least use MDIO
* This is needed mostly for 440GX
*/
@@ -2362,6 +2409,12 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
if (!emac_mii_phy_probe(&dev->phy, i))
break;
}
+
+ /* Enable external clock source */
+#ifdef CONFIG_PPC_DCR_NATIVE
+ if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX))
+ dcri_clrset(SDR0, SDR0_MFR, SDR0_MFR_ECS, 0);
+#endif
mutex_unlock(&emac_phy_map_lock);
if (i == 0x20) {
printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);
@@ -2487,8 +2540,15 @@ static int __devinit emac_init_config(struct emac_instance *dev)
}
/* Check EMAC version */
- if (of_device_is_compatible(np, "ibm,emac4"))
+ if (of_device_is_compatible(np, "ibm,emac4")) {
dev->features |= EMAC_FTR_EMAC4;
+ if (of_device_is_compatible(np, "ibm,emac-440gx"))
+ dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX;
+ } else {
+ if (of_device_is_compatible(np, "ibm,emac-440ep") ||
+ of_device_is_compatible(np, "ibm,emac-440gr"))
+ dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
+ }
/* Fixup some feature bits based on the device tree */
if (of_get_property(np, "has-inverted-stacr-oc", NULL))
@@ -2559,8 +2619,11 @@ static int __devinit emac_probe(struct of_device *ofdev,
struct device_node **blist = NULL;
int err, i;
- /* Skip unused/unwired EMACS */
- if (of_get_property(np, "unused", NULL))
+ /* Skip unused/unwired EMACS. We leave the check for an unused
+ * property here for now, but new flat device trees should set a
+ * status property to "disabled" instead.
+ */
+ if (of_get_property(np, "unused", NULL) || !of_device_is_available(np))
return -ENODEV;
/* Find ourselves in the bootlist if we are there */
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index 4e74d8287c65..1683db9870a4 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -301,6 +301,14 @@ struct emac_instance {
* Set if we have new type STACR with STAOPC
*/
#define EMAC_FTR_HAS_NEW_STACR 0x00000040
+/*
+ * Set if we need phy clock workaround for 440gx
+ */
+#define EMAC_FTR_440GX_PHY_CLK_FIX 0x00000080
+/*
+ * Set if we need phy clock workaround for 440ep or 440gr
+ */
+#define EMAC_FTR_440EP_PHY_CLK_FIX 0x00000100
/* Right now, we don't quite handle the always/possible masks on the
@@ -312,8 +320,8 @@ enum {
EMAC_FTRS_POSSIBLE =
#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
- EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR |
- EMAC_FTR_STACR_OC_INVERT |
+ EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR |
+ EMAC_FTR_STACR_OC_INVERT | EMAC_FTR_440GX_PHY_CLK_FIX |
#endif
#ifdef CONFIG_IBM_NEW_EMAC_TAH
EMAC_FTR_HAS_TAH |
@@ -324,7 +332,7 @@ enum {
#ifdef CONFIG_IBM_NEW_EMAC_RGMII
EMAC_FTR_HAS_RGMII |
#endif
- 0,
+ EMAC_FTR_440EP_PHY_CLK_FIX,
};
static inline int emac_has_feature(struct emac_instance *dev,
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 6869f08c9dcb..10c267b2b961 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -61,8 +61,8 @@ int __devinit mal_register_commac(struct mal_instance *mal,
return 0;
}
-void __devexit mal_unregister_commac(struct mal_instance *mal,
- struct mal_commac *commac)
+void mal_unregister_commac(struct mal_instance *mal,
+ struct mal_commac *commac)
{
unsigned long flags;
@@ -136,6 +136,14 @@ void mal_enable_rx_channel(struct mal_instance *mal, int channel)
{
unsigned long flags;
+ /*
+ * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple
+ * of 8, but enabling in MAL_RXCASR needs the divided by 8 value
+ * for the bitmask
+ */
+ if (!(channel % 8))
+ channel >>= 3;
+
spin_lock_irqsave(&mal->lock, flags);
MAL_DBG(mal, "enable_rx(%d)" NL, channel);
@@ -148,6 +156,14 @@ void mal_enable_rx_channel(struct mal_instance *mal, int channel)
void mal_disable_rx_channel(struct mal_instance *mal, int channel)
{
+ /*
+ * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple
+ * of 8, but enabling in MAL_RXCASR needs the divided by 8 value
+ * for the bitmask
+ */
+ if (!(channel % 8))
+ channel >>= 3;
+
set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel));
MAL_DBG(mal, "disable_rx(%d)" NL, channel);
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
index 5757788227be..e32da3de2695 100644
--- a/drivers/net/ibm_newemac/rgmii.c
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -179,7 +179,7 @@ void rgmii_put_mdio(struct of_device *ofdev, int input)
mutex_unlock(&dev->lock);
}
-void __devexit rgmii_detach(struct of_device *ofdev, int input)
+void rgmii_detach(struct of_device *ofdev, int input)
{
struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
struct rgmii_regs __iomem *p = dev->base;
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
index b023d10d7e1c..30173a9fb557 100644
--- a/drivers/net/ibm_newemac/tah.c
+++ b/drivers/net/ibm_newemac/tah.c
@@ -35,7 +35,7 @@ int __devinit tah_attach(struct of_device *ofdev, int channel)
return 0;
}
-void __devexit tah_detach(struct of_device *ofdev, int channel)
+void tah_detach(struct of_device *ofdev, int channel)
{
struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
index 2ea472aeab06..17b154124943 100644
--- a/drivers/net/ibm_newemac/zmii.c
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -189,7 +189,7 @@ void zmii_set_speed(struct of_device *ofdev, int input, int speed)
mutex_unlock(&dev->lock);
}
-void __devexit zmii_detach(struct of_device *ofdev, int input)
+void zmii_detach(struct of_device *ofdev, int input)
{
struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index aaee02e9e3f0..ae398f04c7b4 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -871,6 +871,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
goto err_pci_reg;
pci_set_master(pdev);
+ pci_save_state(pdev);
err = -ENOMEM;
netdev = alloc_etherdev(sizeof(struct igb_adapter));
@@ -4079,6 +4080,7 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
+ pci_restore_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 9f584521304a..083b0dd70fef 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -60,6 +60,7 @@ static struct platform_driver ali_ircc_driver = {
.resume = ali_ircc_resume,
.driver = {
.name = ALI_IRCC_DRIVER_NAME,
+ .owner = THIS_MODULE,
},
};
@@ -2256,6 +2257,7 @@ static void FIR2SIR(int iobase)
MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>");
MODULE_DESCRIPTION("ALi FIR Controller Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" ALI_IRCC_DRIVER_NAME);
module_param_array(io, int, NULL, 0);
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 8db71ab20456..d5c2d27f3ea4 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -908,6 +908,7 @@ static int pxa_irda_remove(struct platform_device *_dev)
static struct platform_driver pxa_ir_driver = {
.driver = {
.name = "pxa2xx-ir",
+ .owner = THIS_MODULE,
},
.probe = pxa_irda_probe,
.remove = pxa_irda_remove,
@@ -929,3 +930,4 @@ module_init(pxa_irda_init);
module_exit(pxa_irda_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-ir");
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 056639f72bec..1bc8518f9197 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -1008,6 +1008,7 @@ static struct platform_driver sa1100ir_driver = {
.resume = sa1100_irda_resume,
.driver = {
.name = "sa11x0-ir",
+ .owner = THIS_MODULE,
},
};
@@ -1041,3 +1042,4 @@ MODULE_LICENSE("GPL");
MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)");
MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode");
MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)");
+MODULE_ALIAS("platform:sa11x0-ir");
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index cb371a8c24a7..7b859220c255 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -3431,6 +3431,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
}
pci_set_master(pdev);
+ pci_save_state(pdev);
#ifdef CONFIG_NETDEVICES_MULTIQUEUE
netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), MAX_TX_QUEUES);
@@ -3721,6 +3722,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
+ pci_restore_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 5c154fe13859..07944820f745 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -249,6 +249,7 @@ out:
MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
+MODULE_ALIAS("platform:jazzsonic");
#include "sonic.c"
@@ -271,6 +272,7 @@ static struct platform_driver jazz_sonic_driver = {
.remove = __devexit_p(jazz_sonic_device_remove),
.driver = {
.name = jazz_sonic_string,
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index 1d24a73a0e1a..e18576316bda 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -883,7 +883,7 @@ static int korina_init(struct net_device *dev)
static int korina_restart(struct net_device *dev)
{
struct korina_private *lp = netdev_priv(dev);
- int ret = 0;
+ int ret;
/*
* Disable interrupts
@@ -987,7 +987,7 @@ static void korina_poll_controller(struct net_device *dev)
static int korina_open(struct net_device *dev)
{
struct korina_private *lp = netdev_priv(dev);
- int ret = 0;
+ int ret;
/* Initialize */
ret = korina_init(dev);
@@ -1031,6 +1031,8 @@ static int korina_open(struct net_device *dev)
dev->name, lp->und_irq);
goto err_free_ovr_irq;
}
+out:
+ return ret;
err_free_ovr_irq:
free_irq(lp->ovr_irq, dev);
@@ -1041,8 +1043,6 @@ err_free_rx_irq:
err_release:
korina_free_ring(dev);
goto out;
-out:
- return ret;
}
static int korina_close(struct net_device *dev)
@@ -1082,7 +1082,7 @@ static int korina_probe(struct platform_device *pdev)
struct korina_private *lp;
struct net_device *dev;
struct resource *r;
- int retval, err;
+ int rc;
dev = alloc_etherdev(sizeof(struct korina_private));
if (!dev) {
@@ -1106,7 +1106,7 @@ static int korina_probe(struct platform_device *pdev)
lp->eth_regs = ioremap_nocache(r->start, r->end - r->start);
if (!lp->eth_regs) {
printk(KERN_ERR DRV_NAME "cannot remap registers\n");
- retval = -ENXIO;
+ rc = -ENXIO;
goto probe_err_out;
}
@@ -1114,7 +1114,7 @@ static int korina_probe(struct platform_device *pdev)
lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start);
if (!lp->rx_dma_regs) {
printk(KERN_ERR DRV_NAME "cannot remap Rx DMA registers\n");
- retval = -ENXIO;
+ rc = -ENXIO;
goto probe_err_dma_rx;
}
@@ -1122,14 +1122,14 @@ static int korina_probe(struct platform_device *pdev)
lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start);
if (!lp->tx_dma_regs) {
printk(KERN_ERR DRV_NAME "cannot remap Tx DMA registers\n");
- retval = -ENXIO;
+ rc = -ENXIO;
goto probe_err_dma_tx;
}
lp->td_ring = kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL);
if (!lp->td_ring) {
printk(KERN_ERR DRV_NAME "cannot allocate descriptors\n");
- retval = -ENOMEM;
+ rc = -ENXIO;
goto probe_err_td_ring;
}
@@ -1166,14 +1166,14 @@ static int korina_probe(struct platform_device *pdev)
lp->mii_if.phy_id_mask = 0x1f;
lp->mii_if.reg_num_mask = 0x1f;
- err = register_netdev(dev);
- if (err) {
+ rc = register_netdev(dev);
+ if (rc < 0) {
printk(KERN_ERR DRV_NAME
- ": cannot register net device %d\n", err);
- retval = -EINVAL;
+ ": cannot register net device %d\n", rc);
goto probe_err_register;
}
- return 0;
+out:
+ return rc;
probe_err_register:
kfree(lp->td_ring);
@@ -1185,7 +1185,7 @@ probe_err_dma_rx:
iounmap(lp->eth_regs);
probe_err_out:
free_netdev(dev);
- return retval;
+ goto out;
}
static int korina_remove(struct platform_device *pdev)
@@ -1193,12 +1193,9 @@ static int korina_remove(struct platform_device *pdev)
struct korina_device *bif = platform_get_drvdata(pdev);
struct korina_private *lp = netdev_priv(bif->dev);
- if (lp->eth_regs)
- iounmap(lp->eth_regs);
- if (lp->rx_dma_regs)
- iounmap(lp->rx_dma_regs);
- if (lp->tx_dma_regs)
- iounmap(lp->tx_dma_regs);
+ iounmap(lp->eth_regs);
+ iounmap(lp->rx_dma_regs);
+ iounmap(lp->tx_dma_regs);
platform_set_drvdata(pdev, NULL);
unregister_netdev(bif->dev);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index d513bb8a4902..92dccd43bdca 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -1281,6 +1281,7 @@ static struct platform_driver macb_driver = {
.remove = __exit_p(macb_remove),
.driver = {
.name = "macb",
+ .owner = THIS_MODULE,
},
};
@@ -1300,3 +1301,4 @@ module_exit(macb_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel MACB Ethernet driver");
MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_ALIAS("platform:macb");
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index cdaa8fc21809..0b32648a2136 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -830,6 +830,7 @@ static struct platform_driver meth_driver = {
.remove = __devexit_p(meth_remove),
.driver = {
.name = "meth",
+ .owner = THIS_MODULE,
}
};
@@ -855,3 +856,4 @@ module_exit(meth_exit_module);
MODULE_AUTHOR("Ilya Volynets <ilya@theIlya.com>");
MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:meth");
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index 75ef9d0d974d..f9d6b4dca180 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -196,3 +196,160 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
}
}
EXPORT_SYMBOL_GPL(mlx4_buf_free);
+
+static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device)
+{
+ struct mlx4_db_pgdir *pgdir;
+
+ pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL);
+ if (!pgdir)
+ return NULL;
+
+ bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2);
+ pgdir->bits[0] = pgdir->order0;
+ pgdir->bits[1] = pgdir->order1;
+ pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE,
+ &pgdir->db_dma, GFP_KERNEL);
+ if (!pgdir->db_page) {
+ kfree(pgdir);
+ return NULL;
+ }
+
+ return pgdir;
+}
+
+static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir,
+ struct mlx4_db *db, int order)
+{
+ int o;
+ int i;
+
+ for (o = order; o <= 1; ++o) {
+ i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o);
+ if (i < MLX4_DB_PER_PAGE >> o)
+ goto found;
+ }
+
+ return -ENOMEM;
+
+found:
+ clear_bit(i, pgdir->bits[o]);
+
+ i <<= o;
+
+ if (o > order)
+ set_bit(i ^ 1, pgdir->bits[order]);
+
+ db->u.pgdir = pgdir;
+ db->index = i;
+ db->db = pgdir->db_page + db->index;
+ db->dma = pgdir->db_dma + db->index * 4;
+ db->order = order;
+
+ return 0;
+}
+
+int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_db_pgdir *pgdir;
+ int ret = 0;
+
+ mutex_lock(&priv->pgdir_mutex);
+
+ list_for_each_entry(pgdir, &priv->pgdir_list, list)
+ if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
+ goto out;
+
+ pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev));
+ if (!pgdir) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ list_add(&pgdir->list, &priv->pgdir_list);
+
+ /* This should never fail -- we just allocated an empty page: */
+ WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order));
+
+out:
+ mutex_unlock(&priv->pgdir_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mlx4_db_alloc);
+
+void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int o;
+ int i;
+
+ mutex_lock(&priv->pgdir_mutex);
+
+ o = db->order;
+ i = db->index;
+
+ if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) {
+ clear_bit(i ^ 1, db->u.pgdir->order0);
+ ++o;
+ }
+ i >>= o;
+ set_bit(i, db->u.pgdir->bits[o]);
+
+ if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) {
+ dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
+ db->u.pgdir->db_page, db->u.pgdir->db_dma);
+ list_del(&db->u.pgdir->list);
+ kfree(db->u.pgdir);
+ }
+
+ mutex_unlock(&priv->pgdir_mutex);
+}
+EXPORT_SYMBOL_GPL(mlx4_db_free);
+
+int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
+ int size, int max_direct)
+{
+ int err;
+
+ err = mlx4_db_alloc(dev, &wqres->db, 1);
+ if (err)
+ return err;
+
+ *wqres->db.db = 0;
+
+ err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf);
+ if (err)
+ goto err_db;
+
+ err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift,
+ &wqres->mtt);
+ if (err)
+ goto err_buf;
+
+ err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf);
+ if (err)
+ goto err_mtt;
+
+ return 0;
+
+err_mtt:
+ mlx4_mtt_cleanup(dev, &wqres->mtt);
+err_buf:
+ mlx4_buf_free(dev, size, &wqres->buf);
+err_db:
+ mlx4_db_free(dev, &wqres->db);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res);
+
+void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
+ int size)
+{
+ mlx4_mtt_cleanup(dev, &wqres->mtt);
+ mlx4_buf_free(dev, size, &wqres->buf);
+ mlx4_db_free(dev, &wqres->db);
+}
+EXPORT_SYMBOL_GPL(mlx4_free_hwq_res);
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index caa5bcf54e35..6fda0af9d0a6 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -180,7 +180,7 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq,
cq_context->mtt_base_addr_h = mtt_addr >> 32;
cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
- err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1);
+ err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 0);
mlx4_free_cmd_mailbox(dev, mailbox);
return err;
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 49a4acab5e82..a6aa49fc1d68 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -798,6 +798,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&priv->ctx_list);
spin_lock_init(&priv->ctx_lock);
+ INIT_LIST_HEAD(&priv->pgdir_list);
+ mutex_init(&priv->pgdir_mutex);
+
/*
* Now reset the HCA before we touch the PCI capabilities or
* attempt a firmware command, since a boot ROM may have left
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 73336810e652..a4023c2dd050 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -257,6 +257,9 @@ struct mlx4_priv {
struct list_head ctx_list;
spinlock_t ctx_lock;
+ struct list_head pgdir_list;
+ struct mutex pgdir_mutex;
+
struct mlx4_fw fw;
struct mlx4_cmd cmd;
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index fa24e6597591..ee5484c44a18 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -299,3 +299,34 @@ int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
}
EXPORT_SYMBOL_GPL(mlx4_qp_query);
+int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+ struct mlx4_qp_context *context,
+ struct mlx4_qp *qp, enum mlx4_qp_state *qp_state)
+{
+ int err;
+ int i;
+ enum mlx4_qp_state states[] = {
+ MLX4_QP_STATE_RST,
+ MLX4_QP_STATE_INIT,
+ MLX4_QP_STATE_RTR,
+ MLX4_QP_STATE_RTS
+ };
+
+ for (i = 0; i < ARRAY_SIZE(states) - 1; i++) {
+ context->flags &= cpu_to_be32(~(0xf << 28));
+ context->flags |= cpu_to_be32(states[i + 1] << 28);
+ err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1],
+ context, 0, 0, qp);
+ if (err) {
+ mlx4_err(dev, "Failed to bring QP to state: "
+ "%d with error: %d\n",
+ states[i + 1], err);
+ return err;
+ }
+
+ *qp_state = states[i + 1];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_to_ready);
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 601ffd69ebc8..381b36e5f64c 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -2030,6 +2030,7 @@ static struct platform_driver mv643xx_eth_driver = {
.shutdown = mv643xx_eth_shutdown,
.driver = {
.name = MV643XX_ETH_NAME,
+ .owner = THIS_MODULE,
},
};
@@ -2038,6 +2039,7 @@ static struct platform_driver mv643xx_eth_shared_driver = {
.remove = mv643xx_eth_shared_remove,
.driver = {
.name = MV643XX_ETH_SHARED_NAME,
+ .owner = THIS_MODULE,
},
};
@@ -2085,7 +2087,8 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani"
" and Dale Farnsworth");
MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX");
-MODULE_ALIAS("platform:mv643xx_eth");
+MODULE_ALIAS("platform:" MV643XX_ETH_NAME);
+MODULE_ALIAS("platform:" MV643XX_ETH_SHARED_NAME);
/*
* The second part is the low level driver of the gigE ethernet ports.
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 78d34af13a1c..dc442e370850 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -502,4 +502,4 @@ module_exit(netx_eth_cleanup);
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:" CARDNAME);
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 05748ca6f216..af7356468251 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -1132,8 +1132,8 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
u32 fw_minor = 0;
u32 fw_build = 0;
char brd_name[NETXEN_MAX_SHORT_NAME];
- struct netxen_new_user_info user_info;
- int i, addr = NETXEN_USER_START;
+ char serial_num[32];
+ int i, addr;
__le32 *ptr32;
struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
@@ -1150,10 +1150,10 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
valid = 0;
}
if (valid) {
- ptr32 = (u32 *) & user_info;
- for (i = 0;
- i < sizeof(struct netxen_new_user_info) / sizeof(u32);
- i++) {
+ ptr32 = (u32 *)&serial_num;
+ addr = NETXEN_USER_START +
+ offsetof(struct netxen_new_user_info, serial_num);
+ for (i = 0; i < 8; i++) {
if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
printk("%s: ERROR reading %s board userarea.\n",
netxen_nic_driver_name,
@@ -1163,10 +1163,11 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
ptr32++;
addr += sizeof(u32);
}
+
get_brd_name_by_type(board_info->board_type, brd_name);
printk("NetXen %s Board S/N %s Chip id 0x%x\n",
- brd_name, user_info.serial_num, board_info->chip_id);
+ brd_name, serial_num, board_info->chip_id);
printk("NetXen %s Board #%d, Chip id 0x%x\n",
board_info->board_type == 0x0b ? "XGB" : "GBE",
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 7565c2d7f30e..4009c4ce96b4 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -33,8 +33,8 @@
#define DRV_MODULE_NAME "niu"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.7"
-#define DRV_MODULE_RELDATE "February 18, 2008"
+#define DRV_MODULE_VERSION "0.8"
+#define DRV_MODULE_RELDATE "April 24, 2008"
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -673,11 +673,16 @@ static int serdes_init_10g(struct niu *np)
}
if ((sig & mask) != val) {
+ if (np->flags & NIU_FLAGS_HOTPLUG_PHY) {
+ np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
+ return 0;
+ }
dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
"[%08x]\n", np->port, (int) (sig & mask), (int) val);
return -ENODEV;
}
-
+ if (np->flags & NIU_FLAGS_HOTPLUG_PHY)
+ np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT;
return 0;
}
@@ -998,6 +1003,28 @@ static int bcm8704_user_dev3_readback(struct niu *np, int reg)
return 0;
}
+static int bcm8706_init_user_dev3(struct niu *np)
+{
+ int err;
+
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_OPT_DIGITAL_CTRL);
+ if (err < 0)
+ return err;
+ err &= ~USER_ODIG_CTRL_GPIOS;
+ err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT);
+ err |= USER_ODIG_CTRL_RESV2;
+ err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_OPT_DIGITAL_CTRL, err);
+ if (err)
+ return err;
+
+ mdelay(1000);
+
+ return 0;
+}
+
static int bcm8704_init_user_dev3(struct niu *np)
{
int err;
@@ -1127,33 +1154,11 @@ static int xcvr_init_10g_mrvl88x2011(struct niu *np)
MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX);
}
-static int xcvr_init_10g_bcm8704(struct niu *np)
+
+static int xcvr_diag_bcm870x(struct niu *np)
{
- struct niu_link_config *lp = &np->link_config;
u16 analog_stat0, tx_alarm_status;
- int err;
-
- err = bcm8704_reset(np);
- if (err)
- return err;
-
- err = bcm8704_init_user_dev3(np);
- if (err)
- return err;
-
- err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
- MII_BMCR);
- if (err < 0)
- return err;
- err &= ~BMCR_LOOPBACK;
-
- if (lp->loopback_mode == LOOPBACK_MAC)
- err |= BMCR_LOOPBACK;
-
- err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
- MII_BMCR, err);
- if (err)
- return err;
+ int err = 0;
#if 1
err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
@@ -1211,6 +1216,89 @@ static int xcvr_init_10g_bcm8704(struct niu *np)
return 0;
}
+static int xcvr_10g_set_lb_bcm870x(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ int err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ MII_BMCR);
+ if (err < 0)
+ return err;
+
+ err &= ~BMCR_LOOPBACK;
+
+ if (lp->loopback_mode == LOOPBACK_MAC)
+ err |= BMCR_LOOPBACK;
+
+ err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ MII_BMCR, err);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int xcvr_init_10g_bcm8706(struct niu *np)
+{
+ int err = 0;
+ u64 val;
+
+ if ((np->flags & NIU_FLAGS_HOTPLUG_PHY) &&
+ (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) == 0)
+ return err;
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_LED_POLARITY;
+ val |= XMAC_CONFIG_FORCE_LED_ON;
+ nw64_mac(XMAC_CONFIG, val);
+
+ val = nr64(MIF_CONFIG);
+ val |= MIF_CONFIG_INDIRECT_MODE;
+ nw64(MIF_CONFIG, val);
+
+ err = bcm8704_reset(np);
+ if (err)
+ return err;
+
+ err = xcvr_10g_set_lb_bcm870x(np);
+ if (err)
+ return err;
+
+ err = bcm8706_init_user_dev3(np);
+ if (err)
+ return err;
+
+ err = xcvr_diag_bcm870x(np);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int xcvr_init_10g_bcm8704(struct niu *np)
+{
+ int err;
+
+ err = bcm8704_reset(np);
+ if (err)
+ return err;
+
+ err = bcm8704_init_user_dev3(np);
+ if (err)
+ return err;
+
+ err = xcvr_10g_set_lb_bcm870x(np);
+ if (err)
+ return err;
+
+ err = xcvr_diag_bcm870x(np);
+ if (err)
+ return err;
+
+ return 0;
+}
+
static int xcvr_init_10g(struct niu *np)
{
int phy_id, err;
@@ -1548,6 +1636,59 @@ out:
return err;
}
+static int link_status_10g_bcm8706(struct niu *np, int *link_up_p)
+{
+ int err, link_up;
+ link_up = 0;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+ BCM8704_PMD_RCV_SIGDET);
+ if (err < 0)
+ goto out;
+ if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
+ err = 0;
+ goto out;
+ }
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ BCM8704_PCS_10G_R_STATUS);
+ if (err < 0)
+ goto out;
+
+ if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {
+ err = 0;
+ goto out;
+ }
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ BCM8704_PHYXS_XGXS_LANE_STAT);
+ if (err < 0)
+ goto out;
+ if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |
+ PHYXS_XGXS_LANE_STAT_MAGIC |
+ PHYXS_XGXS_LANE_STAT_PATTEST |
+ PHYXS_XGXS_LANE_STAT_LANE3 |
+ PHYXS_XGXS_LANE_STAT_LANE2 |
+ PHYXS_XGXS_LANE_STAT_LANE1 |
+ PHYXS_XGXS_LANE_STAT_LANE0)) {
+ err = 0;
+ np->link_config.active_speed = SPEED_INVALID;
+ np->link_config.active_duplex = DUPLEX_INVALID;
+ goto out;
+ }
+
+ link_up = 1;
+ np->link_config.active_speed = SPEED_10000;
+ np->link_config.active_duplex = DUPLEX_FULL;
+ err = 0;
+
+out:
+ *link_up_p = link_up;
+ if (np->flags & NIU_FLAGS_HOTPLUG_PHY)
+ err = 0;
+ return err;
+}
+
static int link_status_10g_bcom(struct niu *np, int *link_up_p)
{
int err, link_up;
@@ -1627,6 +1768,82 @@ static int link_status_10g(struct niu *np, int *link_up_p)
return err;
}
+static int niu_10g_phy_present(struct niu *np)
+{
+ u64 sig, mask, val;
+
+ sig = nr64(ESR_INT_SIGNALS);
+ switch (np->port) {
+ case 0:
+ mask = ESR_INT_SIGNALS_P0_BITS;
+ val = (ESR_INT_SRDY0_P0 |
+ ESR_INT_DET0_P0 |
+ ESR_INT_XSRDY_P0 |
+ ESR_INT_XDP_P0_CH3 |
+ ESR_INT_XDP_P0_CH2 |
+ ESR_INT_XDP_P0_CH1 |
+ ESR_INT_XDP_P0_CH0);
+ break;
+
+ case 1:
+ mask = ESR_INT_SIGNALS_P1_BITS;
+ val = (ESR_INT_SRDY0_P1 |
+ ESR_INT_DET0_P1 |
+ ESR_INT_XSRDY_P1 |
+ ESR_INT_XDP_P1_CH3 |
+ ESR_INT_XDP_P1_CH2 |
+ ESR_INT_XDP_P1_CH1 |
+ ESR_INT_XDP_P1_CH0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ if ((sig & mask) != val)
+ return 0;
+ return 1;
+}
+
+static int link_status_10g_hotplug(struct niu *np, int *link_up_p)
+{
+ unsigned long flags;
+ int err = 0;
+ int phy_present;
+ int phy_present_prev;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ if (np->link_config.loopback_mode == LOOPBACK_DISABLED) {
+ phy_present_prev = (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) ?
+ 1 : 0;
+ phy_present = niu_10g_phy_present(np);
+ if (phy_present != phy_present_prev) {
+ /* state change */
+ if (phy_present) {
+ np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT;
+ if (np->phy_ops->xcvr_init)
+ err = np->phy_ops->xcvr_init(np);
+ if (err) {
+ /* debounce */
+ np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
+ }
+ } else {
+ np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT;
+ *link_up_p = 0;
+ niuwarn(LINK, "%s: Hotplug PHY Removed\n",
+ np->dev->name);
+ }
+ }
+ if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT)
+ err = link_status_10g_bcm8706(np, link_up_p);
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return err;
+}
+
static int link_status_1g(struct niu *np, int *link_up_p)
{
struct niu_link_config *lp = &np->link_config;
@@ -1761,6 +1978,12 @@ static const struct niu_phy_ops phy_ops_10g_fiber = {
.link_status = link_status_10g,
};
+static const struct niu_phy_ops phy_ops_10g_fiber_hotplug = {
+ .serdes_init = serdes_init_10g,
+ .xcvr_init = xcvr_init_10g_bcm8706,
+ .link_status = link_status_10g_hotplug,
+};
+
static const struct niu_phy_ops phy_ops_10g_copper = {
.serdes_init = serdes_init_10g,
.link_status = link_status_10g, /* XXX */
@@ -1792,6 +2015,11 @@ static const struct niu_phy_template phy_template_10g_fiber = {
.phy_addr_base = 8,
};
+static const struct niu_phy_template phy_template_10g_fiber_hotplug = {
+ .ops = &phy_ops_10g_fiber_hotplug,
+ .phy_addr_base = 8,
+};
+
static const struct niu_phy_template phy_template_10g_copper = {
.ops = &phy_ops_10g_copper,
.phy_addr_base = 10,
@@ -1996,6 +2224,13 @@ static int niu_determine_phy_disposition(struct niu *np)
plat_type == PLAT_TYPE_VF_P1)
phy_addr_off = 8;
phy_addr_off += np->port;
+ if (np->flags & NIU_FLAGS_HOTPLUG_PHY) {
+ tp = &phy_template_10g_fiber_hotplug;
+ if (np->port == 0)
+ phy_addr_off = 8;
+ if (np->port == 1)
+ phy_addr_off = 12;
+ }
break;
case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES:
@@ -6773,6 +7008,37 @@ static int __devinit niu_phy_type_prop_decode(struct niu *np,
return 0;
}
+/* niu board models have a trailing dash version incremented
+ * with HW rev change. Need to ingnore the dash version while
+ * checking for match
+ *
+ * for example, for the 10G card the current vpd.board_model
+ * is 501-5283-04, of which -04 is the dash version and have
+ * to be ignored
+ */
+static int niu_board_model_match(struct niu *np, const char *model)
+{
+ return !strncmp(np->vpd.board_model, model, strlen(model));
+}
+
+static int niu_pci_vpd_get_nports(struct niu *np)
+{
+ int ports = 0;
+
+ if ((niu_board_model_match(np, NIU_QGC_LP_BM_STR)) ||
+ (niu_board_model_match(np, NIU_QGC_PEM_BM_STR)) ||
+ (niu_board_model_match(np, NIU_ALONSO_BM_STR))) {
+ ports = 4;
+ } else if ((niu_board_model_match(np, NIU_2XGF_LP_BM_STR)) ||
+ (niu_board_model_match(np, NIU_2XGF_PEM_BM_STR)) ||
+ (niu_board_model_match(np, NIU_FOXXY_BM_STR)) ||
+ (niu_board_model_match(np, NIU_2XGF_MRVL_BM_STR))) {
+ ports = 2;
+ }
+
+ return ports;
+}
+
static void __devinit niu_pci_vpd_validate(struct niu *np)
{
struct net_device *dev = np->dev;
@@ -6799,6 +7065,9 @@ static void __devinit niu_pci_vpd_validate(struct niu *np)
}
if (np->flags & NIU_FLAGS_10G)
np->mac_xcvr = MAC_XCVR_XPCS;
+ } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+ np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER |
+ NIU_FLAGS_HOTPLUG_PHY);
} else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
dev_err(np->device, PFX "Illegal phy string [%s].\n",
np->vpd.phy_type);
@@ -6987,11 +7256,17 @@ static int __devinit niu_get_and_validate_port(struct niu *np)
if (parent->plat_type == PLAT_TYPE_NIU) {
parent->num_ports = 2;
} else {
- parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
- ESPC_NUM_PORTS_MACS_VAL;
-
- if (!parent->num_ports)
- parent->num_ports = 4;
+ parent->num_ports = niu_pci_vpd_get_nports(np);
+ if (!parent->num_ports) {
+ /* Fall back to SPROM as last resort.
+ * This will fail on most cards.
+ */
+ parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
+ ESPC_NUM_PORTS_MACS_VAL;
+
+ if (!parent->num_ports)
+ return -ENODEV;
+ }
}
}
@@ -7015,7 +7290,8 @@ static int __devinit phy_record(struct niu_parent *parent,
return 0;
if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) &&
- ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011))
+ ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011) &&
+ ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8706))
return 0;
} else {
if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
@@ -7262,7 +7538,6 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
u32 val;
int err;
-
if (!strcmp(np->vpd.model, "SUNW,CP3220") ||
!strcmp(np->vpd.model, "SUNW,CP3260")) {
num_10g = 0;
@@ -7273,6 +7548,12 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
phy_encode(PORT_TYPE_1G, 1) |
phy_encode(PORT_TYPE_1G, 2) |
phy_encode(PORT_TYPE_1G, 3));
+ } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) {
+ num_10g = 2;
+ num_1g = 0;
+ parent->num_ports = 2;
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_10G, 1));
} else {
err = fill_phy_probe_info(np, parent, info);
if (err)
@@ -7733,15 +8014,16 @@ static int __devinit niu_get_invariants(struct niu *np)
have_props = !err;
- err = niu_get_and_validate_port(np);
- if (err)
- return err;
-
err = niu_init_mac_ipp_pcs_base(np);
if (err)
return err;
- if (!have_props) {
+ if (have_props) {
+ err = niu_get_and_validate_port(np);
+ if (err)
+ return err;
+
+ } else {
if (np->parent->plat_type == PLAT_TYPE_NIU)
return -EINVAL;
@@ -7753,10 +8035,17 @@ static int __devinit niu_get_invariants(struct niu *np)
niu_pci_vpd_fetch(np, offset);
nw64(ESPC_PIO_EN, 0);
- if (np->flags & NIU_FLAGS_VPD_VALID)
+ if (np->flags & NIU_FLAGS_VPD_VALID) {
niu_pci_vpd_validate(np);
+ err = niu_get_and_validate_port(np);
+ if (err)
+ return err;
+ }
if (!(np->flags & NIU_FLAGS_VPD_VALID)) {
+ err = niu_get_and_validate_port(np);
+ if (err)
+ return err;
err = niu_pci_probe_sprom(np);
if (err)
return err;
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 336aed08b275..97ffbe137bcb 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -2537,6 +2537,7 @@ struct fcram_hash_ipv6 {
#define NIU_PHY_ID_MASK 0xfffff0f0
#define NIU_PHY_ID_BCM8704 0x00206030
+#define NIU_PHY_ID_BCM8706 0x00206035
#define NIU_PHY_ID_BCM5464R 0x002060b0
#define NIU_PHY_ID_MRVL88X2011 0x01410020
@@ -2937,6 +2938,15 @@ struct rx_ring_info {
#define NIU_MAX_MTU 9216
+/* VPD strings */
+#define NIU_QGC_LP_BM_STR "501-7606"
+#define NIU_2XGF_LP_BM_STR "501-7283"
+#define NIU_QGC_PEM_BM_STR "501-7765"
+#define NIU_2XGF_PEM_BM_STR "501-7626"
+#define NIU_ALONSO_BM_STR "373-0202"
+#define NIU_FOXXY_BM_STR "501-7961"
+#define NIU_2XGF_MRVL_BM_STR "SK-6E82"
+
#define NIU_VPD_MIN_MAJOR 3
#define NIU_VPD_MIN_MINOR 4
@@ -3199,6 +3209,8 @@ struct niu {
struct niu_parent *parent;
u32 flags;
+#define NIU_FLAGS_HOTPLUG_PHY_PRESENT 0x02000000 /* Removebale PHY detected*/
+#define NIU_FLAGS_HOTPLUG_PHY 0x01000000 /* Removebale PHY */
#define NIU_FLAGS_VPD_VALID 0x00800000 /* VPD has valid version */
#define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */
#define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 963630c65ca9..94e0b7ed76f1 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -89,6 +89,9 @@ int mdiobus_register(struct mii_bus *bus)
phydev->bus = bus;
+ /* Run all of the fixups for this PHY */
+ phy_scan_fixups(phydev);
+
err = device_register(&phydev->dev);
if (err) {
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 12fccb1c76dc..3c18bb594957 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -406,8 +406,10 @@ int phy_mii_ioctl(struct phy_device *phydev,
if (mii_data->reg_num == MII_BMCR
&& val & BMCR_RESET
- && phydev->drv->config_init)
+ && phydev->drv->config_init) {
+ phy_scan_fixups(phydev);
phydev->drv->config_init(phydev);
+ }
break;
default:
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8b1121b02f98..ddf8d51832a6 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -53,6 +53,96 @@ static void phy_device_release(struct device *dev)
phy_device_free(to_phy_device(dev));
}
+static LIST_HEAD(phy_fixup_list);
+static DEFINE_MUTEX(phy_fixup_lock);
+
+/*
+ * Creates a new phy_fixup and adds it to the list
+ * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
+ * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY)
+ * It can also be PHY_ANY_UID
+ * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before
+ * comparison
+ * @run: The actual code to be run when a matching PHY is found
+ */
+int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
+ int (*run)(struct phy_device *))
+{
+ struct phy_fixup *fixup;
+
+ fixup = kzalloc(sizeof(struct phy_fixup), GFP_KERNEL);
+ if (!fixup)
+ return -ENOMEM;
+
+ strncpy(fixup->bus_id, bus_id, BUS_ID_SIZE);
+ fixup->phy_uid = phy_uid;
+ fixup->phy_uid_mask = phy_uid_mask;
+ fixup->run = run;
+
+ mutex_lock(&phy_fixup_lock);
+ list_add_tail(&fixup->list, &phy_fixup_list);
+ mutex_unlock(&phy_fixup_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(phy_register_fixup);
+
+/* Registers a fixup to be run on any PHY with the UID in phy_uid */
+int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+ int (*run)(struct phy_device *))
+{
+ return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run);
+}
+EXPORT_SYMBOL(phy_register_fixup_for_uid);
+
+/* Registers a fixup to be run on the PHY with id string bus_id */
+int phy_register_fixup_for_id(const char *bus_id,
+ int (*run)(struct phy_device *))
+{
+ return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run);
+}
+EXPORT_SYMBOL(phy_register_fixup_for_id);
+
+/*
+ * Returns 1 if fixup matches phydev in bus_id and phy_uid.
+ * Fixups can be set to match any in one or more fields.
+ */
+static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
+{
+ if (strcmp(fixup->bus_id, phydev->dev.bus_id) != 0)
+ if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)
+ return 0;
+
+ if ((fixup->phy_uid & fixup->phy_uid_mask) !=
+ (phydev->phy_id & fixup->phy_uid_mask))
+ if (fixup->phy_uid != PHY_ANY_UID)
+ return 0;
+
+ return 1;
+}
+
+/* Runs any matching fixups for this phydev */
+int phy_scan_fixups(struct phy_device *phydev)
+{
+ struct phy_fixup *fixup;
+
+ mutex_lock(&phy_fixup_lock);
+ list_for_each_entry(fixup, &phy_fixup_list, list) {
+ if (phy_needs_fixup(phydev, fixup)) {
+ int err;
+
+ err = fixup->run(phydev);
+
+ if (err < 0)
+ return err;
+ }
+ }
+ mutex_unlock(&phy_fixup_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(phy_scan_fixups);
+
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
{
struct phy_device *dev;
@@ -179,13 +269,13 @@ void phy_prepare_link(struct phy_device *phydev,
* choose to call only the subset of functions which provide
* the desired functionality.
*/
-struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
+struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
void (*handler)(struct net_device *), u32 flags,
phy_interface_t interface)
{
struct phy_device *phydev;
- phydev = phy_attach(dev, phy_id, flags, interface);
+ phydev = phy_attach(dev, bus_id, flags, interface);
if (IS_ERR(phydev))
return phydev;
@@ -226,7 +316,7 @@ static int phy_compare_id(struct device *dev, void *data)
/**
* phy_attach - attach a network device to a particular PHY device
* @dev: network device to attach
- * @phy_id: PHY device to attach
+ * @bus_id: PHY device to attach
* @flags: PHY device's dev_flags
* @interface: PHY device's interface
*
@@ -238,7 +328,7 @@ static int phy_compare_id(struct device *dev, void *data)
* change. The phy_device is returned to the attaching driver.
*/
struct phy_device *phy_attach(struct net_device *dev,
- const char *phy_id, u32 flags, phy_interface_t interface)
+ const char *bus_id, u32 flags, phy_interface_t interface)
{
struct bus_type *bus = &mdio_bus_type;
struct phy_device *phydev;
@@ -246,12 +336,12 @@ struct phy_device *phy_attach(struct net_device *dev,
/* Search the list of PHY devices on the mdio bus for the
* PHY with the requested name */
- d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);
+ d = bus_find_device(bus, NULL, (void *)bus_id, phy_compare_id);
if (d) {
phydev = to_phy_device(d);
} else {
- printk(KERN_ERR "%s not found\n", phy_id);
+ printk(KERN_ERR "%s not found\n", bus_id);
return ERR_PTR(-ENODEV);
}
@@ -271,7 +361,7 @@ struct phy_device *phy_attach(struct net_device *dev,
if (phydev->attached_dev) {
printk(KERN_ERR "%s: %s already attached\n",
- dev->name, phy_id);
+ dev->name, bus_id);
return ERR_PTR(-EBUSY);
}
@@ -287,6 +377,11 @@ struct phy_device *phy_attach(struct net_device *dev,
if (phydev->drv->config_init) {
int err;
+ err = phy_scan_fixups(phydev);
+
+ if (err < 0)
+ return ERR_PTR(err);
+
err = phydev->drv->config_init(phydev);
if (err < 0)
@@ -395,6 +490,7 @@ EXPORT_SYMBOL(genphy_config_advert);
*/
int genphy_setup_forced(struct phy_device *phydev)
{
+ int err;
int ctl = 0;
phydev->pause = phydev->asym_pause = 0;
@@ -407,17 +503,26 @@ int genphy_setup_forced(struct phy_device *phydev)
if (DUPLEX_FULL == phydev->duplex)
ctl |= BMCR_FULLDPLX;
- ctl = phy_write(phydev, MII_BMCR, ctl);
+ err = phy_write(phydev, MII_BMCR, ctl);
- if (ctl < 0)
- return ctl;
+ if (err < 0)
+ return err;
+
+ /*
+ * Run the fixups on this PHY, just in case the
+ * board code needs to change something after a reset
+ */
+ err = phy_scan_fixups(phydev);
+
+ if (err < 0)
+ return err;
/* We just reset the device, so we'd better configure any
* settings the PHY requires to operate */
if (phydev->drv->config_init)
- ctl = phydev->drv->config_init(phydev);
+ err = phydev->drv->config_init(phydev);
- return ctl;
+ return err;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index dcbe01b0ca0d..157fd932e951 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -86,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.20"
+#define DRV_VERSION "2.0.26.22"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -117,20 +117,6 @@ static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
-#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
-#define PANIC 1
-#define LOW 2
-static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
-{
- struct mac_info *mac_control;
-
- mac_control = &sp->mac_control;
- if (rxb_size <= rxd_count[sp->rxd_mode])
- return PANIC;
- else if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16)
- return LOW;
- return 0;
-}
static inline int is_s2io_card_up(const struct s2io_nic * sp)
{
@@ -2458,7 +2444,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
for (i = 0; i < config->tx_fifo_num; i++) {
unsigned long flags;
spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags);
- for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
+ for (j = 0; j < config->tx_cfg[i].fifo_len; j++) {
txdp = (struct TxD *) \
mac_control->fifos[i].list_info[j].list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
@@ -2544,7 +2530,6 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
struct config_param *config;
u64 tmp;
struct buffAdd *ba;
- unsigned long flags;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
struct RxD1 *rxdp1;
@@ -2592,15 +2577,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
dev->name, rxdp);
}
- if(!napi) {
- spin_lock_irqsave(&nic->put_lock, flags);
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- spin_unlock_irqrestore(&nic->put_lock, flags);
- } else {
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- }
+
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & s2BIT(0)))) {
@@ -2978,7 +2955,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
{
struct s2io_nic *nic = ring_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
- int get_block, put_block, put_offset;
+ int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
struct sk_buff *skb;
@@ -2987,19 +2964,11 @@ static void rx_intr_handler(struct ring_info *ring_data)
struct RxD1* rxdp1;
struct RxD3* rxdp3;
- spin_lock(&nic->rx_lock);
-
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
put_block = put_info.block_index;
rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
- if (!napi) {
- spin_lock(&nic->put_lock);
- put_offset = ring_data->put_pos;
- spin_unlock(&nic->put_lock);
- } else
- put_offset = ring_data->put_pos;
while (RXD_IS_UP2DT(rxdp)) {
/*
@@ -3016,7 +2985,6 @@ static void rx_intr_handler(struct ring_info *ring_data)
DBG_PRINT(ERR_DBG, "%s: The skb is ",
dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
- spin_unlock(&nic->rx_lock);
return;
}
if (nic->rxd_mode == RXD_MODE_1) {
@@ -3072,8 +3040,6 @@ static void rx_intr_handler(struct ring_info *ring_data)
}
}
}
-
- spin_unlock(&nic->rx_lock);
}
/**
@@ -4105,7 +4071,6 @@ static int s2io_close(struct net_device *dev)
do_s2io_delete_unicast_mc(sp, tmp64);
}
- /* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
return 0;
@@ -4370,29 +4335,9 @@ s2io_alarm_handle(unsigned long data)
static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
{
- int rxb_size, level;
-
- if (!sp->lro) {
- rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
- level = rx_buffer_level(sp, rxb_size, rng_n);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- int ret;
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "Out of memory in %s",
- __FUNCTION__);
- clear_bit(0, (&sp->tasklet_status));
- return -1;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW)
- tasklet_schedule(&sp->task);
-
- } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
- DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
+ if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
@@ -6770,49 +6715,6 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
}
/**
- * s2io_tasklet - Bottom half of the ISR.
- * @dev_adr : address of the device structure in dma_addr_t format.
- * Description:
- * This is the tasklet or the bottom half of the ISR. This is
- * an extension of the ISR which is scheduled by the scheduler to be run
- * when the load on the CPU is low. All low priority tasks of the ISR can
- * be pushed into the tasklet. For now the tasklet is used only to
- * replenish the Rx buffers in the Rx buffer descriptors.
- * Return value:
- * void.
- */
-
-static void s2io_tasklet(unsigned long dev_addr)
-{
- struct net_device *dev = (struct net_device *) dev_addr;
- struct s2io_nic *sp = dev->priv;
- int i, ret;
- struct mac_info *mac_control;
- struct config_param *config;
-
- mac_control = &sp->mac_control;
- config = &sp->config;
-
- if (!TASKLET_IN_USE) {
- for (i = 0; i < config->rx_ring_num; i++) {
- ret = fill_rx_buffers(sp, i);
- if (ret == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s: Out of ",
- dev->name);
- DBG_PRINT(INFO_DBG, "memory in tasklet\n");
- break;
- } else if (ret == -EFILL) {
- DBG_PRINT(INFO_DBG,
- "%s: Rx Ring %d is full\n",
- dev->name, i);
- break;
- }
- }
- clear_bit(0, (&sp->tasklet_status));
- }
-}
-
-/**
* s2io_set_link - Set the LInk status
* @data: long pointer to device private structue
* Description: Sets the link status for the adapter
@@ -7161,7 +7063,6 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
{
int cnt = 0;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
- unsigned long flags;
register u64 val64 = 0;
struct config_param *config;
config = &sp->config;
@@ -7186,9 +7087,6 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
s2io_rem_isr(sp);
- /* Kill tasklet. */
- tasklet_kill(&sp->task);
-
/* Check if the device is Quiescent and then Reset the NIC */
while(do_io) {
/* As per the HW requirement we need to replenish the
@@ -7223,9 +7121,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
free_tx_buffers(sp);
/* Free all Rx buffers */
- spin_lock_irqsave(&sp->rx_lock, flags);
free_rx_buffers(sp);
- spin_unlock_irqrestore(&sp->rx_lock, flags);
clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state));
}
@@ -7314,9 +7210,6 @@ static int s2io_card_up(struct s2io_nic * sp)
S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
- /* Enable tasklet for the device */
- tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
-
/* Enable select interrupts */
en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
if (sp->config.intr_type != INTA)
@@ -8119,20 +8012,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
s2io_reset(sp);
/*
- * Initialize the tasklet status and link state flags
+ * Initialize link state flags
* and the card state parameter
*/
- sp->tasklet_status = 0;
sp->state = 0;
/* Initialize spinlocks */
for (i = 0; i < sp->config.tx_fifo_num; i++)
spin_lock_init(&mac_control->fifos[i].tx_lock);
- if (!napi)
- spin_lock_init(&sp->put_lock);
- spin_lock_init(&sp->rx_lock);
-
/*
* SXE-002: Configure link and activity LED to init state
* on driver load.
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index e68fdf7e4260..ce53a02105f2 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -703,9 +703,6 @@ struct ring_info {
*/
struct rx_curr_get_info rx_curr_get_info;
- /* Index to the absolute position of the put pointer of Rx ring */
- int put_pos;
-
/* Buffer Address store. */
struct buffAdd **ba;
struct s2io_nic *nic;
@@ -868,8 +865,6 @@ struct s2io_nic {
int device_enabled_once;
char name[60];
- struct tasklet_struct task;
- volatile unsigned long tasklet_status;
/* Timer that handles I/O errors/exceptions */
struct timer_list alarm_timer;
@@ -879,8 +874,6 @@ struct s2io_nic {
atomic_t rx_bufs_left[MAX_RX_RINGS];
- spinlock_t put_lock;
-
#define PROMISC 1
#define ALL_MULTI 2
@@ -964,7 +957,6 @@ struct s2io_nic {
u8 lro;
u16 lro_max_aggr_per_sess;
volatile unsigned long state;
- spinlock_t rx_lock;
u64 general_int_mask;
#define VPD_STRING_LEN 80
u8 product_name[VPD_STRING_LEN];
@@ -1094,7 +1086,6 @@ static void s2io_handle_errors(void * dev_id);
static int s2io_starter(void);
static void s2io_closer(void);
static void s2io_tx_watchdog(struct net_device *dev);
-static void s2io_tasklet(unsigned long dev_addr);
static void s2io_set_multicast(struct net_device *dev);
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
static void s2io_link(struct s2io_nic * sp, int link);
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 78994ede0cb0..6261201403cd 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -825,7 +825,8 @@ static struct platform_driver sgiseeq_driver = {
.probe = sgiseeq_probe,
.remove = __devexit_p(sgiseeq_remove),
.driver = {
- .name = "sgiseeq"
+ .name = "sgiseeq",
+ .owner = THIS_MODULE,
}
};
@@ -850,3 +851,4 @@ module_exit(sgiseeq_module_exit);
MODULE_DESCRIPTION("SGI Seeq 8003 driver");
MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sgiseeq");
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 76cc1d3adf71..4e2800205189 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -92,6 +92,7 @@ module_param(tx_fifo_kb, int, 0400);
MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:smc911x");
/*
* The internal workings of the driver. If you are changing anything
@@ -243,7 +244,7 @@ static void smc911x_reset(struct net_device *dev)
do {
udelay(10);
reg = SMC_GET_PMT_CTRL() & PMT_CTRL_READY_;
- } while ( timeout-- && !reg);
+ } while (--timeout && !reg);
if (timeout == 0) {
PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name);
return;
@@ -267,7 +268,7 @@ static void smc911x_reset(struct net_device *dev)
resets++;
break;
}
- } while ( timeout-- && (reg & HW_CFG_SRST_));
+ } while (--timeout && (reg & HW_CFG_SRST_));
}
if (timeout == 0) {
PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name);
@@ -413,7 +414,7 @@ static inline void smc911x_drop_pkt(struct net_device *dev)
do {
udelay(10);
reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_;
- } while ( timeout-- && reg);
+ } while (--timeout && reg);
if (timeout == 0) {
PRINTK("%s: timeout waiting for RX fast forward\n", dev->name);
}
@@ -2262,6 +2263,7 @@ static struct platform_driver smc911x_driver = {
.resume = smc911x_drv_resume,
.driver = {
.name = CARDNAME,
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 600b92af3334..a188e33484e6 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -132,6 +132,7 @@ module_param(watchdog, int, 0400);
MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:smc91x");
/*
* The internal workings of the driver. If you are changing anything
@@ -2308,6 +2309,7 @@ static struct platform_driver smc_driver = {
.resume = smc_drv_resume,
.driver = {
.name = CARDNAME,
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/sni_82596.c b/drivers/net/sni_82596.c
index 2cf6794acb4f..854ccf2b4105 100644
--- a/drivers/net/sni_82596.c
+++ b/drivers/net/sni_82596.c
@@ -44,6 +44,7 @@ static const char sni_82596_string[] = "snirm_82596";
MODULE_AUTHOR("Thomas Bogendoerfer");
MODULE_DESCRIPTION("i82596 driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:snirm_82596");
module_param(i596_debug, int, 0);
MODULE_PARM_DESC(i596_debug, "82596 debug mask");
@@ -166,6 +167,7 @@ static struct platform_driver sni_82596_driver = {
.remove = __devexit_p(sni_82596_driver_remove),
.driver = {
.name = sni_82596_string,
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 17585e5eed53..e83b166aa6b9 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -625,6 +625,12 @@ static void __init bdx_firmware_endianess(void)
s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]);
}
+static int bdx_range_check(struct bdx_priv *priv, u32 offset)
+{
+ return (offset > (u32) (BDX_REGS_SIZE / priv->nic->port_num)) ?
+ -EINVAL : 0;
+}
+
static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
{
struct bdx_priv *priv = ndev->priv;
@@ -643,9 +649,15 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
}
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
switch (data[0]) {
case BDX_OP_READ:
+ error = bdx_range_check(priv, data[1]);
+ if (error < 0)
+ return error;
data[2] = READ_REG(priv, data[1]);
DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2],
data[2]);
@@ -655,6 +667,9 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
break;
case BDX_OP_WRITE:
+ error = bdx_range_check(priv, data[1]);
+ if (error < 0)
+ return error;
WRITE_REG(priv, data[1], data[2]);
DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]);
break;
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index bc4c62b8e81a..e3f74c9f78bd 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4017,6 +4017,8 @@ static int tg3_halt(struct tg3 *, int, int);
* Invoked with tp->lock held.
*/
static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+ __releases(tp->lock)
+ __acquires(tp->lock)
{
int err;
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 6f33f84d37b0..6017d5267d08 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -162,6 +162,7 @@ static struct platform_driver tsi_eth_driver = {
.remove = tsi108_ether_remove,
.driver = {
.name = "tsi-ethernet",
+ .owner = THIS_MODULE,
},
};
@@ -1729,3 +1730,4 @@ module_exit(tsi108_ether_exit);
MODULE_AUTHOR("Tundra Semiconductor Corporation");
MODULE_DESCRIPTION("Tsi108 Gigabit Ethernet driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tsi-ethernet");
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 333961bb7873..c0dd25ba7a18 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -2183,7 +2183,6 @@ typhoon_resume(struct pci_dev *pdev)
}
netif_device_attach(dev);
- netif_start_queue(dev);
return 0;
reset:
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 2f11254bcc07..281ce3d39532 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3932,7 +3932,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
fixed_link = of_get_property(np, "fixed-link", NULL);
if (fixed_link) {
- ug_info->mdio_bus = 0;
+ snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0");
ug_info->phy_address = fixed_link[0];
phy = NULL;
} else {
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ed1afaf683a4..6b8d882d197b 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -605,7 +605,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
static void velocity_init_cam_filter(struct velocity_info *vptr)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
- unsigned short vid;
/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -617,29 +616,33 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
mac_set_cam_mask(regs, vptr->mCAMmask);
- /* Enable first VCAM */
+ /* Enable VCAMs */
if (vptr->vlgrp) {
- for (vid = 0; vid < VLAN_VID_MASK; vid++) {
- if (vlan_group_get_device(vptr->vlgrp, vid)) {
- /* If Tagging option is enabled and
- VLAN ID is not zero, then
- turn on MCFG_RTGOPT also */
- if (vid != 0)
- WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+ unsigned int vid, i = 0;
+
+ if (!vlan_group_get_device(vptr->vlgrp, 0))
+ WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
- mac_set_vlan_cam(regs, 0, (u8 *) &vid);
+ for (vid = 1; (vid < VLAN_VID_MASK); vid++) {
+ if (vlan_group_get_device(vptr->vlgrp, vid)) {
+ mac_set_vlan_cam(regs, i, (u8 *) &vid);
+ vptr->vCAMmask[i / 8] |= 0x1 << (i % 8);
+ if (++i >= VCAM_SIZE)
+ break;
}
}
- vptr->vCAMmask[0] |= 1;
mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
- } else {
- u16 temp = 0;
- mac_set_vlan_cam(regs, 0, (u8 *) &temp);
- temp = 1;
- mac_set_vlan_cam_mask(regs, (u8 *) &temp);
}
}
+static void velocity_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ vptr->vlgrp = grp;
+}
+
static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -959,11 +962,13 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid;
dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;
+ dev->vlan_rx_register = velocity_vlan_rx_register;
#ifdef VELOCITY_ZERO_COPY_SUPPORT
dev->features |= NETIF_F_SG;
#endif
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER;
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_HW_VLAN_RX;
if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
dev->features |= NETIF_F_IP_CSUM;
@@ -1597,8 +1602,13 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
skb_put(skb, pkt_len - 4);
skb->protocol = eth_type_trans(skb, vptr->dev);
+ if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) {
+ vlan_hwaccel_rx(skb, vptr->vlgrp,
+ swab16(le16_to_cpu(rd->rdesc1.PQTAG)));
+ } else
+ netif_rx(skb);
+
stats->rx_bytes += pkt_len;
- netif_rx(skb);
return 0;
}
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index c4c8eab8574f..c2cc42f723d5 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -402,7 +402,7 @@ static int __init c101_init(void)
#ifdef MODULE
printk(KERN_INFO "c101: no card initialized\n");
#endif
- return -ENOSYS; /* no parameters specified, abort */
+ return -EINVAL; /* no parameters specified, abort */
}
printk(KERN_INFO "%s\n", version);
@@ -420,11 +420,11 @@ static int __init c101_init(void)
c101_run(irq, ram);
if (*hw == '\x0')
- return first_card ? 0 : -ENOSYS;
+ return first_card ? 0 : -EINVAL;
}while(*hw++ == ':');
printk(KERN_ERR "c101: invalid hardware parameters\n");
- return first_card ? 0 : -ENOSYS;
+ return first_card ? 0 : -EINVAL;
}
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index c4ab0326f911..520bb0b1a9a2 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1090,10 +1090,6 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
pvc_device *pvc = NULL;
struct net_device *dev;
int result, used;
- char * prefix = "pvc%d";
-
- if (type == ARPHRD_ETHER)
- prefix = "pvceth%d";
if ((pvc = add_pvc(frad, dlci)) == NULL) {
printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c2642bc1d49b..2c343aae38d4 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -56,7 +56,7 @@ obj-$(CONFIG_RTL8187) += rtl8187.o
obj-$(CONFIG_ADM8211) += adm8211.o
-obj-$(CONFIG_IWLCORE) += iwlwifi/
+obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_RT2X00) += rt2x00/
obj-$(CONFIG_P54_COMMON) += p54/
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index c4e631d14bfe..9a25f550fd16 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,6 +1,11 @@
+config IWLWIFI
+ bool
+ default n
+
config IWLCORE
tristate "Intel Wireless Wifi Core"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ select IWLWIFI
config IWLWIFI_LEDS
bool
@@ -106,6 +111,7 @@ config IWL3945
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
+ select IWLWIFI
---help---
Select to build the driver supporting the:
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 7483d45bc5bc..e62018a36133 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1809,3 +1809,5 @@ module_exit(netif_exit);
MODULE_DESCRIPTION("Xen virtual network device frontend");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vif");
+MODULE_ALIAS("xennet");
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 631689171159..715a44471617 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -13,6 +13,7 @@
#include <linux/i2c.h>
#include <linux/of.h>
+#include <linux/module.h>
struct i2c_driver_device {
char *of_device;
@@ -113,3 +114,5 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
}
}
EXPORT_SYMBOL(of_register_i2c_devices);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index b07ba2a14119..9304c4555079 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -491,7 +491,7 @@ typedef enum {
*/
void sync_buffer(int cpu)
{
- struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu];
+ struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
struct mm_struct *mm = NULL;
struct task_struct * new;
unsigned long cookie = 0;
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index c93d3d2640ab..efcbf4b4579f 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -27,7 +27,7 @@
#include "buffer_sync.h"
#include "oprof.h"
-struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct oprofile_cpu_buffer, cpu_buffer);
static void wq_sync_buffer(struct work_struct *work);
@@ -39,7 +39,7 @@ void free_cpu_buffers(void)
int i;
for_each_online_cpu(i)
- vfree(cpu_buffer[i].buffer);
+ vfree(per_cpu(cpu_buffer, i).buffer);
}
int alloc_cpu_buffers(void)
@@ -49,7 +49,7 @@ int alloc_cpu_buffers(void)
unsigned long buffer_size = fs_cpu_buffer_size;
for_each_online_cpu(i) {
- struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+ struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size,
cpu_to_node(i));
@@ -83,7 +83,7 @@ void start_cpu_work(void)
work_enabled = 1;
for_each_online_cpu(i) {
- struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+ struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
/*
* Spread the work by 1 jiffy per cpu so they dont all
@@ -100,7 +100,7 @@ void end_cpu_work(void)
work_enabled = 0;
for_each_online_cpu(i) {
- struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+ struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
cancel_delayed_work(&b->work);
}
@@ -227,7 +227,7 @@ static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf)
void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel)
{
- struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
+ struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
if (!backtrace_depth) {
log_sample(cpu_buf, pc, is_kernel, event);
@@ -254,13 +254,13 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
{
- struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
+ struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
log_sample(cpu_buf, pc, is_kernel, event);
}
void oprofile_add_trace(unsigned long pc)
{
- struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
+ struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
if (!cpu_buf->tracing)
return;
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index c66c025abe75..13588174311d 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -14,6 +14,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/cache.h>
+#include <linux/sched.h>
struct task_struct;
@@ -47,7 +48,7 @@ struct oprofile_cpu_buffer {
struct delayed_work work;
} ____cacheline_aligned;
-extern struct oprofile_cpu_buffer cpu_buffer[];
+DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
index d1f6d776e9e4..f99b28e7b79a 100644
--- a/drivers/oprofile/oprofile_stats.c
+++ b/drivers/oprofile/oprofile_stats.c
@@ -23,7 +23,7 @@ void oprofile_reset_stats(void)
int i;
for_each_possible_cpu(i) {
- cpu_buf = &cpu_buffer[i];
+ cpu_buf = &per_cpu(cpu_buffer, i);
cpu_buf->sample_received = 0;
cpu_buf->sample_lost_overflow = 0;
cpu_buf->backtrace_aborted = 0;
@@ -49,7 +49,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
return;
for_each_possible_cpu(i) {
- cpu_buf = &cpu_buffer[i];
+ cpu_buf = &per_cpu(cpu_buffer, i);
snprintf(buf, 10, "cpu%d", i);
cpudir = oprofilefs_mkdir(sb, dir, buf);
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index 96ac54072f6f..d39a78dbd026 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -31,7 +31,7 @@ int aer_osc_setup(struct pcie_device *pciedev)
{
acpi_status status = AE_NOT_FOUND;
struct pci_dev *pdev = pciedev->port;
- acpi_handle handle = 0;
+ acpi_handle handle = NULL;
if (acpi_pci_disabled)
return -1;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 8d8852651fd2..1b0eb5aaf650 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -38,7 +38,6 @@ config PCMCIA_DEBUG
config PCMCIA
tristate "16-bit PCMCIA support"
select CRC32
- select HAVE_IDE
default y
---help---
This option enables support for 16-bit PCMCIA cards. Most older
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 12a1645a2e43..e85cbf116db1 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -167,7 +167,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
return error;
}
- if (pnp_dev->protocol && pnp_dev->protocol->suspend)
+ if (pnp_dev->protocol->suspend)
pnp_dev->protocol->suspend(pnp_dev, state);
return 0;
}
@@ -181,7 +181,7 @@ static int pnp_bus_resume(struct device *dev)
if (!pnp_drv)
return 0;
- if (pnp_dev->protocol && pnp_dev->protocol->resume)
+ if (pnp_dev->protocol->resume)
pnp_dev->protocol->resume(pnp_dev);
if (pnp_can_write(pnp_dev)) {
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c283a9a70d83..63e64ef39fb7 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -44,7 +44,7 @@ static struct acpi_device_id excluded_id_list[] __initdata = {
{"", 0},
};
-static inline int is_exclusive_device(struct acpi_device *dev)
+static inline int __init is_exclusive_device(struct acpi_device *dev)
{
return (!acpi_match_device_ids(dev, excluded_id_list));
}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 37993206ae5d..e4daf4635c48 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -49,8 +49,11 @@ static void quirk_awe32_resources(struct pnp_dev *dev)
port2->max += 0x400;
port3->min += 0x800;
port3->max += 0x800;
+ dev_info(&dev->dev,
+ "AWE32 quirk - added ioports 0x%lx and 0x%lx\n",
+ (unsigned long)port2->min,
+ (unsigned long)port3->min);
}
- printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n");
}
static void quirk_cmi8330_resources(struct pnp_dev *dev)
@@ -73,7 +76,8 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev)
IORESOURCE_DMA_8BIT)
dma->map = 0x000A;
}
- printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n");
+ dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 "
+ "and DMA channels to 1, 3\n");
}
static void quirk_sb16audio_resources(struct pnp_dev *dev)
@@ -104,8 +108,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
changed = 1;
}
if (changed)
- printk(KERN_INFO
- "pnp: SB audio device quirk - increasing port range\n");
+ dev_info(&dev->dev, "SB audio device quirk - increased port range\n");
}
@@ -214,8 +217,8 @@ void pnp_fixup_device(struct pnp_dev *dev)
quirk = pnp_fixups[i].quirk_function;
#ifdef DEBUG
- dev_dbg(&dev->dev, "calling quirk 0x%p", quirk);
- print_fn_descriptor_symbol(": %s()\n",
+ dev_dbg(&dev->dev, "calling ");
+ print_fn_descriptor_symbol("%s()\n",
(unsigned long) *quirk);
#endif
(*quirk)(dev);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 02a4c8cf2b2d..6cc2c0330230 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -20,10 +20,6 @@ menuconfig RTC_CLASS
if RTC_CLASS
-if GEN_RTC || RTC
-comment "Conflicting RTC option has been selected, check GEN_RTC and RTC"
-endif
-
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
depends on RTC_CLASS = y
@@ -304,6 +300,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
+ default y if X86
help
Say "yes" here to get direct support for the real time clock
found in every PC or ACPI-based system, and some other boards.
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 52abffc86bcd..39e64ab1ecb7 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -83,7 +83,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = tm->tm_year - 1900;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -97,7 +97,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
{
unsigned long cr;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -142,7 +142,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->enabled = (at91_sys_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
? 1 : 0;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -178,7 +178,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (alrm->enabled)
at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
@@ -193,7 +193,7 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
{
int ret = 0;
- pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
+ pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg);
switch (cmd) {
case RTC_AIE_OFF: /* alarm off */
@@ -265,7 +265,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
rtc_update_irq(rtc, 1, events);
- pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
+ pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__,
events >> 8, events & 0x000000FF);
return IRQ_HANDLED;
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 56728a2a3385..38d8742a4bdf 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -288,7 +288,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
rtc_update_irq(rtc->rtcdev, 1, events);
- pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__,
+ pr_debug("%s: num=%ld, events=0x%02lx\n", __func__,
events >> 8, events & 0x000000FF);
return IRQ_HANDLED;
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 7b002ceeaa7d..b9397818f73a 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -122,7 +122,7 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index d08912f18ddd..a83a40b3ebaa 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -181,8 +181,7 @@ ds1511_wdog_disable(void)
* stupidly, some callers call with year unmolested;
* and some call with year = year - 1900. thanks.
*/
- int
-ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
{
u8 mon, day, dow, hrs, min, sec, yrs, cen;
unsigned int flags;
@@ -245,8 +244,7 @@ ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
return 0;
}
- int
-ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
{
unsigned int century;
unsigned int flags;
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index e0900ca678ec..6fa4556f5f5c 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -50,13 +50,13 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
/* read date registers */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
dev_dbg(&client->dev,
"%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
- __FUNCTION__, buf[0], buf[1], buf[2], buf[3]);
+ __func__, buf[0], buf[1], buf[2], buf[3]);
time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
@@ -64,7 +64,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
+ __func__, tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
return 0;
@@ -84,7 +84,7 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
xfer = i2c_master_send(client, buf, 6);
if (xfer != 6) {
- dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
+ dev_err(&client->dev, "%s: send: %d\n", __func__, xfer);
return -EIO;
}
@@ -98,7 +98,7 @@ static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev,
"%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -133,7 +133,7 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
/* read control register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&adapter->dev, "%s\n", __func__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 725b0c73c333..fb15e3fb4ce2 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -15,16 +15,15 @@
#include <linux/bcd.h>
#include <linux/rtc.h>
-#define DRV_NAME "isl1208"
-#define DRV_VERSION "0.2"
+#define DRV_VERSION "0.3"
/* Register map */
/* rtc section */
#define ISL1208_REG_SC 0x00
#define ISL1208_REG_MN 0x01
#define ISL1208_REG_HR 0x02
-#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
-#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
+#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
+#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
#define ISL1208_REG_DT 0x03
#define ISL1208_REG_MO 0x04
#define ISL1208_REG_YR 0x05
@@ -33,14 +32,14 @@
/* control/status section */
#define ISL1208_REG_SR 0x07
-#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
-#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
-#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
-#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
-#define ISL1208_REG_SR_BAT (1<<1) /* battery */
-#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
+#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
+#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
+#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
+#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
+#define ISL1208_REG_SR_BAT (1<<1) /* battery */
+#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
#define ISL1208_REG_INT 0x08
-#define ISL1208_REG_09 0x09 /* reserved */
+#define ISL1208_REG_09 0x09 /* reserved */
#define ISL1208_REG_ATR 0x0a
#define ISL1208_REG_DTR 0x0b
@@ -58,39 +57,21 @@
#define ISL1208_REG_USR2 0x13
#define ISL1208_USR_SECTION_LEN 2
-/* i2c configuration */
-#define ISL1208_I2C_ADDR 0xde
-
-static const unsigned short normal_i2c[] = {
- ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD; /* defines addr_data */
-
-static int isl1208_attach_adapter(struct i2c_adapter *adapter);
-static int isl1208_detach_client(struct i2c_client *client);
-
-static struct i2c_driver isl1208_driver = {
- .driver = {
- .name = DRV_NAME,
- },
- .id = I2C_DRIVERID_ISL1208,
- .attach_adapter = &isl1208_attach_adapter,
- .detach_client = &isl1208_detach_client,
-};
+static struct i2c_driver isl1208_driver;
/* block read */
static int
isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
- unsigned len)
+ unsigned len)
{
u8 reg_addr[1] = { reg };
struct i2c_msg msgs[2] = {
- { client->addr, client->flags, sizeof(reg_addr), reg_addr },
- { client->addr, client->flags | I2C_M_RD, len, buf }
+ {client->addr, 0, sizeof(reg_addr), reg_addr}
+ ,
+ {client->addr, I2C_M_RD, len, buf}
};
int ret;
- BUG_ON(len == 0);
BUG_ON(reg > ISL1208_REG_USR2);
BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
@@ -103,15 +84,14 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
/* block write */
static int
isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
- unsigned len)
+ unsigned len)
{
u8 i2c_buf[ISL1208_REG_USR2 + 2];
struct i2c_msg msgs[1] = {
- { client->addr, client->flags, len + 1, i2c_buf }
+ {client->addr, 0, len + 1, i2c_buf}
};
int ret;
- BUG_ON(len == 0);
BUG_ON(reg > ISL1208_REG_USR2);
BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
@@ -125,7 +105,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
}
/* simple check to see wether we have a isl1208 */
-static int isl1208_i2c_validate_client(struct i2c_client *client)
+static int
+isl1208_i2c_validate_client(struct i2c_client *client)
{
u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
u8 zero_mask[ISL1208_RTC_SECTION_LEN] = {
@@ -139,24 +120,29 @@ static int isl1208_i2c_validate_client(struct i2c_client *client)
return ret;
for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) {
- if (regs[i] & zero_mask[i]) /* check if bits are cleared */
+ if (regs[i] & zero_mask[i]) /* check if bits are cleared */
return -ENODEV;
}
return 0;
}
-static int isl1208_i2c_get_sr(struct i2c_client *client)
+static int
+isl1208_i2c_get_sr(struct i2c_client *client)
{
- return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0;
+ int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR);
+ if (sr < 0)
+ return -EIO;
+
+ return sr;
}
-static int isl1208_i2c_get_atr(struct i2c_client *client)
+static int
+isl1208_i2c_get_atr(struct i2c_client *client)
{
int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR);
-
if (atr < 0)
- return -EIO;
+ return atr;
/* The 6bit value in the ATR register controls the load
* capacitance C_load * in steps of 0.25pF
@@ -169,51 +155,54 @@ static int isl1208_i2c_get_atr(struct i2c_client *client)
*
*/
- atr &= 0x3f; /* mask out lsb */
- atr ^= 1<<5; /* invert 6th bit */
- atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
+ atr &= 0x3f; /* mask out lsb */
+ atr ^= 1 << 5; /* invert 6th bit */
+ atr += 2 * 9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
return atr;
}
-static int isl1208_i2c_get_dtr(struct i2c_client *client)
+static int
+isl1208_i2c_get_dtr(struct i2c_client *client)
{
int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR);
-
if (dtr < 0)
return -EIO;
/* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
- dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1);
+ dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1);
return dtr;
}
-static int isl1208_i2c_get_usr(struct i2c_client *client)
+static int
+isl1208_i2c_get_usr(struct i2c_client *client)
{
u8 buf[ISL1208_USR_SECTION_LEN] = { 0, };
int ret;
- ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf,
- ISL1208_USR_SECTION_LEN);
+ ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
if (ret < 0)
return ret;
return (buf[1] << 8) | buf[0];
}
-static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
+static int
+isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
{
u8 buf[ISL1208_USR_SECTION_LEN];
buf[0] = usr & 0xff;
buf[1] = (usr >> 8) & 0xff;
- return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf,
- ISL1208_USR_SECTION_LEN);
+ return isl1208_i2c_set_regs(client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
}
-static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
+static int
+isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct i2c_client *const client = to_i2c_client(dev);
int sr, dtr, atr, usr;
@@ -230,20 +219,19 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
(sr & ISL1208_REG_SR_ALM) ? " ALM" : "",
(sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "",
(sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "",
- (sr & ISL1208_REG_SR_ARST) ? " ARST" : "",
- sr);
+ (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", sr);
seq_printf(seq, "batt_status\t: %s\n",
(sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
dtr = isl1208_i2c_get_dtr(client);
- if (dtr >= 0 -1)
+ if (dtr >= 0 - 1)
seq_printf(seq, "digital_trim\t: %d ppm\n", dtr);
atr = isl1208_i2c_get_atr(client);
if (atr >= 0)
seq_printf(seq, "analog_trim\t: %d.%.2d pF\n",
- atr>>2, (atr&0x3)*25);
+ atr >> 2, (atr & 0x3) * 25);
usr = isl1208_i2c_get_usr(client);
if (usr >= 0)
@@ -252,9 +240,8 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-
-static int isl1208_i2c_read_time(struct i2c_client *client,
- struct rtc_time *tm)
+static int
+isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
{
int sr;
u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
@@ -274,27 +261,30 @@ static int isl1208_i2c_read_time(struct i2c_client *client,
tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]);
tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]);
- { /* HR field has a more complex interpretation */
+
+ /* HR field has a more complex interpretation */
+ {
const u8 _hr = regs[ISL1208_REG_HR];
- if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
+ if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
tm->tm_hour = BCD2BIN(_hr & 0x3f);
- else { // 12h format
+ else {
+ /* 12h format */
tm->tm_hour = BCD2BIN(_hr & 0x1f);
- if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
+ if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
tm->tm_hour += 12;
}
}
tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]);
- tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100;
tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]);
return 0;
}
-static int isl1208_i2c_read_alarm(struct i2c_client *client,
- struct rtc_wkalrm *alarm)
+static int
+isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
{
struct rtc_time *const tm = &alarm->time;
u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
@@ -307,7 +297,7 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client,
}
sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs,
- ISL1208_ALARM_SECTION_LEN);
+ ISL1208_ALARM_SECTION_LEN);
if (sr < 0) {
dev_err(&client->dev, "%s: reading alarm section failed\n",
__func__);
@@ -315,23 +305,25 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client,
}
/* MSB of each alarm register is an enable bit */
- tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f);
- tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f);
- tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f);
- tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f);
- tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1;
- tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03);
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f);
+ tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mon =
+ BCD2BIN(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03);
return 0;
}
-static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int
+isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return isl1208_i2c_read_time(to_i2c_client(dev), tm);
}
-static int isl1208_i2c_set_time(struct i2c_client *client,
- struct rtc_time const *tm)
+static int
+isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
{
int sr;
u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
@@ -353,7 +345,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client,
}
/* set WRTC */
- sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR,
sr | ISL1208_REG_SR_WRTC);
if (sr < 0) {
dev_err(&client->dev, "%s: writing SR failed\n", __func__);
@@ -369,7 +361,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client,
}
/* clear WRTC again */
- sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR,
sr & ~ISL1208_REG_SR_WRTC);
if (sr < 0) {
dev_err(&client->dev, "%s: writing SR failed\n", __func__);
@@ -380,70 +372,69 @@ static int isl1208_i2c_set_time(struct i2c_client *client,
}
-static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int
+isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
return isl1208_i2c_set_time(to_i2c_client(dev), tm);
}
-static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int
+isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
}
static const struct rtc_class_ops isl1208_rtc_ops = {
- .proc = isl1208_rtc_proc,
- .read_time = isl1208_rtc_read_time,
- .set_time = isl1208_rtc_set_time,
- .read_alarm = isl1208_rtc_read_alarm,
- //.set_alarm = isl1208_rtc_set_alarm,
+ .proc = isl1208_rtc_proc,
+ .read_time = isl1208_rtc_read_time,
+ .set_time = isl1208_rtc_set_time,
+ .read_alarm = isl1208_rtc_read_alarm,
+ /*.set_alarm = isl1208_rtc_set_alarm, */
};
/* sysfs interface */
-static ssize_t isl1208_sysfs_show_atrim(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t
+isl1208_sysfs_show_atrim(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int atr;
-
- atr = isl1208_i2c_get_atr(to_i2c_client(dev));
+ int atr = isl1208_i2c_get_atr(to_i2c_client(dev));
if (atr < 0)
return atr;
- return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25);
+ return sprintf(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25);
}
+
static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
-static ssize_t isl1208_sysfs_show_dtrim(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t
+isl1208_sysfs_show_dtrim(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int dtr;
-
- dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
+ int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
if (dtr < 0)
return dtr;
return sprintf(buf, "%d ppm\n", dtr);
}
+
static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
-static ssize_t isl1208_sysfs_show_usr(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t
+isl1208_sysfs_show_usr(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int usr;
-
- usr = isl1208_i2c_get_usr(to_i2c_client(dev));
+ int usr = isl1208_i2c_get_usr(to_i2c_client(dev));
if (usr < 0)
return usr;
return sprintf(buf, "0x%.4x\n", usr);
}
-static ssize_t isl1208_sysfs_store_usr(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t
+isl1208_sysfs_store_usr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int usr = -1;
@@ -460,124 +451,116 @@ static ssize_t isl1208_sysfs_store_usr(struct device *dev,
return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
}
+
static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
isl1208_sysfs_store_usr);
static int
-isl1208_probe(struct i2c_adapter *adapter, int addr, int kind)
+isl1208_sysfs_register(struct device *dev)
{
- int rc = 0;
- struct i2c_client *new_client = NULL;
- struct rtc_device *rtc = NULL;
+ int err;
+
+ err = device_create_file(dev, &dev_attr_atrim);
+ if (err)
+ return err;
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
- rc = -ENODEV;
- goto failout;
+ err = device_create_file(dev, &dev_attr_dtrim);
+ if (err) {
+ device_remove_file(dev, &dev_attr_atrim);
+ return err;
}
- new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (new_client == NULL) {
- rc = -ENOMEM;
- goto failout;
+ err = device_create_file(dev, &dev_attr_usr);
+ if (err) {
+ device_remove_file(dev, &dev_attr_atrim);
+ device_remove_file(dev, &dev_attr_dtrim);
}
- new_client->addr = addr;
- new_client->adapter = adapter;
- new_client->driver = &isl1208_driver;
- new_client->flags = 0;
- strcpy(new_client->name, DRV_NAME);
+ return 0;
+}
- if (kind < 0) {
- rc = isl1208_i2c_validate_client(new_client);
- if (rc < 0)
- goto failout;
- }
+static int
+isl1208_sysfs_unregister(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_atrim);
+ device_remove_file(dev, &dev_attr_atrim);
+ device_remove_file(dev, &dev_attr_usr);
+
+ return 0;
+}
+
+static int
+isl1208_probe(struct i2c_client *client)
+{
+ int rc = 0;
+ struct rtc_device *rtc;
- rc = i2c_attach_client(new_client);
- if (rc < 0)
- goto failout;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
- dev_info(&new_client->dev,
+ if (isl1208_i2c_validate_client(client) < 0)
+ return -ENODEV;
+
+ dev_info(&client->dev,
"chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(isl1208_driver.driver.name,
- &new_client->dev,
- &isl1208_rtc_ops, THIS_MODULE);
-
- if (IS_ERR(rtc)) {
- rc = PTR_ERR(rtc);
- goto failout_detach;
- }
+ &client->dev, &isl1208_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- i2c_set_clientdata(new_client, rtc);
+ i2c_set_clientdata(client, rtc);
- rc = isl1208_i2c_get_sr(new_client);
+ rc = isl1208_i2c_get_sr(client);
if (rc < 0) {
- dev_err(&new_client->dev, "reading status failed\n");
- goto failout_unregister;
+ dev_err(&client->dev, "reading status failed\n");
+ goto exit_unregister;
}
if (rc & ISL1208_REG_SR_RTCF)
- dev_warn(&new_client->dev, "rtc power failure detected, "
+ dev_warn(&client->dev, "rtc power failure detected, "
"please set clock.\n");
- rc = device_create_file(&new_client->dev, &dev_attr_atrim);
- if (rc < 0)
- goto failout_unregister;
- rc = device_create_file(&new_client->dev, &dev_attr_dtrim);
- if (rc < 0)
- goto failout_atrim;
- rc = device_create_file(&new_client->dev, &dev_attr_usr);
- if (rc < 0)
- goto failout_dtrim;
+ rc = isl1208_sysfs_register(&client->dev);
+ if (rc)
+ goto exit_unregister;
return 0;
- failout_dtrim:
- device_remove_file(&new_client->dev, &dev_attr_dtrim);
- failout_atrim:
- device_remove_file(&new_client->dev, &dev_attr_atrim);
- failout_unregister:
+exit_unregister:
rtc_device_unregister(rtc);
- failout_detach:
- i2c_detach_client(new_client);
- failout:
- kfree(new_client);
- return rc;
-}
-static int
-isl1208_attach_adapter (struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, isl1208_probe);
+ return rc;
}
static int
-isl1208_detach_client(struct i2c_client *client)
+isl1208_remove(struct i2c_client *client)
{
- int rc;
- struct rtc_device *const rtc = i2c_get_clientdata(client);
-
- if (rtc)
- rtc_device_unregister(rtc); /* do we need to kfree? */
-
- rc = i2c_detach_client(client);
- if (rc)
- return rc;
+ struct rtc_device *rtc = i2c_get_clientdata(client);
- kfree(client);
+ isl1208_sysfs_unregister(&client->dev);
+ rtc_device_unregister(rtc);
return 0;
}
-/* module management */
+static struct i2c_driver isl1208_driver = {
+ .driver = {
+ .name = "rtc-isl1208",
+ },
+ .probe = isl1208_probe,
+ .remove = isl1208_remove,
+};
-static int __init isl1208_init(void)
+static int __init
+isl1208_init(void)
{
return i2c_add_driver(&isl1208_driver);
}
-static void __exit isl1208_exit(void)
+static void __exit
+isl1208_exit(void)
{
i2c_del_driver(&isl1208_driver);
}
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index 7683412970c4..ded3c0abad83 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -98,7 +98,7 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (rc != ARRAY_SIZE(msgs)) {
dev_err(&client->dev, "%s: register read failed\n",
- __FUNCTION__);
+ __func__);
return -EIO;
}
return 0;
@@ -150,7 +150,7 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
write_failed:
dev_err(&client->dev, "%s: register write failed\n",
- __FUNCTION__);
+ __func__);
return -EIO;
}
@@ -214,7 +214,7 @@ static int max6900_i2c_clear_write_protect(struct i2c_client *client)
rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0);
if (rc < 0) {
dev_err(&client->dev, "%s: control register write failed\n",
- __FUNCTION__);
+ __func__);
return -EIO;
}
return 0;
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 1f956dc5d56e..12f0310ae89c 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -140,7 +140,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
dt->tm_year -= 1900;
#ifdef MAX6902_DEBUG
- printk("\n%s : Read RTC values\n",__FUNCTION__);
+ printk("\n%s : Read RTC values\n",__func__);
printk("tm_hour: %i\n",dt->tm_hour);
printk("tm_min : %i\n",dt->tm_min);
printk("tm_sec : %i\n",dt->tm_sec);
@@ -158,7 +158,7 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
dt->tm_year = dt->tm_year+1900;
#ifdef MAX6902_DEBUG
- printk("\n%s : Setting RTC values\n",__FUNCTION__);
+ printk("\n%s : Setting RTC values\n",__func__);
printk("tm_sec : %i\n",dt->tm_sec);
printk("tm_min : %i\n",dt->tm_min);
printk("tm_hour: %i\n",dt->tm_hour);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index b3317fcc16c3..a41681d26eba 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -18,17 +18,7 @@
#include <linux/bcd.h>
#include <linux/rtc.h>
-#define DRV_VERSION "0.4.2"
-
-/* Addresses to scan: none
- * This chip cannot be reliably autodetected. An empty eeprom
- * located at 0x51 will pass the validation routine due to
- * the way the registers are implemented.
- */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Module parameters */
-I2C_CLIENT_INSMOD;
+#define DRV_VERSION "0.4.3"
#define PCF8563_REG_ST1 0x00 /* status */
#define PCF8563_REG_ST2 0x01
@@ -53,8 +43,10 @@ I2C_CLIENT_INSMOD;
#define PCF8563_SC_LV 0x80 /* low voltage */
#define PCF8563_MO_C 0x80 /* century */
+static struct i2c_driver pcf8563_driver;
+
struct pcf8563 {
- struct i2c_client client;
+ struct rtc_device *rtc;
/*
* The meaning of MO_C bit varies by the chip type.
* From PCF8563 datasheet: this bit is toggled when the years
@@ -72,16 +64,13 @@ struct pcf8563 {
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
};
-static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
-static int pcf8563_detach(struct i2c_client *client);
-
/*
* In the routines that deal directly with the pcf8563 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
*/
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
- struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
+ struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
@@ -91,7 +80,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
/* read registers */
if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -102,7 +91,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev,
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
- __FUNCTION__,
+ __func__,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7],
buf[8]);
@@ -123,7 +112,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -138,13 +127,13 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
- struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
+ struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
int i, err;
unsigned char buf[9];
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -174,7 +163,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
if (err != sizeof(data)) {
dev_err(&client->dev,
"%s: err=%d addr=%02x, data=%02x\n",
- __FUNCTION__, err, data[0], data[1]);
+ __func__, err, data[0], data[1]);
return -EIO;
}
};
@@ -219,7 +208,7 @@ static int pcf8563_validate_client(struct i2c_client *client)
if (xfer != ARRAY_SIZE(msgs)) {
dev_err(&client->dev,
"%s: could not read register 0x%02X\n",
- __FUNCTION__, pattern[i].reg);
+ __func__, pattern[i].reg);
return -EIO;
}
@@ -231,7 +220,7 @@ static int pcf8563_validate_client(struct i2c_client *client)
dev_dbg(&client->dev,
"%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
"max=%d, value=%d, raw=0x%02X\n",
- __FUNCTION__, i, pattern[i].reg, pattern[i].mask,
+ __func__, i, pattern[i].reg, pattern[i].mask,
pattern[i].min, pattern[i].max,
value, buf);
@@ -257,100 +246,67 @@ static const struct rtc_class_ops pcf8563_rtc_ops = {
.set_time = pcf8563_rtc_set_time,
};
-static int pcf8563_attach(struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, pcf8563_probe);
-}
-
-static struct i2c_driver pcf8563_driver = {
- .driver = {
- .name = "pcf8563",
- },
- .id = I2C_DRIVERID_PCF8563,
- .attach_adapter = &pcf8563_attach,
- .detach_client = &pcf8563_detach,
-};
-
-static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
+static int pcf8563_probe(struct i2c_client *client)
{
struct pcf8563 *pcf8563;
- struct i2c_client *client;
- struct rtc_device *rtc;
int err = 0;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&client->dev, "%s\n", __func__);
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
- err = -ENODEV;
- goto exit;
- }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
- if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &pcf8563->client;
- client->addr = address;
- client->driver = &pcf8563_driver;
- client->adapter = adapter;
-
- strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE);
+ pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);
+ if (!pcf8563)
+ return -ENOMEM;
/* Verify the chip is really an PCF8563 */
- if (kind < 0) {
- if (pcf8563_validate_client(client) < 0) {
- err = -ENODEV;
- goto exit_kfree;
- }
- }
-
- /* Inform the i2c layer */
- if ((err = i2c_attach_client(client)))
+ if (pcf8563_validate_client(client) < 0) {
+ err = -ENODEV;
goto exit_kfree;
+ }
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
- rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev,
- &pcf8563_rtc_ops, THIS_MODULE);
+ pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
+ &client->dev, &pcf8563_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- err = PTR_ERR(rtc);
- goto exit_detach;
+ if (IS_ERR(pcf8563->rtc)) {
+ err = PTR_ERR(pcf8563->rtc);
+ goto exit_kfree;
}
- i2c_set_clientdata(client, rtc);
+ i2c_set_clientdata(client, pcf8563);
return 0;
-exit_detach:
- i2c_detach_client(client);
-
exit_kfree:
kfree(pcf8563);
-exit:
return err;
}
-static int pcf8563_detach(struct i2c_client *client)
+static int pcf8563_remove(struct i2c_client *client)
{
- struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
- int err;
- struct rtc_device *rtc = i2c_get_clientdata(client);
+ struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
- if (rtc)
- rtc_device_unregister(rtc);
-
- if ((err = i2c_detach_client(client)))
- return err;
+ if (pcf8563->rtc)
+ rtc_device_unregister(pcf8563->rtc);
kfree(pcf8563);
return 0;
}
+static struct i2c_driver pcf8563_driver = {
+ .driver = {
+ .name = "rtc-pcf8563",
+ },
+ .probe = pcf8563_probe,
+ .remove = pcf8563_remove,
+};
+
static int __init pcf8563_init(void)
{
return i2c_add_driver(&pcf8563_driver);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 8b3997007506..3d09d8f0b1f0 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -15,7 +15,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
index 664e89a817ed..1c14d4497c4d 100644
--- a/drivers/rtc/rtc-rs5c313.c
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -228,7 +228,7 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
ndelay(700); /* CE:L */
if (cnt++ > 100) {
- dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+ dev_err(dev, "%s: timeout error\n", __func__);
return -EIO;
}
}
@@ -289,7 +289,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
ndelay(700); /* CE:L */
if (cnt++ > 100) {
- dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+ dev_err(dev, "%s: timeout error\n", __func__);
return -EIO;
}
}
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 6b67b5097927..7e63074708eb 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -99,7 +99,7 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
* least 80219 chips; this works around that bug.
*/
if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
- pr_debug("%s: can't read registers\n", rs5c->rtc->name);
+ dev_warn(&client->dev, "can't read registers\n");
return -EIO;
}
@@ -166,7 +166,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -181,7 +181,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -195,7 +195,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
buf[7] = BIN2BCD(tm->tm_year - 100);
if ((i2c_master_send(client, buf, 8)) != 8) {
- dev_err(&client->dev, "%s: write error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
}
@@ -220,7 +220,7 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
*osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768;
if (trim) {
- dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, tmp);
+ dev_dbg(&client->dev, "%s: raw trim=%x\n", __func__, tmp);
tmp &= RS5C372_TRIM_MASK;
if (tmp & 0x3e) {
int t = tmp & 0x3f;
@@ -500,7 +500,7 @@ static int rs5c372_probe(struct i2c_client *client)
struct rs5c372 *rs5c372;
struct rtc_time tm;
- dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
@@ -512,12 +512,12 @@ static int rs5c372_probe(struct i2c_client *client)
goto exit;
}
- /* we read registers 0x0f then 0x00-0x0f; skip the first one */
- rs5c372->regs=&rs5c372->buf[1];
-
rs5c372->client = client;
i2c_set_clientdata(client, rs5c372);
+ /* we read registers 0x0f then 0x00-0x0f; skip the first one */
+ rs5c372->regs = &rs5c372->buf[1];
+
err = rs5c_get_regs(rs5c372);
if (err < 0)
goto exit_kfree;
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 9f4d5129a496..f26e0cad8f16 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -68,7 +68,7 @@ static void s3c_rtc_setaie(int to)
{
unsigned int tmp;
- pr_debug("%s: aie=%d\n", __FUNCTION__, to);
+ pr_debug("%s: aie=%d\n", __func__, to);
tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
@@ -82,7 +82,7 @@ static void s3c_rtc_setpie(int to)
{
unsigned int tmp;
- pr_debug("%s: pie=%d\n", __FUNCTION__, to);
+ pr_debug("%s: pie=%d\n", __func__, to);
spin_lock_irq(&s3c_rtc_pie_lock);
tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
@@ -457,7 +457,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
+ pr_debug("%s: probe=%p\n", __func__, pdev);
/* find the IRQs */
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index c594b34c6767..110699bb4787 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -361,7 +361,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 4d27ccc4fc06..2531ce4c9db0 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -145,6 +145,8 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
unsigned long now, alarm;
struct rtc_wkalrm alm;
struct rtc_device *rtc = to_rtc_device(dev);
+ char *buf_ptr;
+ int adjust = 0;
/* Only request alarms that trigger in the future. Disable them
* by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
@@ -154,7 +156,15 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
return retval;
rtc_tm_to_time(&alm.time, &now);
- alarm = simple_strtoul(buf, NULL, 0);
+ buf_ptr = (char *)buf;
+ if (*buf_ptr == '+') {
+ buf_ptr++;
+ adjust = 1;
+ }
+ alarm = simple_strtoul(buf_ptr, NULL, 0);
+ if (adjust) {
+ alarm += now;
+ }
if (alarm > now) {
/* Avoid accidentally clobbering active alarms; we can't
* entirely prevent that here, without even the minimal
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index 254c9fce27da..bc930022004a 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -147,7 +147,7 @@ static int __devexit test_remove(struct platform_device *plat_dev)
return 0;
}
-static struct platform_driver test_drv = {
+static struct platform_driver test_driver = {
.probe = test_probe,
.remove = __devexit_p(test_remove),
.driver = {
@@ -160,7 +160,7 @@ static int __init test_init(void)
{
int err;
- if ((err = platform_driver_register(&test_drv)))
+ if ((err = platform_driver_register(&test_driver)))
return err;
if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) {
@@ -191,7 +191,7 @@ exit_free_test0:
platform_device_put(test0);
exit_driver_unregister:
- platform_driver_unregister(&test_drv);
+ platform_driver_unregister(&test_driver);
return err;
}
@@ -199,7 +199,7 @@ static void __exit test_exit(void)
{
platform_device_unregister(test0);
platform_device_unregister(test1);
- platform_driver_unregister(&test_drv);
+ platform_driver_unregister(&test_driver);
}
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 24203a06051a..10025d840268 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -107,7 +107,7 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt)
dt->tm_year = BCD2BIN(tmp)+100;
#ifdef DEBUG
- printk("\n%s : Read RTC values\n",__FUNCTION__);
+ printk("\n%s : Read RTC values\n",__func__);
printk("tm_hour: %i\n",dt->tm_hour);
printk("tm_min : %i\n",dt->tm_min);
printk("tm_sec : %i\n",dt->tm_sec);
@@ -126,7 +126,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
struct v3020 *chip = dev_get_drvdata(dev);
#ifdef DEBUG
- printk("\n%s : Setting RTC values\n",__FUNCTION__);
+ printk("\n%s : Setting RTC values\n",__func__);
printk("tm_sec : %i\n",dt->tm_sec);
printk("tm_min : %i\n",dt->tm_min);
printk("tm_hour: %i\n",dt->tm_hour);
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index b90fb1866ce9..095282f63523 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -22,20 +22,7 @@
#include <linux/rtc.h>
#include <linux/delay.h>
-#define DRV_VERSION "1.0.7"
-
-/* Addresses to scan: none. This chip is located at
- * 0x6f and uses a two bytes register addressing.
- * Two bytes need to be written to read a single register,
- * while most other chips just require one and take the second
- * one as the data to be written. To prevent corrupting
- * unknown chips, the user must explicitly set the probe parameter.
- */
-
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD;
+#define DRV_VERSION "1.0.8"
/* offsets into CCR area */
@@ -91,19 +78,7 @@ I2C_CLIENT_INSMOD;
#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */
-/* Prototypes */
-static int x1205_attach(struct i2c_adapter *adapter);
-static int x1205_detach(struct i2c_client *client);
-static int x1205_probe(struct i2c_adapter *adapter, int address, int kind);
-
-static struct i2c_driver x1205_driver = {
- .driver = {
- .name = "x1205",
- },
- .id = I2C_DRIVERID_X1205,
- .attach_adapter = &x1205_attach,
- .detach_client = &x1205_detach,
-};
+static struct i2c_driver x1205_driver;
/*
* In the routines that deal directly with the x1205 hardware, we use
@@ -124,14 +99,14 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
/* read date registers */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
dev_dbg(&client->dev,
"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
- __FUNCTION__,
+ __func__,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
@@ -146,7 +121,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -164,7 +139,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
/* read status register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -187,7 +162,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
dev_dbg(&client->dev,
"%s: secs=%d, mins=%d, hours=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour);
buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
@@ -200,7 +175,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
if (datetoo) {
dev_dbg(&client->dev,
"%s: mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
@@ -216,12 +191,12 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
/* this sequence is required to unlock the chip */
if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
- dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
+ dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
return -EIO;
}
if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
- dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
+ dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer);
return -EIO;
}
@@ -233,7 +208,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
if (xfer != 3) {
dev_err(&client->dev,
"%s: xfer=%d addr=%02x, data=%02x\n",
- __FUNCTION__,
+ __func__,
xfer, rdata[1], rdata[2]);
return -EIO;
}
@@ -241,7 +216,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
/* disable further writes */
if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
- dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
+ dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer);
return -EIO;
}
@@ -274,11 +249,11 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim)
/* read dtr register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
- dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
+ dev_dbg(&client->dev, "%s: raw dtr=%x\n", __func__, dtr);
*trim = 0;
@@ -306,11 +281,11 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
/* read atr register */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
- dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
+ dev_dbg(&client->dev, "%s: raw atr=%x\n", __func__, atr);
/* atr is a two's complement value on 6 bits,
* perform sign extension. The formula is
@@ -319,11 +294,11 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
if (atr & 0x20)
atr |= 0xC0;
- dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
+ dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __func__, atr, atr);
*trim = (atr * 250) + 11000;
- dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
+ dev_dbg(&client->dev, "%s: real=%d\n", __func__, *trim);
return 0;
}
@@ -377,7 +352,7 @@ static int x1205_validate_client(struct i2c_client *client)
if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
dev_err(&client->dev,
"%s: could not read register %x\n",
- __FUNCTION__, probe_zero_pattern[i]);
+ __func__, probe_zero_pattern[i]);
return -EIO;
}
@@ -385,7 +360,7 @@ static int x1205_validate_client(struct i2c_client *client)
if ((buf & probe_zero_pattern[i+1]) != 0) {
dev_err(&client->dev,
"%s: register=%02x, zero pattern=%d, value=%x\n",
- __FUNCTION__, probe_zero_pattern[i], i, buf);
+ __func__, probe_zero_pattern[i], i, buf);
return -ENODEV;
}
@@ -405,7 +380,7 @@ static int x1205_validate_client(struct i2c_client *client)
if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
dev_err(&client->dev,
"%s: could not read register %x\n",
- __FUNCTION__, probe_limits_pattern[i].reg);
+ __func__, probe_limits_pattern[i].reg);
return -EIO;
}
@@ -416,7 +391,7 @@ static int x1205_validate_client(struct i2c_client *client)
value < probe_limits_pattern[i].min) {
dev_dbg(&client->dev,
"%s: register=%x, lim pattern=%d, value=%d\n",
- __FUNCTION__, probe_limits_pattern[i].reg,
+ __func__, probe_limits_pattern[i].reg,
i, value);
return -ENODEV;
@@ -497,58 +472,49 @@ static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
}
static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
-static int x1205_attach(struct i2c_adapter *adapter)
+static int x1205_sysfs_register(struct device *dev)
+{
+ int err;
+
+ err = device_create_file(dev, &dev_attr_atrim);
+ if (err)
+ return err;
+
+ err = device_create_file(dev, &dev_attr_dtrim);
+ if (err)
+ device_remove_file(dev, &dev_attr_atrim);
+
+ return err;
+}
+
+static void x1205_sysfs_unregister(struct device *dev)
{
- return i2c_probe(adapter, &addr_data, x1205_probe);
+ device_remove_file(dev, &dev_attr_atrim);
+ device_remove_file(dev, &dev_attr_dtrim);
}
-static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
+
+static int x1205_probe(struct i2c_client *client)
{
int err = 0;
unsigned char sr;
- struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
- err = -ENODEV;
- goto exit;
- }
-
- if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* I2C client */
- client->addr = address;
- client->driver = &x1205_driver;
- client->adapter = adapter;
+ dev_dbg(&client->dev, "%s\n", __func__);
- strlcpy(client->name, x1205_driver.driver.name, I2C_NAME_SIZE);
-
- /* Verify the chip is really an X1205 */
- if (kind < 0) {
- if (x1205_validate_client(client) < 0) {
- err = -ENODEV;
- goto exit_kfree;
- }
- }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
- /* Inform the i2c layer */
- if ((err = i2c_attach_client(client)))
- goto exit_kfree;
+ if (x1205_validate_client(client) < 0)
+ return -ENODEV;
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
&x1205_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- err = PTR_ERR(rtc);
- goto exit_detach;
- }
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
@@ -565,45 +531,35 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
else
dev_err(&client->dev, "couldn't read status\n");
- err = device_create_file(&client->dev, &dev_attr_atrim);
- if (err) goto exit_devreg;
- err = device_create_file(&client->dev, &dev_attr_dtrim);
- if (err) goto exit_atrim;
+ err = x1205_sysfs_register(&client->dev);
+ if (err)
+ goto exit_devreg;
return 0;
-exit_atrim:
- device_remove_file(&client->dev, &dev_attr_atrim);
-
exit_devreg:
rtc_device_unregister(rtc);
-exit_detach:
- i2c_detach_client(client);
-
-exit_kfree:
- kfree(client);
-
-exit:
return err;
}
-static int x1205_detach(struct i2c_client *client)
+static int x1205_remove(struct i2c_client *client)
{
- int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
- if (rtc)
- rtc_device_unregister(rtc);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
- kfree(client);
-
+ rtc_device_unregister(rtc);
+ x1205_sysfs_unregister(&client->dev);
return 0;
}
+static struct i2c_driver x1205_driver = {
+ .driver = {
+ .name = "rtc-x1205",
+ },
+ .probe = x1205_probe,
+ .remove = x1205_remove,
+};
+
static int __init x1205_init(void)
{
return i2c_add_driver(&x1205_driver);
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 5a888704a8d0..4f4e7cf105d4 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -5,7 +5,7 @@
CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
obj-y += s390mach.o sysinfo.o s390_rdev.o
-obj-y += cio/ block/ char/ crypto/ net/ scsi/
+obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
drivers-y += drivers/s390/built-in.o
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 04787eab1016..bb52d2fbac18 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -36,7 +36,7 @@ static int dcssblk_open(struct inode *inode, struct file *filp);
static int dcssblk_release(struct inode *inode, struct file *filp);
static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
- unsigned long *data);
+ void **kaddr, unsigned long *pfn);
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
@@ -636,7 +636,7 @@ fail:
static int
dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
- unsigned long *data)
+ void **kaddr, unsigned long *pfn)
{
struct dcssblk_dev_info *dev_info;
unsigned long pgoff;
@@ -649,7 +649,9 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
pgoff = secnum / (PAGE_SIZE / 512);
if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
return -ERANGE;
- *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE);
+ *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
+ *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
+
return 0;
}
diff --git a/drivers/s390/kvm/Makefile b/drivers/s390/kvm/Makefile
new file mode 100644
index 000000000000..4a5ec39f9ca6
--- /dev/null
+++ b/drivers/s390/kvm/Makefile
@@ -0,0 +1,9 @@
+# Makefile for kvm guest drivers on s390
+#
+# Copyright IBM Corp. 2008
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (version 2 only)
+# as published by the Free Software Foundation.
+
+obj-$(CONFIG_VIRTIO) += kvm_virtio.o
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
new file mode 100644
index 000000000000..bbef3764fbf8
--- /dev/null
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -0,0 +1,338 @@
+/*
+ * kvm_virtio.c - virtio for kvm on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/interrupt.h>
+#include <linux/virtio_ring.h>
+#include <asm/io.h>
+#include <asm/kvm_para.h>
+#include <asm/kvm_virtio.h>
+#include <asm/setup.h>
+#include <asm/s390_ext.h>
+
+#define VIRTIO_SUBCODE_64 0x0D00
+
+/*
+ * The pointer to our (page) of device descriptions.
+ */
+static void *kvm_devices;
+
+/*
+ * Unique numbering for kvm devices.
+ */
+static unsigned int dev_index;
+
+struct kvm_device {
+ struct virtio_device vdev;
+ struct kvm_device_desc *desc;
+};
+
+#define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev)
+
+/*
+ * memory layout:
+ * - kvm_device_descriptor
+ * struct kvm_device_desc
+ * - configuration
+ * struct kvm_vqconfig
+ * - feature bits
+ * - config space
+ */
+static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc)
+{
+ return (struct kvm_vqconfig *)(desc + 1);
+}
+
+static u8 *kvm_vq_features(const struct kvm_device_desc *desc)
+{
+ return (u8 *)(kvm_vq_config(desc) + desc->num_vq);
+}
+
+static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc)
+{
+ return kvm_vq_features(desc) + desc->feature_len * 2;
+}
+
+/*
+ * The total size of the config page used by this device (incl. desc)
+ */
+static unsigned desc_size(const struct kvm_device_desc *desc)
+{
+ return sizeof(*desc)
+ + desc->num_vq * sizeof(struct kvm_vqconfig)
+ + desc->feature_len * 2
+ + desc->config_len;
+}
+
+/*
+ * This tests (and acknowleges) a feature bit.
+ */
+static bool kvm_feature(struct virtio_device *vdev, unsigned fbit)
+{
+ struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+ u8 *features;
+
+ if (fbit / 8 > desc->feature_len)
+ return false;
+
+ features = kvm_vq_features(desc);
+ if (!(features[fbit / 8] & (1 << (fbit % 8))))
+ return false;
+
+ /*
+ * We set the matching bit in the other half of the bitmap to tell the
+ * Host we want to use this feature.
+ */
+ features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
+ return true;
+}
+
+/*
+ * Reading and writing elements in config space
+ */
+static void kvm_get(struct virtio_device *vdev, unsigned int offset,
+ void *buf, unsigned len)
+{
+ struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+
+ BUG_ON(offset + len > desc->config_len);
+ memcpy(buf, kvm_vq_configspace(desc) + offset, len);
+}
+
+static void kvm_set(struct virtio_device *vdev, unsigned int offset,
+ const void *buf, unsigned len)
+{
+ struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+
+ BUG_ON(offset + len > desc->config_len);
+ memcpy(kvm_vq_configspace(desc) + offset, buf, len);
+}
+
+/*
+ * The operations to get and set the status word just access
+ * the status field of the device descriptor. set_status will also
+ * make a hypercall to the host, to tell about status changes
+ */
+static u8 kvm_get_status(struct virtio_device *vdev)
+{
+ return to_kvmdev(vdev)->desc->status;
+}
+
+static void kvm_set_status(struct virtio_device *vdev, u8 status)
+{
+ BUG_ON(!status);
+ to_kvmdev(vdev)->desc->status = status;
+ kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS,
+ (unsigned long) to_kvmdev(vdev)->desc);
+}
+
+/*
+ * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the
+ * descriptor address. The Host will zero the status and all the
+ * features.
+ */
+static void kvm_reset(struct virtio_device *vdev)
+{
+ kvm_hypercall1(KVM_S390_VIRTIO_RESET,
+ (unsigned long) to_kvmdev(vdev)->desc);
+}
+
+/*
+ * When the virtio_ring code wants to notify the Host, it calls us here and we
+ * make a hypercall. We hand the address of the virtqueue so the Host
+ * knows which virtqueue we're talking about.
+ */
+static void kvm_notify(struct virtqueue *vq)
+{
+ struct kvm_vqconfig *config = vq->priv;
+
+ kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address);
+}
+
+/*
+ * This routine finds the first virtqueue described in the configuration of
+ * this device and sets it up.
+ */
+static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
+ unsigned index,
+ void (*callback)(struct virtqueue *vq))
+{
+ struct kvm_device *kdev = to_kvmdev(vdev);
+ struct kvm_vqconfig *config;
+ struct virtqueue *vq;
+ int err;
+
+ if (index >= kdev->desc->num_vq)
+ return ERR_PTR(-ENOENT);
+
+ config = kvm_vq_config(kdev->desc)+index;
+
+ if (add_shared_memory(config->address,
+ vring_size(config->num, PAGE_SIZE))) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ vq = vring_new_virtqueue(config->num, vdev, (void *) config->address,
+ kvm_notify, callback);
+ if (!vq) {
+ err = -ENOMEM;
+ goto unmap;
+ }
+
+ /*
+ * register a callback token
+ * The host will sent this via the external interrupt parameter
+ */
+ config->token = (u64) vq;
+
+ vq->priv = config;
+ return vq;
+unmap:
+ remove_shared_memory(config->address, vring_size(config->num,
+ PAGE_SIZE));
+out:
+ return ERR_PTR(err);
+}
+
+static void kvm_del_vq(struct virtqueue *vq)
+{
+ struct kvm_vqconfig *config = vq->priv;
+
+ vring_del_virtqueue(vq);
+ remove_shared_memory(config->address,
+ vring_size(config->num, PAGE_SIZE));
+}
+
+/*
+ * The config ops structure as defined by virtio config
+ */
+static struct virtio_config_ops kvm_vq_configspace_ops = {
+ .feature = kvm_feature,
+ .get = kvm_get,
+ .set = kvm_set,
+ .get_status = kvm_get_status,
+ .set_status = kvm_set_status,
+ .reset = kvm_reset,
+ .find_vq = kvm_find_vq,
+ .del_vq = kvm_del_vq,
+};
+
+/*
+ * The root device for the kvm virtio devices.
+ * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2.
+ */
+static struct device kvm_root = {
+ .parent = NULL,
+ .bus_id = "kvm_s390",
+};
+
+/*
+ * adds a new device and register it with virtio
+ * appropriate drivers are loaded by the device model
+ */
+static void add_kvm_device(struct kvm_device_desc *d)
+{
+ struct kvm_device *kdev;
+
+ kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
+ if (!kdev) {
+ printk(KERN_EMERG "Cannot allocate kvm dev %u\n",
+ dev_index++);
+ return;
+ }
+
+ kdev->vdev.dev.parent = &kvm_root;
+ kdev->vdev.index = dev_index++;
+ kdev->vdev.id.device = d->type;
+ kdev->vdev.config = &kvm_vq_configspace_ops;
+ kdev->desc = d;
+
+ if (register_virtio_device(&kdev->vdev) != 0) {
+ printk(KERN_ERR "Failed to register kvm device %u\n",
+ kdev->vdev.index);
+ kfree(kdev);
+ }
+}
+
+/*
+ * scan_devices() simply iterates through the device page.
+ * The type 0 is reserved to mean "end of devices".
+ */
+static void scan_devices(void)
+{
+ unsigned int i;
+ struct kvm_device_desc *d;
+
+ for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
+ d = kvm_devices + i;
+
+ if (d->type == 0)
+ break;
+
+ add_kvm_device(d);
+ }
+}
+
+/*
+ * we emulate the request_irq behaviour on top of s390 extints
+ */
+static void kvm_extint_handler(u16 code)
+{
+ void *data = (void *) *(long *) __LC_PFAULT_INTPARM;
+ u16 subcode = S390_lowcore.cpu_addr;
+
+ if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
+ return;
+
+ vring_interrupt(0, data);
+}
+
+/*
+ * Init function for virtio
+ * devices are in a single page above top of "normal" mem
+ */
+static int __init kvm_devices_init(void)
+{
+ int rc;
+
+ if (!MACHINE_IS_KVM)
+ return -ENODEV;
+
+ rc = device_register(&kvm_root);
+ if (rc) {
+ printk(KERN_ERR "Could not register kvm_s390 root device");
+ return rc;
+ }
+
+ if (add_shared_memory((max_pfn) << PAGE_SHIFT, PAGE_SIZE)) {
+ device_unregister(&kvm_root);
+ return -ENOMEM;
+ }
+
+ kvm_devices = (void *) (max_pfn << PAGE_SHIFT);
+
+ ctl_set_bit(0, 9);
+ register_external_interrupt(0x2603, kvm_extint_handler);
+
+ scan_devices();
+ return 0;
+}
+
+/*
+ * We do this after core stuff, but before the drivers.
+ */
+postcore_initcall(kvm_devices_init);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 7c3f02816e95..9af2330f07a2 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1927,7 +1927,8 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
/* setup new FSF request */
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
- 0, NULL, &lock_flags, &fsf_req);
+ ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags,
+ &fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not create exchange configuration "
"data request for adapter %s.\n",
@@ -2035,21 +2036,21 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
min(FC_SERIAL_NUMBER_SIZE, 17));
}
- ZFCP_LOG_NORMAL("The adapter %s reported the following "
- "characteristics:\n"
- "WWNN 0x%016Lx, "
- "WWPN 0x%016Lx, "
- "S_ID 0x%06x,\n"
- "adapter version 0x%x, "
- "LIC version 0x%x, "
- "FC link speed %d Gb/s\n",
- zfcp_get_busid_by_adapter(adapter),
- (wwn_t) fc_host_node_name(shost),
- (wwn_t) fc_host_port_name(shost),
- fc_host_port_id(shost),
- adapter->hydra_version,
- adapter->fsf_lic_version,
- fc_host_speed(shost));
+ if (fsf_req->erp_action)
+ ZFCP_LOG_NORMAL("The adapter %s reported the following "
+ "characteristics:\n"
+ "WWNN 0x%016Lx, WWPN 0x%016Lx, "
+ "S_ID 0x%06x,\n"
+ "adapter version 0x%x, "
+ "LIC version 0x%x, "
+ "FC link speed %d Gb/s\n",
+ zfcp_get_busid_by_adapter(adapter),
+ (wwn_t) fc_host_node_name(shost),
+ (wwn_t) fc_host_port_name(shost),
+ fc_host_port_id(shost),
+ adapter->hydra_version,
+ adapter->fsf_lic_version,
+ fc_host_speed(shost));
if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
ZFCP_LOG_NORMAL("error: the adapter %s "
"only supports newer control block "
@@ -2114,8 +2115,10 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req);
return -EIO;
case FC_PORTTYPE_NPORT:
- ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
- "network detected at adapter %s.\n",
+ if (fsf_req->erp_action)
+ ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
+ "network detected at adapter "
+ "%s.\n",
zfcp_get_busid_by_adapter(adapter));
break;
default:
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 8cce5cc11d50..099970b27001 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -213,6 +213,7 @@
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
+#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
/* host connection features */
#define FSF_FEATURE_NPIV_MODE 0x00000001
@@ -340,6 +341,15 @@ struct fsf_qtcb_prefix {
u8 res1[20];
} __attribute__ ((packed));
+struct fsf_statistics_info {
+ u64 input_req;
+ u64 output_req;
+ u64 control_req;
+ u64 input_mb;
+ u64 output_mb;
+ u64 seconds_act;
+} __attribute__ ((packed));
+
union fsf_status_qual {
u8 byte[FSF_STATUS_QUALIFIER_SIZE];
u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)];
@@ -436,7 +446,8 @@ struct fsf_qtcb_bottom_config {
u32 hardware_version;
u8 serial_number[32];
struct fsf_nport_serv_param plogi_payload;
- u8 res4[160];
+ struct fsf_statistics_info stat_info;
+ u8 res4[112];
} __attribute__ ((packed));
struct fsf_qtcb_bottom_port {
@@ -469,7 +480,10 @@ struct fsf_qtcb_bottom_port {
u64 control_requests;
u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */
u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */
- u8 res2[256];
+ u8 cp_util;
+ u8 cb_util;
+ u8 a_util;
+ u8 res2[253];
} __attribute__ ((packed));
union fsf_qtcb_bottom {
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index f81850624eed..01687559dc06 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -40,6 +40,7 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int,
unsigned int, unsigned int);
static struct device_attribute *zfcp_sysfs_sdev_attrs[];
+static struct device_attribute *zfcp_a_stats_attrs[];
struct zfcp_data zfcp_data = {
.scsi_host_template = {
@@ -61,6 +62,7 @@ struct zfcp_data zfcp_data = {
.use_clustering = 1,
.sdev_attrs = zfcp_sysfs_sdev_attrs,
.max_sectors = ZFCP_MAX_SECTORS,
+ .shost_attrs = zfcp_a_stats_attrs,
},
.driver_version = ZFCP_VERSION,
};
@@ -809,4 +811,116 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
NULL
};
+static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *scsi_host = dev_to_shost(dev);
+ struct fsf_qtcb_bottom_port *qtcb_port;
+ int retval;
+ struct zfcp_adapter *adapter;
+
+ adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
+ if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA))
+ return -EOPNOTSUPP;
+
+ qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL);
+ if (!qtcb_port)
+ return -ENOMEM;
+
+ retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port);
+ if (!retval)
+ retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util,
+ qtcb_port->cb_util, qtcb_port->a_util);
+ kfree(qtcb_port);
+ return retval;
+}
+
+static int zfcp_sysfs_adapter_ex_config(struct device *dev,
+ struct fsf_statistics_info *stat_inf)
+{
+ int retval;
+ struct fsf_qtcb_bottom_config *qtcb_config;
+ struct Scsi_Host *scsi_host = dev_to_shost(dev);
+ struct zfcp_adapter *adapter;
+
+ adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
+ if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA))
+ return -EOPNOTSUPP;
+
+ qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config),
+ GFP_KERNEL);
+ if (!qtcb_config)
+ return -ENOMEM;
+
+ retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config);
+ if (!retval)
+ *stat_inf = qtcb_config->stat_info;
+
+ kfree(qtcb_config);
+ return retval;
+}
+
+static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct fsf_statistics_info stat_info;
+ int retval;
+
+ retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);
+ if (retval)
+ return retval;
+
+ return sprintf(buf, "%llu %llu %llu\n",
+ (unsigned long long) stat_info.input_req,
+ (unsigned long long) stat_info.output_req,
+ (unsigned long long) stat_info.control_req);
+}
+
+static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct fsf_statistics_info stat_info;
+ int retval;
+
+ retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);
+ if (retval)
+ return retval;
+
+ return sprintf(buf, "%llu %llu\n",
+ (unsigned long long) stat_info.input_mb,
+ (unsigned long long) stat_info.output_mb);
+}
+
+static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct fsf_statistics_info stat_info;
+ int retval;
+
+ retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);
+ if (retval)
+ return retval;
+
+ return sprintf(buf, "%llu\n",
+ (unsigned long long) stat_info.seconds_act);
+}
+
+static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL);
+static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL);
+static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL);
+static DEVICE_ATTR(seconds_active, S_IRUGO,
+ zfcp_sysfs_adapter_sec_active_show, NULL);
+
+static struct device_attribute *zfcp_a_stats_attrs[] = {
+ &dev_attr_utilization,
+ &dev_attr_requests,
+ &dev_attr_megabytes,
+ &dev_attr_seconds_active,
+ NULL
+};
+
#undef ZFCP_LOG_AREA
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index b374e457e5e2..b898d382b7b0 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -1499,7 +1499,7 @@ static void FlashPoint_StartCCB(unsigned long pCurrCard, struct sccb *p_Sccb)
thisCard = ((struct sccb_card *)pCurrCard)->cardIndex;
ioport = ((struct sccb_card *)pCurrCard)->ioPort;
- if ((p_Sccb->TargID > MAX_SCSI_TAR) || (p_Sccb->Lun > MAX_LUN)) {
+ if ((p_Sccb->TargID >= MAX_SCSI_TAR) || (p_Sccb->Lun >= MAX_LUN)) {
p_Sccb->HostStatus = SCCB_COMPLETE;
p_Sccb->SccbStatus = SCCB_ERROR;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 7f78e3ea517d..99c57b0c1d54 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1677,6 +1677,16 @@ config MAC_SCSI
SCSI-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
+config SCSI_MAC_ESP
+ tristate "Macintosh NCR53c9[46] SCSI"
+ depends on MAC && SCSI
+ help
+ This is the NCR 53c9x SCSI controller found on most of the 68040
+ based Macintoshes.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mac_esp.
+
config MVME147_SCSI
bool "WD33C93 SCSI driver for MVME147"
depends on MVME147 && SCSI=y
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 23e6ecbd4778..6c775e350c98 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o
obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
+obj-$(CONFIG_SCSI_MAC_ESP) += esp_scsi.o mac_esp.o
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 6ccdc96cc480..f5215fd4b73d 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -994,13 +994,13 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
SCpnt->SCp.sent_command = 0;
if(SCpnt->SCp.phase & (resetting|check_condition)) {
- if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
+ if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt));
return FAILED;
}
} else {
SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
- if(SCpnt->host_scribble==0) {
+ if(!SCpnt->host_scribble) {
printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
return FAILED;
}
@@ -1162,7 +1162,7 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
}
DO_LOCK(flags);
- issued = remove_SC(&ISSUE_SC, SCpnt)==0;
+ issued = remove_SC(&ISSUE_SC, SCpnt) == NULL;
disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
DO_UNLOCK(flags);
@@ -1432,15 +1432,10 @@ static void run(struct work_struct *work)
*/
static irqreturn_t intr(int irqno, void *dev_id)
{
- struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
+ struct Scsi_Host *shpnt = dev_id;
unsigned long flags;
unsigned char rev, dmacntrl0;
- if (!shpnt) {
- printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno);
- return IRQ_NONE;
- }
-
/*
* Read a couple of registers that are known to not be all 1's. If
* we read all 1's (-1), that means that either:
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 5a1471c370fa..80594947c6f6 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -153,8 +153,6 @@ struct aha1542_hostdata {
#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
-static struct Scsi_Host *aha_host[7]; /* One for each IRQ level (9-15) */
-
static DEFINE_SPINLOCK(aha1542_lock);
@@ -163,8 +161,7 @@ static DEFINE_SPINLOCK(aha1542_lock);
static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
static int aha1542_restart(struct Scsi_Host *shost);
-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id);
-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id);
+static void aha1542_intr_handle(struct Scsi_Host *shost);
#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
@@ -404,23 +401,19 @@ fail:
}
/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id)
+static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id)
{
unsigned long flags;
- struct Scsi_Host *shost;
-
- shost = aha_host[irq - 9];
- if (!shost)
- panic("Splunge!");
+ struct Scsi_Host *shost = dev_id;
spin_lock_irqsave(shost->host_lock, flags);
- aha1542_intr_handle(shost, dev_id);
+ aha1542_intr_handle(shost);
spin_unlock_irqrestore(shost->host_lock, flags);
return IRQ_HANDLED;
}
/* A "high" level interrupt handler */
-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
+static void aha1542_intr_handle(struct Scsi_Host *shost)
{
void (*my_done) (Scsi_Cmnd *) = NULL;
int errstatus, mbi, mbo, mbistatus;
@@ -1197,7 +1190,8 @@ fail:
DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
spin_lock_irqsave(&aha1542_lock, flags);
- if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
+ if (request_irq(irq_level, do_aha1542_intr_handle, 0,
+ "aha1542", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
spin_unlock_irqrestore(&aha1542_lock, flags);
goto unregister;
@@ -1205,7 +1199,7 @@ fail:
if (dma_chan != 0xFF) {
if (request_dma(dma_chan, "aha1542")) {
printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
- free_irq(irq_level, NULL);
+ free_irq(irq_level, shpnt);
spin_unlock_irqrestore(&aha1542_lock, flags);
goto unregister;
}
@@ -1214,7 +1208,7 @@ fail:
enable_dma(dma_chan);
}
}
- aha_host[irq_level - 9] = shpnt;
+
shpnt->this_id = scsi_id;
shpnt->unique_id = base_io;
shpnt->io_port = base_io;
@@ -1276,7 +1270,7 @@ unregister:
static int aha1542_release(struct Scsi_Host *shost)
{
if (shost->irq)
- free_irq(shost->irq, NULL);
+ free_irq(shost->irq, shost);
if (shost->dma_channel != 0xff)
free_dma(shost->dma_channel);
if (shost->io_port && shost->n_io_port)
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index 1ac119733bac..f220e5e436ab 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -50,7 +50,7 @@ aic7770_map_registers(struct ahc_softc *ahc, u_int port)
/*
* Lock out other contenders for our i/o space.
*/
- if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0)
+ if (!request_region(port, AHC_EISA_IOSIZE, "aic7xxx"))
return (ENOMEM);
ahc->tag = BUS_SPACE_PIO;
ahc->bsh.ioport = port;
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 2f00467b6b8c..be5558ab84ea 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -815,7 +815,7 @@ struct ahd_tmode_tstate {
struct ahd_phase_table_entry {
uint8_t phase;
uint8_t mesg_out; /* Message response to parity errors */
- char *phasemsg;
+ const char *phasemsg;
};
/************************** Serial EEPROM Format ******************************/
@@ -1314,7 +1314,7 @@ typedef int (ahd_device_setup_t)(struct ahd_softc *);
struct ahd_pci_identity {
uint64_t full_id;
uint64_t id_mask;
- char *name;
+ const char *name;
ahd_device_setup_t *setup;
};
@@ -1322,7 +1322,7 @@ struct ahd_pci_identity {
struct aic7770_identity {
uint32_t full_id;
uint32_t id_mask;
- char *name;
+ const char *name;
ahd_device_setup_t *setup;
};
extern struct aic7770_identity aic7770_ident_table [];
@@ -1333,12 +1333,11 @@ extern const int ahd_num_aic7770_devs;
/*************************** Function Declarations ****************************/
/******************************************************************************/
-void ahd_reset_cmds_pending(struct ahd_softc *ahd);
/***************************** PCI Front End *********************************/
-struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
+const struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
int ahd_pci_config(struct ahd_softc *,
- struct ahd_pci_identity *);
+ const struct ahd_pci_identity *);
int ahd_pci_test_register_access(struct ahd_softc *);
#ifdef CONFIG_PM
void ahd_pci_suspend(struct ahd_softc *);
@@ -1376,16 +1375,6 @@ int ahd_write_flexport(struct ahd_softc *ahd,
int ahd_read_flexport(struct ahd_softc *ahd, u_int addr,
uint8_t *value);
-/*************************** Interrupt Services *******************************/
-void ahd_run_qoutfifo(struct ahd_softc *ahd);
-#ifdef AHD_TARGET_MODE
-void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
-#endif
-void ahd_handle_hwerrint(struct ahd_softc *ahd);
-void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
-void ahd_handle_scsiint(struct ahd_softc *ahd,
- u_int intstat);
-
/***************************** Error Recovery *********************************/
typedef enum {
SEARCH_COMPLETE,
@@ -1479,7 +1468,7 @@ extern uint32_t ahd_debug;
void ahd_print_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
void ahd_dump_card_state(struct ahd_softc *ahd);
-int ahd_print_register(ahd_reg_parse_entry_t *table,
+int ahd_print_register(const ahd_reg_parse_entry_t *table,
u_int num_entries,
const char *name,
u_int address,
diff --git a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg
index be14e2ecb8f7..cca16fc5b4ad 100644
--- a/drivers/scsi/aic7xxx/aic79xx.reg
+++ b/drivers/scsi/aic7xxx/aic79xx.reg
@@ -198,6 +198,7 @@ register SEQINTCODE {
register CLRINT {
address 0x003
access_mode WO
+ count 19
field CLRHWERRINT 0x80 /* Rev B or greater */
field CLRBRKADRINT 0x40
field CLRSWTMINT 0x20
@@ -245,6 +246,7 @@ register CLRERR {
register HCNTRL {
address 0x005
access_mode RW
+ count 12
field SEQ_RESET 0x80 /* Rev B or greater */
field POWRDN 0x40
field SWINT 0x10
@@ -262,6 +264,7 @@ register HNSCB_QOFF {
address 0x006
access_mode RW
size 2
+ count 2
}
/*
@@ -270,6 +273,7 @@ register HNSCB_QOFF {
register HESCB_QOFF {
address 0x008
access_mode RW
+ count 2
}
/*
@@ -287,6 +291,7 @@ register HS_MAILBOX {
*/
register SEQINTSTAT {
address 0x00C
+ count 1
access_mode RO
field SEQ_SWTMRTO 0x10
field SEQ_SEQINT 0x08
@@ -332,6 +337,7 @@ register SNSCB_QOFF {
*/
register SESCB_QOFF {
address 0x012
+ count 2
access_mode RW
modes M_CCHAN
}
@@ -397,6 +403,7 @@ register DFCNTRL {
address 0x019
access_mode RW
modes M_DFF0, M_DFF1
+ count 11
field PRELOADEN 0x80
field SCSIENWRDIS 0x40 /* Rev B only. */
field SCSIEN 0x20
@@ -415,6 +422,7 @@ register DFCNTRL {
*/
register DSCOMMAND0 {
address 0x019
+ count 1
access_mode RW
modes M_CFG
field CACHETHEN 0x80 /* Cache Threshold enable */
@@ -580,6 +588,7 @@ register DFF_THRSH {
address 0x088
access_mode RW
modes M_CFG
+ count 1
field WR_DFTHRSH 0x70 {
WR_DFTHRSH_MIN,
WR_DFTHRSH_25,
@@ -800,6 +809,7 @@ register PCIXCTL {
address 0x093
access_mode RW
modes M_CFG
+ count 1
field SERRPULSE 0x80
field UNEXPSCIEN 0x20
field SPLTSMADIS 0x10
@@ -844,6 +854,7 @@ register DCHSPLTSTAT0 {
address 0x096
access_mode RW
modes M_DFF0, M_DFF1
+ count 2
field STAETERM 0x80
field SCBCERR 0x40
field SCADERR 0x20
@@ -895,6 +906,7 @@ register DCHSPLTSTAT1 {
address 0x097
access_mode RW
modes M_DFF0, M_DFF1
+ count 2
field RXDATABUCKET 0x01
}
@@ -1048,6 +1060,7 @@ register SGSPLTSTAT0 {
address 0x09E
access_mode RW
modes M_DFF0, M_DFF1
+ count 2
field STAETERM 0x80
field SCBCERR 0x40
field SCADERR 0x20
@@ -1065,6 +1078,7 @@ register SGSPLTSTAT1 {
address 0x09F
access_mode RW
modes M_DFF0, M_DFF1
+ count 2
field RXDATABUCKET 0x01
}
@@ -1086,6 +1100,7 @@ register DF0PCISTAT {
address 0x0A0
access_mode RW
modes M_CFG
+ count 1
field DPE 0x80
field SSE 0x40
field RMA 0x20
@@ -1184,6 +1199,7 @@ register TARGPCISTAT {
address 0x0A7
access_mode RW
modes M_CFG
+ count 5
field DPE 0x80
field SSE 0x40
field STA 0x08
@@ -1198,6 +1214,7 @@ register LQIN {
address 0x020
access_mode RW
size 20
+ count 2
modes M_DFF0, M_DFF1, M_SCSI
}
@@ -1229,6 +1246,7 @@ register LUNPTR {
address 0x022
access_mode RW
modes M_CFG
+ count 2
}
/*
@@ -1259,6 +1277,7 @@ register CMDLENPTR {
address 0x025
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1270,6 +1289,7 @@ register ATTRPTR {
address 0x026
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1281,6 +1301,7 @@ register FLAGPTR {
address 0x027
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1291,6 +1312,7 @@ register CMDPTR {
address 0x028
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1301,6 +1323,7 @@ register QNEXTPTR {
address 0x029
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1323,6 +1346,7 @@ register ABRTBYTEPTR {
address 0x02B
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1333,6 +1357,7 @@ register ABRTBITPTR {
address 0x02C
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1370,6 +1395,7 @@ register LUNLEN {
address 0x030
access_mode RW
modes M_CFG
+ count 2
mask ILUNLEN 0x0F
mask TLUNLEN 0xF0
}
@@ -1383,6 +1409,7 @@ register CDBLIMIT {
address 0x031
access_mode RW
modes M_CFG
+ count 1
}
/*
@@ -1394,6 +1421,7 @@ register MAXCMD {
address 0x032
access_mode RW
modes M_CFG
+ count 9
}
/*
@@ -1458,6 +1486,7 @@ register LQCTL1 {
address 0x038
access_mode RW
modes M_DFF0, M_DFF1, M_SCSI
+ count 2
field PCI2PCI 0x04
field SINGLECMD 0x02
field ABORTPENDING 0x01
@@ -1470,6 +1499,7 @@ register LQCTL2 {
address 0x039
access_mode RW
modes M_DFF0, M_DFF1, M_SCSI
+ count 5
field LQIRETRY 0x80
field LQICONTINUE 0x40
field LQITOIDLE 0x20
@@ -1528,6 +1558,7 @@ register SCSISEQ1 {
address 0x03B
access_mode RW
modes M_DFF0, M_DFF1, M_SCSI
+ count 8
field MANUALCTL 0x40
field ENSELI 0x20
field ENRSELI 0x10
@@ -1667,6 +1698,9 @@ register SCSISIGO {
}
}
+/*
+ * SCSI Control Signal In
+ */
register SCSISIGI {
address 0x041
access_mode RO
@@ -1703,6 +1737,7 @@ register MULTARGID {
access_mode RW
modes M_CFG
size 2
+ count 2
}
/*
@@ -1758,6 +1793,7 @@ register TARGIDIN {
address 0x048
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 2
field CLKOUT 0x80
field TARGID 0x0F
}
@@ -1798,6 +1834,7 @@ register OPTIONMODE {
address 0x04A
access_mode RW
modes M_CFG
+ count 4
field BIOSCANCTL 0x80
field AUTOACKEN 0x40
field BIASCANCTL 0x20
@@ -1850,6 +1887,7 @@ register SIMODE0 {
address 0x04B
access_mode RW
modes M_CFG
+ count 8
field ENSELDO 0x40
field ENSELDI 0x20
field ENSELINGO 0x10
@@ -1945,6 +1983,7 @@ register PERRDIAG {
address 0x04E
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 3
field HIZERO 0x80
field HIPERR 0x40
field PREVPHASE 0x20
@@ -1962,6 +2001,7 @@ register LQISTATE {
address 0x04E
access_mode RO
modes M_CFG
+ count 6
}
/*
@@ -1971,6 +2011,7 @@ register SOFFCNT {
address 0x04F
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 1
}
/*
@@ -1980,6 +2021,7 @@ register LQOSTATE {
address 0x04F
access_mode RO
modes M_CFG
+ count 2
}
/*
@@ -1989,6 +2031,7 @@ register LQISTAT0 {
address 0x050
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 2
field LQIATNQAS 0x20
field LQICRCT1 0x10
field LQICRCT2 0x08
@@ -2004,6 +2047,7 @@ register CLRLQIINT0 {
address 0x050
access_mode WO
modes M_DFF0, M_DFF1, M_SCSI
+ count 1
field CLRLQIATNQAS 0x20
field CLRLQICRCT1 0x10
field CLRLQICRCT2 0x08
@@ -2019,6 +2063,7 @@ register LQIMODE0 {
address 0x050
access_mode RW
modes M_CFG
+ count 3
field ENLQIATNQASK 0x20
field ENLQICRCT1 0x10
field ENLQICRCT2 0x08
@@ -2034,6 +2079,7 @@ register LQISTAT1 {
address 0x051
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 3
field LQIPHASE_LQ 0x80
field LQIPHASE_NLQ 0x40
field LQIABORT 0x20
@@ -2051,6 +2097,7 @@ register CLRLQIINT1 {
address 0x051
access_mode WO
modes M_DFF0, M_DFF1, M_SCSI
+ count 4
field CLRLQIPHASE_LQ 0x80
field CLRLQIPHASE_NLQ 0x40
field CLRLIQABORT 0x20
@@ -2068,6 +2115,7 @@ register LQIMODE1 {
address 0x051
access_mode RW
modes M_CFG
+ count 4
field ENLQIPHASE_LQ 0x80 /* LQIPHASE1 */
field ENLQIPHASE_NLQ 0x40 /* LQIPHASE2 */
field ENLIQABORT 0x20
@@ -2102,6 +2150,7 @@ register SSTAT3 {
address 0x053
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 3
field NTRAMPERR 0x02
field OSRAMPERR 0x01
}
@@ -2113,6 +2162,7 @@ register CLRSINT3 {
address 0x053
access_mode WO
modes M_DFF0, M_DFF1, M_SCSI
+ count 3
field CLRNTRAMPERR 0x02
field CLROSRAMPERR 0x01
}
@@ -2124,6 +2174,7 @@ register SIMODE3 {
address 0x053
access_mode RW
modes M_CFG
+ count 4
field ENNTRAMPERR 0x02
field ENOSRAMPERR 0x01
}
@@ -2135,6 +2186,7 @@ register LQOSTAT0 {
address 0x054
access_mode RO
modes M_DFF0, M_DFF1, M_SCSI
+ count 2
field LQOTARGSCBPERR 0x10
field LQOSTOPT2 0x08
field LQOATNLQ 0x04
@@ -2149,6 +2201,7 @@ register CLRLQOINT0 {
address 0x054
access_mode WO
modes M_DFF0, M_DFF1, M_SCSI
+ count 3
field CLRLQOTARGSCBPERR 0x10
field CLRLQOSTOPT2 0x08
field CLRLQOATNLQ 0x04
@@ -2163,6 +2216,7 @@ register LQOMODE0 {
address 0x054
access_mode RW
modes M_CFG
+ count 4
field ENLQOTARGSCBPERR 0x10
field ENLQOSTOPT2 0x08
field ENLQOATNLQ 0x04
@@ -2191,6 +2245,7 @@ register CLRLQOINT1 {
address 0x055
access_mode WO
modes M_DFF0, M_DFF1, M_SCSI
+ count 7
field CLRLQOINITSCBPERR 0x10
field CLRLQOSTOPI2 0x08
field CLRLQOBADQAS 0x04
@@ -2205,6 +2260,7 @@ register LQOMODE1 {
address 0x055
access_mode RW
modes M_CFG
+ count 4
field ENLQOINITSCBPERR 0x10
field ENLQOSTOPI2 0x08
field ENLQOBADQAS 0x04
@@ -2232,6 +2288,7 @@ register OS_SPACE_CNT {
address 0x056
access_mode RO
modes M_CFG
+ count 2
}
/*
@@ -2286,13 +2343,19 @@ register NEXTSCB {
modes M_SCSI
}
-/* Rev B only. */
+/*
+ * LQO SCSI Control
+ * (Rev B only.)
+ */
register LQOSCSCTL {
address 0x05A
access_mode RW
size 1
modes M_CFG
+ count 1
field LQOH2A_VERSION 0x80
+ field LQOBUSETDLY 0x40
+ field LQONOHOLDLACK 0x02
field LQONOCHKOVER 0x01
}
@@ -2459,6 +2522,7 @@ register NEGPERIOD {
address 0x061
access_mode RW
modes M_SCSI
+ count 1
}
/*
@@ -2478,6 +2542,7 @@ register NEGOFFSET {
address 0x062
access_mode RW
modes M_SCSI
+ count 1
}
/*
@@ -2487,6 +2552,7 @@ register NEGPPROPTS {
address 0x063
access_mode RW
modes M_SCSI
+ count 1
field PPROPT_PACE 0x08
field PPROPT_QAS 0x04
field PPROPT_DT 0x02
@@ -2516,12 +2582,19 @@ register ANNEXCOL {
address 0x065
access_mode RW
modes M_SCSI
+ count 7
}
+/*
+ * SCSI Check
+ * (Rev. B only)
+ */
register SCSCHKN {
address 0x066
access_mode RW
modes M_CFG
+ count 1
+ field BIDICHKDIS 0x80
field STSELSKIDDIS 0x40
field CURRFIFODEF 0x20
field WIDERESEN 0x10
@@ -2561,6 +2634,7 @@ register ANNEXDAT {
address 0x066
access_mode RW
modes M_SCSI
+ count 3
}
/*
@@ -2596,6 +2670,7 @@ register TOWNID {
address 0x069
access_mode RW
modes M_SCSI
+ count 2
}
/*
@@ -2737,6 +2812,7 @@ register SCBAUTOPTR {
address 0x0AB
access_mode RW
modes M_CFG
+ count 1
field AUSCBPTR_EN 0x80
field SCBPTR_ADDR 0x38
field SCBPTR_OFF 0x07
@@ -2881,6 +2957,7 @@ register BRDDAT {
address 0x0B8
access_mode RW
modes M_SCSI
+ count 2
}
/*
@@ -2890,6 +2967,7 @@ register BRDCTL {
address 0x0B9
access_mode RW
modes M_SCSI
+ count 7
field FLXARBACK 0x80
field FLXARBREQ 0x40
field BRDADDR 0x38
@@ -2905,6 +2983,7 @@ register SEEADR {
address 0x0BA
access_mode RW
modes M_SCSI
+ count 4
}
/*
@@ -2915,6 +2994,7 @@ register SEEDAT {
access_mode RW
size 2
modes M_SCSI
+ count 4
}
/*
@@ -2924,6 +3004,7 @@ register SEESTAT {
address 0x0BE
access_mode RO
modes M_SCSI
+ count 1
field INIT_DONE 0x80
field SEEOPCODE 0x70
field LDALTID_L 0x08
@@ -2939,6 +3020,7 @@ register SEECTL {
address 0x0BE
access_mode RW
modes M_SCSI
+ count 4
field SEEOPCODE 0x70 {
SEEOP_ERASE 0x70,
SEEOP_READ 0x60,
@@ -3000,6 +3082,7 @@ register DSPDATACTL {
address 0x0C1
access_mode RW
modes M_CFG
+ count 3
field BYPASSENAB 0x80
field DESQDIS 0x10
field RCVROFFSTDIS 0x04
@@ -3058,6 +3141,7 @@ register DSPSELECT {
address 0x0C4
access_mode RW
modes M_CFG
+ count 1
field AUTOINCEN 0x80
field DSPSEL 0x1F
}
@@ -3071,6 +3155,7 @@ register WRTBIASCTL {
address 0x0C5
access_mode WO
modes M_CFG
+ count 3
field AUTOXBCDIS 0x80
field XMITMANVAL 0x3F
}
@@ -3196,7 +3281,8 @@ register OVLYADDR {
*/
register SEQCTL0 {
address 0x0D6
- access_mode RW
+ access_mode RW
+ count 11
field PERRORDIS 0x80
field PAUSEDIS 0x40
field FAILDIS 0x20
@@ -3226,7 +3312,8 @@ register SEQCTL1 {
*/
register FLAGS {
address 0x0D8
- access_mode RO
+ access_mode RO
+ count 23
field ZERO 0x02
field CARRY 0x01
}
@@ -3255,7 +3342,8 @@ register SEQINTCTL {
*/
register SEQRAM {
address 0x0DA
- access_mode RW
+ access_mode RW
+ count 2
}
/*
@@ -3266,6 +3354,7 @@ register PRGMCNT {
address 0x0DE
access_mode RW
size 2
+ count 5
}
/*
@@ -3273,7 +3362,7 @@ register PRGMCNT {
*/
register ACCUM {
address 0x0E0
- access_mode RW
+ access_mode RW
accumulator
}
@@ -3401,6 +3490,7 @@ register INTVEC1_ADDR {
access_mode RW
size 2
modes M_CFG
+ count 1
}
/*
@@ -3412,6 +3502,7 @@ register CURADDR {
access_mode RW
size 2
modes M_SCSI
+ count 2
}
/*
@@ -3423,6 +3514,7 @@ register INTVEC2_ADDR {
access_mode RW
size 2
modes M_CFG
+ count 1
}
/*
@@ -3579,6 +3671,7 @@ scratch_ram {
/* Parameters for DMA Logic */
DMAPARAMS {
size 1
+ count 8
field PRELOADEN 0x80
field WIDEODD 0x40
field SCSIEN 0x20
@@ -3648,9 +3741,11 @@ scratch_ram {
*/
KERNEL_TQINPOS {
size 1
+ count 1
}
- TQINPOS {
+ TQINPOS {
size 1
+ count 8
}
/*
* Base address of our shared data with the kernel driver in host
@@ -3681,6 +3776,7 @@ scratch_ram {
}
ARG_2 {
size 1
+ count 1
alias RETURN_2
}
@@ -3698,6 +3794,7 @@ scratch_ram {
*/
SCSISEQ_TEMPLATE {
size 1
+ count 7
field MANUALCTL 0x40
field ENSELI 0x20
field ENRSELI 0x10
@@ -3711,6 +3808,7 @@ scratch_ram {
*/
INITIATOR_TAG {
size 1
+ count 1
}
SEQ_FLAGS2 {
@@ -3777,6 +3875,7 @@ scratch_ram {
*/
CMDSIZE_TABLE {
size 8
+ count 8
}
/*
* When an SCB with the MK_MESSAGE flag is
@@ -3803,8 +3902,8 @@ scratch_ram {
/************************* Hardware SCB Definition ****************************/
scb {
address 0x180
- size 64
- modes 0, 1, 2, 3
+ size 64
+ modes 0, 1, 2, 3
SCB_RESIDUAL_DATACNT {
size 4
alias SCB_CDB_STORE
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index ade0fb8fbdb2..55508b0fcec4 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -52,7 +52,7 @@
/***************************** Lookup Tables **********************************/
-static char *ahd_chip_names[] =
+static const char *const ahd_chip_names[] =
{
"NONE",
"aic7901",
@@ -66,10 +66,10 @@ static const u_int num_chip_names = ARRAY_SIZE(ahd_chip_names);
*/
struct ahd_hard_error_entry {
uint8_t errno;
- char *errmesg;
+ const char *errmesg;
};
-static struct ahd_hard_error_entry ahd_hard_errors[] = {
+static const struct ahd_hard_error_entry ahd_hard_errors[] = {
{ DSCTMOUT, "Discard Timer has timed out" },
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
{ SQPARERR, "Sequencer Parity Error" },
@@ -79,7 +79,7 @@ static struct ahd_hard_error_entry ahd_hard_errors[] = {
};
static const u_int num_errors = ARRAY_SIZE(ahd_hard_errors);
-static struct ahd_phase_table_entry ahd_phase_table[] =
+static const struct ahd_phase_table_entry ahd_phase_table[] =
{
{ P_DATAOUT, MSG_NOOP, "in Data-out phase" },
{ P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" },
@@ -213,7 +213,7 @@ static void ahd_dumpseq(struct ahd_softc *ahd);
#endif
static void ahd_loadseq(struct ahd_softc *ahd);
static int ahd_check_patch(struct ahd_softc *ahd,
- struct patch **start_patch,
+ const struct patch **start_patch,
u_int start_instr, u_int *skip_addr);
static u_int ahd_resolve_seqaddr(struct ahd_softc *ahd,
u_int address);
@@ -254,7 +254,7 @@ static void ahd_freeze_devq(struct ahd_softc *ahd,
struct scb *scb);
static void ahd_handle_scb_status(struct ahd_softc *ahd,
struct scb *scb);
-static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
+static const struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
static void ahd_shutdown(void *arg);
static void ahd_update_coalescing_values(struct ahd_softc *ahd,
u_int timer,
@@ -266,8 +266,774 @@ static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
int target, char channel, int lun,
u_int tag, role_t role);
-/******************************** Private Inlines *****************************/
+static void ahd_reset_cmds_pending(struct ahd_softc *ahd);
+
+/*************************** Interrupt Services *******************************/
+static void ahd_run_qoutfifo(struct ahd_softc *ahd);
+#ifdef AHD_TARGET_MODE
+static void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
+#endif
+static void ahd_handle_hwerrint(struct ahd_softc *ahd);
+static void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
+static void ahd_handle_scsiint(struct ahd_softc *ahd,
+ u_int intstat);
+
+/************************ Sequencer Execution Control *************************/
+void
+ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
+{
+ if (ahd->src_mode == src && ahd->dst_mode == dst)
+ return;
+#ifdef AHD_DEBUG
+ if (ahd->src_mode == AHD_MODE_UNKNOWN
+ || ahd->dst_mode == AHD_MODE_UNKNOWN)
+ panic("Setting mode prior to saving it.\n");
+ if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
+ printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
+ ahd_build_mode_state(ahd, src, dst));
+#endif
+ ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
+ ahd->src_mode = src;
+ ahd->dst_mode = dst;
+}
+
+static void
+ahd_update_modes(struct ahd_softc *ahd)
+{
+ ahd_mode_state mode_ptr;
+ ahd_mode src;
+ ahd_mode dst;
+
+ mode_ptr = ahd_inb(ahd, MODE_PTR);
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
+ printf("Reading mode 0x%x\n", mode_ptr);
+#endif
+ ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
+ ahd_known_modes(ahd, src, dst);
+}
+
+static void
+ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
+ ahd_mode dstmode, const char *file, int line)
+{
+#ifdef AHD_DEBUG
+ if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
+ || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
+ panic("%s:%s:%d: Mode assertion failed.\n",
+ ahd_name(ahd), file, line);
+ }
+#endif
+}
+
+#define AHD_ASSERT_MODES(ahd, source, dest) \
+ ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
+
+ahd_mode_state
+ahd_save_modes(struct ahd_softc *ahd)
+{
+ if (ahd->src_mode == AHD_MODE_UNKNOWN
+ || ahd->dst_mode == AHD_MODE_UNKNOWN)
+ ahd_update_modes(ahd);
+
+ return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
+}
+
+void
+ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
+{
+ ahd_mode src;
+ ahd_mode dst;
+
+ ahd_extract_mode_state(ahd, state, &src, &dst);
+ ahd_set_modes(ahd, src, dst);
+}
+
+/*
+ * Determine whether the sequencer has halted code execution.
+ * Returns non-zero status if the sequencer is stopped.
+ */
+int
+ahd_is_paused(struct ahd_softc *ahd)
+{
+ return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
+}
+
+/*
+ * Request that the sequencer stop and wait, indefinitely, for it
+ * to stop. The sequencer will only acknowledge that it is paused
+ * once it has reached an instruction boundary and PAUSEDIS is
+ * cleared in the SEQCTL register. The sequencer may use PAUSEDIS
+ * for critical sections.
+ */
+void
+ahd_pause(struct ahd_softc *ahd)
+{
+ ahd_outb(ahd, HCNTRL, ahd->pause);
+
+ /*
+ * Since the sequencer can disable pausing in a critical section, we
+ * must loop until it actually stops.
+ */
+ while (ahd_is_paused(ahd) == 0)
+ ;
+}
+
+/*
+ * Allow the sequencer to continue program execution.
+ * We check here to ensure that no additional interrupt
+ * sources that would cause the sequencer to halt have been
+ * asserted. If, for example, a SCSI bus reset is detected
+ * while we are fielding a different, pausing, interrupt type,
+ * we don't want to release the sequencer before going back
+ * into our interrupt handler and dealing with this new
+ * condition.
+ */
+void
+ahd_unpause(struct ahd_softc *ahd)
+{
+ /*
+ * Automatically restore our modes to those saved
+ * prior to the first change of the mode.
+ */
+ if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
+ && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
+ if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
+ ahd_reset_cmds_pending(ahd);
+ ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
+ }
+
+ if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
+ ahd_outb(ahd, HCNTRL, ahd->unpause);
+
+ ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
+}
+
+/*********************** Scatter Gather List Handling *************************/
+void *
+ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
+ void *sgptr, dma_addr_t addr, bus_size_t len, int last)
+{
+ scb->sg_count++;
+ if (sizeof(dma_addr_t) > 4
+ && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+ struct ahd_dma64_seg *sg;
+
+ sg = (struct ahd_dma64_seg *)sgptr;
+ sg->addr = ahd_htole64(addr);
+ sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
+ return (sg + 1);
+ } else {
+ struct ahd_dma_seg *sg;
+ sg = (struct ahd_dma_seg *)sgptr;
+ sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
+ sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
+ | (last ? AHD_DMA_LAST_SEG : 0));
+ return (sg + 1);
+ }
+}
+
+static void
+ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
+{
+ /* XXX Handle target mode SCBs. */
+ scb->crc_retry_count = 0;
+ if ((scb->flags & SCB_PACKETIZED) != 0) {
+ /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
+ scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
+ } else {
+ if (ahd_get_transfer_length(scb) & 0x01)
+ scb->hscb->task_attribute = SCB_XFERLEN_ODD;
+ else
+ scb->hscb->task_attribute = 0;
+ }
+
+ if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
+ || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
+ scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
+ ahd_htole32(scb->sense_busaddr);
+}
+
+static void
+ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+ /*
+ * Copy the first SG into the "current" data ponter area.
+ */
+ if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+ struct ahd_dma64_seg *sg;
+
+ sg = (struct ahd_dma64_seg *)scb->sg_list;
+ scb->hscb->dataptr = sg->addr;
+ scb->hscb->datacnt = sg->len;
+ } else {
+ struct ahd_dma_seg *sg;
+ uint32_t *dataptr_words;
+
+ sg = (struct ahd_dma_seg *)scb->sg_list;
+ dataptr_words = (uint32_t*)&scb->hscb->dataptr;
+ dataptr_words[0] = sg->addr;
+ dataptr_words[1] = 0;
+ if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
+ uint64_t high_addr;
+
+ high_addr = ahd_le32toh(sg->len) & 0x7F000000;
+ scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
+ }
+ scb->hscb->datacnt = sg->len;
+ }
+ /*
+ * Note where to find the SG entries in bus space.
+ * We also set the full residual flag which the
+ * sequencer will clear as soon as a data transfer
+ * occurs.
+ */
+ scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
+}
+
+static void
+ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+ scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
+ scb->hscb->dataptr = 0;
+ scb->hscb->datacnt = 0;
+}
+
+/************************** Memory mapping routines ***************************/
+static void *
+ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
+{
+ dma_addr_t sg_offset;
+
+ /* sg_list_phys points to entry 1, not 0 */
+ sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
+ return ((uint8_t *)scb->sg_list + sg_offset);
+}
+
+static uint32_t
+ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
+{
+ dma_addr_t sg_offset;
+
+ /* sg_list_phys points to entry 1, not 0 */
+ sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
+ - ahd_sg_size(ahd);
+
+ return (scb->sg_list_busaddr + sg_offset);
+}
+
+static void
+ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
+{
+ ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
+ scb->hscb_map->dmamap,
+ /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
+ /*len*/sizeof(*scb->hscb), op);
+}
+
+void
+ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
+{
+ if (scb->sg_count == 0)
+ return;
+
+ ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
+ scb->sg_map->dmamap,
+ /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
+ /*len*/ahd_sg_size(ahd) * scb->sg_count, op);
+}
+
+static void
+ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
+{
+ ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
+ scb->sense_map->dmamap,
+ /*offset*/scb->sense_busaddr,
+ /*len*/AHD_SENSE_BUFSIZE, op);
+}
+
+#ifdef AHD_TARGET_MODE
+static uint32_t
+ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
+{
+ return (((uint8_t *)&ahd->targetcmds[index])
+ - (uint8_t *)ahd->qoutfifo);
+}
+#endif
+
+/*********************** Miscelaneous Support Functions ***********************/
+/*
+ * Return pointers to the transfer negotiation information
+ * for the specified our_id/remote_id pair.
+ */
+struct ahd_initiator_tinfo *
+ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
+ u_int remote_id, struct ahd_tmode_tstate **tstate)
+{
+ /*
+ * Transfer data structures are stored from the perspective
+ * of the target role. Since the parameters for a connection
+ * in the initiator role to a given target are the same as
+ * when the roles are reversed, we pretend we are the target.
+ */
+ if (channel == 'B')
+ our_id += 8;
+ *tstate = ahd->enabled_targets[our_id];
+ return (&(*tstate)->transinfo[remote_id]);
+}
+
+uint16_t
+ahd_inw(struct ahd_softc *ahd, u_int port)
+{
+ /*
+ * Read high byte first as some registers increment
+ * or have other side effects when the low byte is
+ * read.
+ */
+ uint16_t r = ahd_inb(ahd, port+1) << 8;
+ return r | ahd_inb(ahd, port);
+}
+
+void
+ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
+{
+ /*
+ * Write low byte first to accomodate registers
+ * such as PRGMCNT where the order maters.
+ */
+ ahd_outb(ahd, port, value & 0xFF);
+ ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
+}
+
+uint32_t
+ahd_inl(struct ahd_softc *ahd, u_int port)
+{
+ return ((ahd_inb(ahd, port))
+ | (ahd_inb(ahd, port+1) << 8)
+ | (ahd_inb(ahd, port+2) << 16)
+ | (ahd_inb(ahd, port+3) << 24));
+}
+
+void
+ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
+{
+ ahd_outb(ahd, port, (value) & 0xFF);
+ ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
+ ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
+ ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
+}
+
+uint64_t
+ahd_inq(struct ahd_softc *ahd, u_int port)
+{
+ return ((ahd_inb(ahd, port))
+ | (ahd_inb(ahd, port+1) << 8)
+ | (ahd_inb(ahd, port+2) << 16)
+ | (ahd_inb(ahd, port+3) << 24)
+ | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
+ | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
+ | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
+ | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
+}
+
+void
+ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
+{
+ ahd_outb(ahd, port, value & 0xFF);
+ ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
+ ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
+ ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
+ ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
+ ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
+ ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
+ ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
+}
+
+u_int
+ahd_get_scbptr(struct ahd_softc *ahd)
+{
+ AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+ ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+ return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
+}
+
+void
+ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
+{
+ AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+ ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+ ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
+ ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
+}
+
+#if 0 /* unused */
+static u_int
+ahd_get_hnscb_qoff(struct ahd_softc *ahd)
+{
+ return (ahd_inw_atomic(ahd, HNSCB_QOFF));
+}
+#endif
+
+static void
+ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
+{
+ ahd_outw_atomic(ahd, HNSCB_QOFF, value);
+}
+
+#if 0 /* unused */
+static u_int
+ahd_get_hescb_qoff(struct ahd_softc *ahd)
+{
+ return (ahd_inb(ahd, HESCB_QOFF));
+}
+#endif
+
+static void
+ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
+{
+ ahd_outb(ahd, HESCB_QOFF, value);
+}
+
+static u_int
+ahd_get_snscb_qoff(struct ahd_softc *ahd)
+{
+ u_int oldvalue;
+
+ AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+ oldvalue = ahd_inw(ahd, SNSCB_QOFF);
+ ahd_outw(ahd, SNSCB_QOFF, oldvalue);
+ return (oldvalue);
+}
+
+static void
+ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
+{
+ AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+ ahd_outw(ahd, SNSCB_QOFF, value);
+}
+
+#if 0 /* unused */
+static u_int
+ahd_get_sescb_qoff(struct ahd_softc *ahd)
+{
+ AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+ return (ahd_inb(ahd, SESCB_QOFF));
+}
+#endif
+
+static void
+ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
+{
+ AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+ ahd_outb(ahd, SESCB_QOFF, value);
+}
+
+#if 0 /* unused */
+static u_int
+ahd_get_sdscb_qoff(struct ahd_softc *ahd)
+{
+ AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+ return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
+}
+#endif
+
+static void
+ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
+{
+ AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+ ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
+ ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
+}
+
+u_int
+ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
+{
+ u_int value;
+
+ /*
+ * Workaround PCI-X Rev A. hardware bug.
+ * After a host read of SCB memory, the chip
+ * may become confused into thinking prefetch
+ * was required. This starts the discard timer
+ * running and can cause an unexpected discard
+ * timer interrupt. The work around is to read
+ * a normal register prior to the exhaustion of
+ * the discard timer. The mode pointer register
+ * has no side effects and so serves well for
+ * this purpose.
+ *
+ * Razor #528
+ */
+ value = ahd_inb(ahd, offset);
+ if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
+ ahd_inb(ahd, MODE_PTR);
+ return (value);
+}
+
+u_int
+ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
+{
+ return (ahd_inb_scbram(ahd, offset)
+ | (ahd_inb_scbram(ahd, offset+1) << 8));
+}
+
+static uint32_t
+ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
+{
+ return (ahd_inw_scbram(ahd, offset)
+ | (ahd_inw_scbram(ahd, offset+2) << 16));
+}
+
+static uint64_t
+ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
+{
+ return (ahd_inl_scbram(ahd, offset)
+ | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
+}
+
+struct scb *
+ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
+{
+ struct scb* scb;
+
+ if (tag >= AHD_SCB_MAX)
+ return (NULL);
+ scb = ahd->scb_data.scbindex[tag];
+ if (scb != NULL)
+ ahd_sync_scb(ahd, scb,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ return (scb);
+}
+
+static void
+ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
+{
+ struct hardware_scb *q_hscb;
+ struct map_node *q_hscb_map;
+ uint32_t saved_hscb_busaddr;
+
+ /*
+ * Our queuing method is a bit tricky. The card
+ * knows in advance which HSCB (by address) to download,
+ * and we can't disappoint it. To achieve this, the next
+ * HSCB to download is saved off in ahd->next_queued_hscb.
+ * When we are called to queue "an arbitrary scb",
+ * we copy the contents of the incoming HSCB to the one
+ * the sequencer knows about, swap HSCB pointers and
+ * finally assign the SCB to the tag indexed location
+ * in the scb_array. This makes sure that we can still
+ * locate the correct SCB by SCB_TAG.
+ */
+ q_hscb = ahd->next_queued_hscb;
+ q_hscb_map = ahd->next_queued_hscb_map;
+ saved_hscb_busaddr = q_hscb->hscb_busaddr;
+ memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+ q_hscb->hscb_busaddr = saved_hscb_busaddr;
+ q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
+
+ /* Now swap HSCB pointers. */
+ ahd->next_queued_hscb = scb->hscb;
+ ahd->next_queued_hscb_map = scb->hscb_map;
+ scb->hscb = q_hscb;
+ scb->hscb_map = q_hscb_map;
+
+ /* Now define the mapping from tag to SCB in the scbindex */
+ ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
+ */
+void
+ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+ ahd_swap_with_next_hscb(ahd, scb);
+
+ if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
+ panic("Attempt to queue invalid SCB tag %x\n",
+ SCB_GET_TAG(scb));
+
+ /*
+ * Keep a history of SCBs we've downloaded in the qinfifo.
+ */
+ ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
+ ahd->qinfifonext++;
+
+ if (scb->sg_count != 0)
+ ahd_setup_data_scb(ahd, scb);
+ else
+ ahd_setup_noxfer_scb(ahd, scb);
+ ahd_setup_scb_common(ahd, scb);
+
+ /*
+ * Make sure our data is consistent from the
+ * perspective of the adapter.
+ */
+ ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
+ uint64_t host_dataptr;
+
+ host_dataptr = ahd_le64toh(scb->hscb->dataptr);
+ printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
+ ahd_name(ahd),
+ SCB_GET_TAG(scb), scb->hscb->scsiid,
+ ahd_le32toh(scb->hscb->hscb_busaddr),
+ (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
+ (u_int)(host_dataptr & 0xFFFFFFFF),
+ ahd_le32toh(scb->hscb->datacnt));
+ }
+#endif
+ /* Tell the adapter about the newly queued SCB */
+ ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+}
+
+/************************** Interrupt Processing ******************************/
+static void
+ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
+{
+ ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+ /*offset*/0,
+ /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
+}
+
+static void
+ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
+{
+#ifdef AHD_TARGET_MODE
+ if ((ahd->flags & AHD_TARGETROLE) != 0) {
+ ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
+ ahd->shared_data_map.dmamap,
+ ahd_targetcmd_offset(ahd, 0),
+ sizeof(struct target_cmd) * AHD_TMODE_CMDS,
+ op);
+ }
+#endif
+}
+
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHD_RUN_QOUTFIFO 0x1
+#define AHD_RUN_TQINFIFO 0x2
+static u_int
+ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
+{
+ u_int retval;
+
+ retval = 0;
+ ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+ /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
+ /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
+ if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
+ == ahd->qoutfifonext_valid_tag)
+ retval |= AHD_RUN_QOUTFIFO;
+#ifdef AHD_TARGET_MODE
+ if ((ahd->flags & AHD_TARGETROLE) != 0
+ && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
+ ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
+ ahd->shared_data_map.dmamap,
+ ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
+ /*len*/sizeof(struct target_cmd),
+ BUS_DMASYNC_POSTREAD);
+ if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
+ retval |= AHD_RUN_TQINFIFO;
+ }
+#endif
+ return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+int
+ahd_intr(struct ahd_softc *ahd)
+{
+ u_int intstat;
+
+ if ((ahd->pause & INTEN) == 0) {
+ /*
+ * Our interrupt is not enabled on the chip
+ * and may be disabled for re-entrancy reasons,
+ * so just return. This is likely just a shared
+ * interrupt.
+ */
+ return (0);
+ }
+
+ /*
+ * Instead of directly reading the interrupt status register,
+ * infer the cause of the interrupt by checking our in-core
+ * completion queues. This avoids a costly PCI bus read in
+ * most cases.
+ */
+ if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
+ && (ahd_check_cmdcmpltqueues(ahd) != 0))
+ intstat = CMDCMPLT;
+ else
+ intstat = ahd_inb(ahd, INTSTAT);
+
+ if ((intstat & INT_PEND) == 0)
+ return (0);
+
+ if (intstat & CMDCMPLT) {
+ ahd_outb(ahd, CLRINT, CLRCMDINT);
+
+ /*
+ * Ensure that the chip sees that we've cleared
+ * this interrupt before we walk the output fifo.
+ * Otherwise, we may, due to posted bus writes,
+ * clear the interrupt after we finish the scan,
+ * and after the sequencer has added new entries
+ * and asserted the interrupt again.
+ */
+ if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+ if (ahd_is_paused(ahd)) {
+ /*
+ * Potentially lost SEQINT.
+ * If SEQINTCODE is non-zero,
+ * simulate the SEQINT.
+ */
+ if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
+ intstat |= SEQINT;
+ }
+ } else {
+ ahd_flush_device_writes(ahd);
+ }
+ ahd_run_qoutfifo(ahd);
+ ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
+ ahd->cmdcmplt_total++;
+#ifdef AHD_TARGET_MODE
+ if ((ahd->flags & AHD_TARGETROLE) != 0)
+ ahd_run_tqinfifo(ahd, /*paused*/FALSE);
+#endif
+ }
+
+ /*
+ * Handle statuses that may invalidate our cached
+ * copy of INTSTAT separately.
+ */
+ if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
+ /* Hot eject. Do nothing */
+ } else if (intstat & HWERRINT) {
+ ahd_handle_hwerrint(ahd);
+ } else if ((intstat & (PCIINT|SPLTINT)) != 0) {
+ ahd->bus_intr(ahd);
+ } else {
+
+ if ((intstat & SEQINT) != 0)
+ ahd_handle_seqint(ahd, intstat);
+
+ if ((intstat & SCSIINT) != 0)
+ ahd_handle_scsiint(ahd, intstat);
+ }
+ return (1);
+}
+
+/******************************** Private Inlines *****************************/
static __inline void
ahd_assert_atn(struct ahd_softc *ahd)
{
@@ -280,7 +1046,7 @@ ahd_assert_atn(struct ahd_softc *ahd)
* are currently in a packetized transfer. We could
* just as easily be sending or receiving a message.
*/
-static __inline int
+static int
ahd_currently_packetized(struct ahd_softc *ahd)
{
ahd_mode_state saved_modes;
@@ -896,7 +1662,7 @@ clrchn:
* a copy of the first byte (little endian) of the sgptr
* hscb field.
*/
-void
+static void
ahd_run_qoutfifo(struct ahd_softc *ahd)
{
struct ahd_completion *completion;
@@ -935,7 +1701,7 @@ ahd_run_qoutfifo(struct ahd_softc *ahd)
}
/************************* Interrupt Handling *********************************/
-void
+static void
ahd_handle_hwerrint(struct ahd_softc *ahd)
{
/*
@@ -1009,7 +1775,7 @@ ahd_dump_sglist(struct scb *scb)
}
#endif /* AHD_DEBUG */
-void
+static void
ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
{
u_int seqintcode;
@@ -1621,7 +2387,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_unpause(ahd);
}
-void
+static void
ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
{
struct scb *scb;
@@ -3571,11 +4337,11 @@ ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
devinfo->target, devinfo->lun);
}
-static struct ahd_phase_table_entry*
+static const struct ahd_phase_table_entry*
ahd_lookup_phase_entry(int phase)
{
- struct ahd_phase_table_entry *entry;
- struct ahd_phase_table_entry *last_entry;
+ const struct ahd_phase_table_entry *entry;
+ const struct ahd_phase_table_entry *last_entry;
/*
* num_phases doesn't include the default entry which
@@ -3941,7 +4707,7 @@ ahd_clear_msg_state(struct ahd_softc *ahd)
*/
static void
ahd_handle_message_phase(struct ahd_softc *ahd)
-{
+{
struct ahd_devinfo devinfo;
u_int bus_phase;
int end_session;
@@ -5983,8 +6749,7 @@ found:
*/
void
ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
-{
-
+{
/* Clean up for the next user */
scb->flags = SCB_FLAG_NONE;
scb->hscb->control = 0;
@@ -6272,6 +7037,24 @@ static const char *termstat_strings[] = {
"Not Configured"
};
+/***************************** Timer Facilities *******************************/
+#define ahd_timer_init init_timer
+#define ahd_timer_stop del_timer_sync
+typedef void ahd_linux_callback_t (u_long);
+
+static void
+ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
+{
+ struct ahd_softc *ahd;
+
+ ahd = (struct ahd_softc *)arg;
+ del_timer(timer);
+ timer->data = (u_long)arg;
+ timer->expires = jiffies + (usec * HZ)/1000000;
+ timer->function = (ahd_linux_callback_t*)func;
+ add_timer(timer);
+}
+
/*
* Start the board, ready for normal operation
*/
@@ -7370,7 +8153,7 @@ ahd_qinfifo_count(struct ahd_softc *ahd)
+ ARRAY_SIZE(ahd->qinfifo) - wrap_qinpos);
}
-void
+static void
ahd_reset_cmds_pending(struct ahd_softc *ahd)
{
struct scb *scb;
@@ -8571,7 +9354,7 @@ ahd_loadseq(struct ahd_softc *ahd)
struct cs cs_table[num_critical_sections];
u_int begin_set[num_critical_sections];
u_int end_set[num_critical_sections];
- struct patch *cur_patch;
+ const struct patch *cur_patch;
u_int cs_count;
u_int cur_cs;
u_int i;
@@ -8726,11 +9509,11 @@ ahd_loadseq(struct ahd_softc *ahd)
}
static int
-ahd_check_patch(struct ahd_softc *ahd, struct patch **start_patch,
+ahd_check_patch(struct ahd_softc *ahd, const struct patch **start_patch,
u_int start_instr, u_int *skip_addr)
{
- struct patch *cur_patch;
- struct patch *last_patch;
+ const struct patch *cur_patch;
+ const struct patch *last_patch;
u_int num_patches;
num_patches = ARRAY_SIZE(patches);
@@ -8764,7 +9547,7 @@ ahd_check_patch(struct ahd_softc *ahd, struct patch **start_patch,
static u_int
ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address)
{
- struct patch *cur_patch;
+ const struct patch *cur_patch;
int address_offset;
u_int skip_addr;
u_int i;
@@ -8895,7 +9678,7 @@ sized:
}
int
-ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
+ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries,
const char *name, u_int address, u_int value,
u_int *cur_column, u_int wrap_point)
{
@@ -9886,7 +10669,7 @@ ahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask)
#endif
}
-void
+static void
ahd_run_tqinfifo(struct ahd_softc *ahd, int paused)
{
struct target_cmd *cmd;
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
index 45e55575a0fa..5f12cf9d99d0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -63,18 +63,15 @@ static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd,
static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
ahd_mode_state state,
ahd_mode *src, ahd_mode *dst);
-static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
- ahd_mode dst);
-static __inline void ahd_update_modes(struct ahd_softc *ahd);
-static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
- ahd_mode dstmode, const char *file,
- int line);
-static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
-static __inline void ahd_restore_modes(struct ahd_softc *ahd,
- ahd_mode_state state);
-static __inline int ahd_is_paused(struct ahd_softc *ahd);
-static __inline void ahd_pause(struct ahd_softc *ahd);
-static __inline void ahd_unpause(struct ahd_softc *ahd);
+
+void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
+ ahd_mode dst);
+ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
+void ahd_restore_modes(struct ahd_softc *ahd,
+ ahd_mode_state state);
+int ahd_is_paused(struct ahd_softc *ahd);
+void ahd_pause(struct ahd_softc *ahd);
+void ahd_unpause(struct ahd_softc *ahd);
static __inline void
ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
@@ -99,256 +96,16 @@ ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state,
*dst = (state & DST_MODE) >> DST_MODE_SHIFT;
}
-static __inline void
-ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
-{
- if (ahd->src_mode == src && ahd->dst_mode == dst)
- return;
-#ifdef AHD_DEBUG
- if (ahd->src_mode == AHD_MODE_UNKNOWN
- || ahd->dst_mode == AHD_MODE_UNKNOWN)
- panic("Setting mode prior to saving it.\n");
- if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
- printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
- ahd_build_mode_state(ahd, src, dst));
-#endif
- ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
- ahd->src_mode = src;
- ahd->dst_mode = dst;
-}
-
-static __inline void
-ahd_update_modes(struct ahd_softc *ahd)
-{
- ahd_mode_state mode_ptr;
- ahd_mode src;
- ahd_mode dst;
-
- mode_ptr = ahd_inb(ahd, MODE_PTR);
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
- printf("Reading mode 0x%x\n", mode_ptr);
-#endif
- ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
- ahd_known_modes(ahd, src, dst);
-}
-
-static __inline void
-ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
- ahd_mode dstmode, const char *file, int line)
-{
-#ifdef AHD_DEBUG
- if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
- || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
- panic("%s:%s:%d: Mode assertion failed.\n",
- ahd_name(ahd), file, line);
- }
-#endif
-}
-
-static __inline ahd_mode_state
-ahd_save_modes(struct ahd_softc *ahd)
-{
- if (ahd->src_mode == AHD_MODE_UNKNOWN
- || ahd->dst_mode == AHD_MODE_UNKNOWN)
- ahd_update_modes(ahd);
-
- return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
-}
-
-static __inline void
-ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
-{
- ahd_mode src;
- ahd_mode dst;
-
- ahd_extract_mode_state(ahd, state, &src, &dst);
- ahd_set_modes(ahd, src, dst);
-}
-
-#define AHD_ASSERT_MODES(ahd, source, dest) \
- ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
-
-/*
- * Determine whether the sequencer has halted code execution.
- * Returns non-zero status if the sequencer is stopped.
- */
-static __inline int
-ahd_is_paused(struct ahd_softc *ahd)
-{
- return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
-}
-
-/*
- * Request that the sequencer stop and wait, indefinitely, for it
- * to stop. The sequencer will only acknowledge that it is paused
- * once it has reached an instruction boundary and PAUSEDIS is
- * cleared in the SEQCTL register. The sequencer may use PAUSEDIS
- * for critical sections.
- */
-static __inline void
-ahd_pause(struct ahd_softc *ahd)
-{
- ahd_outb(ahd, HCNTRL, ahd->pause);
-
- /*
- * Since the sequencer can disable pausing in a critical section, we
- * must loop until it actually stops.
- */
- while (ahd_is_paused(ahd) == 0)
- ;
-}
-
-/*
- * Allow the sequencer to continue program execution.
- * We check here to ensure that no additional interrupt
- * sources that would cause the sequencer to halt have been
- * asserted. If, for example, a SCSI bus reset is detected
- * while we are fielding a different, pausing, interrupt type,
- * we don't want to release the sequencer before going back
- * into our interrupt handler and dealing with this new
- * condition.
- */
-static __inline void
-ahd_unpause(struct ahd_softc *ahd)
-{
- /*
- * Automatically restore our modes to those saved
- * prior to the first change of the mode.
- */
- if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
- && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
- if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
- ahd_reset_cmds_pending(ahd);
- ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
- }
-
- if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
- ahd_outb(ahd, HCNTRL, ahd->unpause);
-
- ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
-}
-
/*********************** Scatter Gather List Handling *************************/
-static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
- void *sgptr, dma_addr_t addr,
- bus_size_t len, int last);
-static __inline void ahd_setup_scb_common(struct ahd_softc *ahd,
- struct scb *scb);
-static __inline void ahd_setup_data_scb(struct ahd_softc *ahd,
- struct scb *scb);
-static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd,
- struct scb *scb);
-
-static __inline void *
-ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
- void *sgptr, dma_addr_t addr, bus_size_t len, int last)
-{
- scb->sg_count++;
- if (sizeof(dma_addr_t) > 4
- && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
- struct ahd_dma64_seg *sg;
-
- sg = (struct ahd_dma64_seg *)sgptr;
- sg->addr = ahd_htole64(addr);
- sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
- return (sg + 1);
- } else {
- struct ahd_dma_seg *sg;
-
- sg = (struct ahd_dma_seg *)sgptr;
- sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
- sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
- | (last ? AHD_DMA_LAST_SEG : 0));
- return (sg + 1);
- }
-}
-
-static __inline void
-ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
-{
- /* XXX Handle target mode SCBs. */
- scb->crc_retry_count = 0;
- if ((scb->flags & SCB_PACKETIZED) != 0) {
- /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
- scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
- } else {
- if (ahd_get_transfer_length(scb) & 0x01)
- scb->hscb->task_attribute = SCB_XFERLEN_ODD;
- else
- scb->hscb->task_attribute = 0;
- }
-
- if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
- || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
- scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
- ahd_htole32(scb->sense_busaddr);
-}
-
-static __inline void
-ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
-{
- /*
- * Copy the first SG into the "current" data ponter area.
- */
- if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
- struct ahd_dma64_seg *sg;
-
- sg = (struct ahd_dma64_seg *)scb->sg_list;
- scb->hscb->dataptr = sg->addr;
- scb->hscb->datacnt = sg->len;
- } else {
- struct ahd_dma_seg *sg;
- uint32_t *dataptr_words;
-
- sg = (struct ahd_dma_seg *)scb->sg_list;
- dataptr_words = (uint32_t*)&scb->hscb->dataptr;
- dataptr_words[0] = sg->addr;
- dataptr_words[1] = 0;
- if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
- uint64_t high_addr;
-
- high_addr = ahd_le32toh(sg->len) & 0x7F000000;
- scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
- }
- scb->hscb->datacnt = sg->len;
- }
- /*
- * Note where to find the SG entries in bus space.
- * We also set the full residual flag which the
- * sequencer will clear as soon as a data transfer
- * occurs.
- */
- scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
-}
-
-static __inline void
-ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
-{
- scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
- scb->hscb->dataptr = 0;
- scb->hscb->datacnt = 0;
-}
+void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
+ void *sgptr, dma_addr_t addr,
+ bus_size_t len, int last);
/************************** Memory mapping routines ***************************/
static __inline size_t ahd_sg_size(struct ahd_softc *ahd);
-static __inline void *
- ahd_sg_bus_to_virt(struct ahd_softc *ahd,
- struct scb *scb,
- uint32_t sg_busaddr);
-static __inline uint32_t
- ahd_sg_virt_to_bus(struct ahd_softc *ahd,
- struct scb *scb,
- void *sg);
-static __inline void ahd_sync_scb(struct ahd_softc *ahd,
- struct scb *scb, int op);
-static __inline void ahd_sync_sglist(struct ahd_softc *ahd,
- struct scb *scb, int op);
-static __inline void ahd_sync_sense(struct ahd_softc *ahd,
- struct scb *scb, int op);
-static __inline uint32_t
- ahd_targetcmd_offset(struct ahd_softc *ahd,
- u_int index);
+
+void ahd_sync_sglist(struct ahd_softc *ahd,
+ struct scb *scb, int op);
static __inline size_t
ahd_sg_size(struct ahd_softc *ahd)
@@ -358,104 +115,32 @@ ahd_sg_size(struct ahd_softc *ahd)
return (sizeof(struct ahd_dma_seg));
}
-static __inline void *
-ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
-{
- dma_addr_t sg_offset;
-
- /* sg_list_phys points to entry 1, not 0 */
- sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
- return ((uint8_t *)scb->sg_list + sg_offset);
-}
-
-static __inline uint32_t
-ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
-{
- dma_addr_t sg_offset;
-
- /* sg_list_phys points to entry 1, not 0 */
- sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
- - ahd_sg_size(ahd);
-
- return (scb->sg_list_busaddr + sg_offset);
-}
-
-static __inline void
-ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
-{
- ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
- scb->hscb_map->dmamap,
- /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
- /*len*/sizeof(*scb->hscb), op);
-}
-
-static __inline void
-ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
-{
- if (scb->sg_count == 0)
- return;
-
- ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
- scb->sg_map->dmamap,
- /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
- /*len*/ahd_sg_size(ahd) * scb->sg_count, op);
-}
-
-static __inline void
-ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
-{
- ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
- scb->sense_map->dmamap,
- /*offset*/scb->sense_busaddr,
- /*len*/AHD_SENSE_BUFSIZE, op);
-}
-
-static __inline uint32_t
-ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
-{
- return (((uint8_t *)&ahd->targetcmds[index])
- - (uint8_t *)ahd->qoutfifo);
-}
-
/*********************** Miscellaneous Support Functions ***********************/
-static __inline struct ahd_initiator_tinfo *
- ahd_fetch_transinfo(struct ahd_softc *ahd,
- char channel, u_int our_id,
- u_int remote_id,
- struct ahd_tmode_tstate **tstate);
-static __inline uint16_t
- ahd_inw(struct ahd_softc *ahd, u_int port);
-static __inline void ahd_outw(struct ahd_softc *ahd, u_int port,
- u_int value);
-static __inline uint32_t
- ahd_inl(struct ahd_softc *ahd, u_int port);
-static __inline void ahd_outl(struct ahd_softc *ahd, u_int port,
- uint32_t value);
-static __inline uint64_t
- ahd_inq(struct ahd_softc *ahd, u_int port);
-static __inline void ahd_outq(struct ahd_softc *ahd, u_int port,
- uint64_t value);
-static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd);
-static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
-static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd);
-static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
-static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd);
-static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
-static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd);
-static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
-static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd);
-static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
-static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd);
-static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
-static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
-static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
-static __inline uint32_t
- ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
-static __inline uint64_t
- ahd_inq_scbram(struct ahd_softc *ahd, u_int offset);
-static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd,
- struct scb *scb);
-static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
+struct ahd_initiator_tinfo *
+ ahd_fetch_transinfo(struct ahd_softc *ahd,
+ char channel, u_int our_id,
+ u_int remote_id,
+ struct ahd_tmode_tstate **tstate);
+uint16_t
+ ahd_inw(struct ahd_softc *ahd, u_int port);
+void ahd_outw(struct ahd_softc *ahd, u_int port,
+ u_int value);
+uint32_t
+ ahd_inl(struct ahd_softc *ahd, u_int port);
+void ahd_outl(struct ahd_softc *ahd, u_int port,
+ uint32_t value);
+uint64_t
+ ahd_inq(struct ahd_softc *ahd, u_int port);
+void ahd_outq(struct ahd_softc *ahd, u_int port,
+ uint64_t value);
+u_int ahd_get_scbptr(struct ahd_softc *ahd);
+void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
+u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
+u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
+struct scb *
+ ahd_lookup_scb(struct ahd_softc *ahd, u_int tag);
+void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
+
static __inline uint8_t *
ahd_get_sense_buf(struct ahd_softc *ahd,
struct scb *scb);
@@ -463,25 +148,7 @@ static __inline uint32_t
ahd_get_sense_bufaddr(struct ahd_softc *ahd,
struct scb *scb);
-/*
- * Return pointers to the transfer negotiation information
- * for the specified our_id/remote_id pair.
- */
-static __inline struct ahd_initiator_tinfo *
-ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
- u_int remote_id, struct ahd_tmode_tstate **tstate)
-{
- /*
- * Transfer data structures are stored from the perspective
- * of the target role. Since the parameters for a connection
- * in the initiator role to a given target are the same as
- * when the roles are reversed, we pretend we are the target.
- */
- if (channel == 'B')
- our_id += 8;
- *tstate = ahd->enabled_targets[our_id];
- return (&(*tstate)->transinfo[remote_id]);
-}
+#if 0 /* unused */
#define AHD_COPY_COL_IDX(dst, src) \
do { \
@@ -489,304 +156,7 @@ do { \
dst->hscb->lun = src->hscb->lun; \
} while (0)
-static __inline uint16_t
-ahd_inw(struct ahd_softc *ahd, u_int port)
-{
- /*
- * Read high byte first as some registers increment
- * or have other side effects when the low byte is
- * read.
- */
- uint16_t r = ahd_inb(ahd, port+1) << 8;
- return r | ahd_inb(ahd, port);
-}
-
-static __inline void
-ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
-{
- /*
- * Write low byte first to accomodate registers
- * such as PRGMCNT where the order maters.
- */
- ahd_outb(ahd, port, value & 0xFF);
- ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
-}
-
-static __inline uint32_t
-ahd_inl(struct ahd_softc *ahd, u_int port)
-{
- return ((ahd_inb(ahd, port))
- | (ahd_inb(ahd, port+1) << 8)
- | (ahd_inb(ahd, port+2) << 16)
- | (ahd_inb(ahd, port+3) << 24));
-}
-
-static __inline void
-ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
-{
- ahd_outb(ahd, port, (value) & 0xFF);
- ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
- ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
- ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
-}
-
-static __inline uint64_t
-ahd_inq(struct ahd_softc *ahd, u_int port)
-{
- return ((ahd_inb(ahd, port))
- | (ahd_inb(ahd, port+1) << 8)
- | (ahd_inb(ahd, port+2) << 16)
- | (ahd_inb(ahd, port+3) << 24)
- | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
- | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
- | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
- | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
-}
-
-static __inline void
-ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
-{
- ahd_outb(ahd, port, value & 0xFF);
- ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
- ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
- ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
- ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
- ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
- ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
- ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
-}
-
-static __inline u_int
-ahd_get_scbptr(struct ahd_softc *ahd)
-{
- AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
- ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
- return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
-}
-
-static __inline void
-ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
-{
- AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
- ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
- ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
- ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
-}
-
-static __inline u_int
-ahd_get_hnscb_qoff(struct ahd_softc *ahd)
-{
- return (ahd_inw_atomic(ahd, HNSCB_QOFF));
-}
-
-static __inline void
-ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
-{
- ahd_outw_atomic(ahd, HNSCB_QOFF, value);
-}
-
-static __inline u_int
-ahd_get_hescb_qoff(struct ahd_softc *ahd)
-{
- return (ahd_inb(ahd, HESCB_QOFF));
-}
-
-static __inline void
-ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
-{
- ahd_outb(ahd, HESCB_QOFF, value);
-}
-
-static __inline u_int
-ahd_get_snscb_qoff(struct ahd_softc *ahd)
-{
- u_int oldvalue;
-
- AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
- oldvalue = ahd_inw(ahd, SNSCB_QOFF);
- ahd_outw(ahd, SNSCB_QOFF, oldvalue);
- return (oldvalue);
-}
-
-static __inline void
-ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
-{
- AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
- ahd_outw(ahd, SNSCB_QOFF, value);
-}
-
-static __inline u_int
-ahd_get_sescb_qoff(struct ahd_softc *ahd)
-{
- AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
- return (ahd_inb(ahd, SESCB_QOFF));
-}
-
-static __inline void
-ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
-{
- AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
- ahd_outb(ahd, SESCB_QOFF, value);
-}
-
-static __inline u_int
-ahd_get_sdscb_qoff(struct ahd_softc *ahd)
-{
- AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
- return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
-}
-
-static __inline void
-ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
-{
- AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
- ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
- ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
-}
-
-static __inline u_int
-ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
-{
- u_int value;
-
- /*
- * Workaround PCI-X Rev A. hardware bug.
- * After a host read of SCB memory, the chip
- * may become confused into thinking prefetch
- * was required. This starts the discard timer
- * running and can cause an unexpected discard
- * timer interrupt. The work around is to read
- * a normal register prior to the exhaustion of
- * the discard timer. The mode pointer register
- * has no side effects and so serves well for
- * this purpose.
- *
- * Razor #528
- */
- value = ahd_inb(ahd, offset);
- if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
- ahd_inb(ahd, MODE_PTR);
- return (value);
-}
-
-static __inline u_int
-ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
-{
- return (ahd_inb_scbram(ahd, offset)
- | (ahd_inb_scbram(ahd, offset+1) << 8));
-}
-
-static __inline uint32_t
-ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
-{
- return (ahd_inw_scbram(ahd, offset)
- | (ahd_inw_scbram(ahd, offset+2) << 16));
-}
-
-static __inline uint64_t
-ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
-{
- return (ahd_inl_scbram(ahd, offset)
- | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
-}
-
-static __inline struct scb *
-ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
-{
- struct scb* scb;
-
- if (tag >= AHD_SCB_MAX)
- return (NULL);
- scb = ahd->scb_data.scbindex[tag];
- if (scb != NULL)
- ahd_sync_scb(ahd, scb,
- BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- return (scb);
-}
-
-static __inline void
-ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
-{
- struct hardware_scb *q_hscb;
- struct map_node *q_hscb_map;
- uint32_t saved_hscb_busaddr;
-
- /*
- * Our queuing method is a bit tricky. The card
- * knows in advance which HSCB (by address) to download,
- * and we can't disappoint it. To achieve this, the next
- * HSCB to download is saved off in ahd->next_queued_hscb.
- * When we are called to queue "an arbitrary scb",
- * we copy the contents of the incoming HSCB to the one
- * the sequencer knows about, swap HSCB pointers and
- * finally assign the SCB to the tag indexed location
- * in the scb_array. This makes sure that we can still
- * locate the correct SCB by SCB_TAG.
- */
- q_hscb = ahd->next_queued_hscb;
- q_hscb_map = ahd->next_queued_hscb_map;
- saved_hscb_busaddr = q_hscb->hscb_busaddr;
- memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
- q_hscb->hscb_busaddr = saved_hscb_busaddr;
- q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
-
- /* Now swap HSCB pointers. */
- ahd->next_queued_hscb = scb->hscb;
- ahd->next_queued_hscb_map = scb->hscb_map;
- scb->hscb = q_hscb;
- scb->hscb_map = q_hscb_map;
-
- /* Now define the mapping from tag to SCB in the scbindex */
- ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
-}
-
-/*
- * Tell the sequencer about a new transaction to execute.
- */
-static __inline void
-ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
-{
- ahd_swap_with_next_hscb(ahd, scb);
-
- if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
- panic("Attempt to queue invalid SCB tag %x\n",
- SCB_GET_TAG(scb));
-
- /*
- * Keep a history of SCBs we've downloaded in the qinfifo.
- */
- ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
- ahd->qinfifonext++;
-
- if (scb->sg_count != 0)
- ahd_setup_data_scb(ahd, scb);
- else
- ahd_setup_noxfer_scb(ahd, scb);
- ahd_setup_scb_common(ahd, scb);
-
- /*
- * Make sure our data is consistent from the
- * perspective of the adapter.
- */
- ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
- uint64_t host_dataptr;
-
- host_dataptr = ahd_le64toh(scb->hscb->dataptr);
- printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
- ahd_name(ahd),
- SCB_GET_TAG(scb), scb->hscb->scsiid,
- ahd_le32toh(scb->hscb->hscb_busaddr),
- (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
- (u_int)(host_dataptr & 0xFFFFFFFF),
- ahd_le32toh(scb->hscb->datacnt));
- }
#endif
- /* Tell the adapter about the newly queued SCB */
- ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
-}
static __inline uint8_t *
ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
@@ -801,151 +171,6 @@ ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
}
/************************** Interrupt Processing ******************************/
-static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
-static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
-static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
-static __inline int ahd_intr(struct ahd_softc *ahd);
-
-static __inline void
-ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
-{
- ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
- /*offset*/0,
- /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
-}
-
-static __inline void
-ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
-{
-#ifdef AHD_TARGET_MODE
- if ((ahd->flags & AHD_TARGETROLE) != 0) {
- ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
- ahd->shared_data_map.dmamap,
- ahd_targetcmd_offset(ahd, 0),
- sizeof(struct target_cmd) * AHD_TMODE_CMDS,
- op);
- }
-#endif
-}
-
-/*
- * See if the firmware has posted any completed commands
- * into our in-core command complete fifos.
- */
-#define AHD_RUN_QOUTFIFO 0x1
-#define AHD_RUN_TQINFIFO 0x2
-static __inline u_int
-ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
-{
- u_int retval;
-
- retval = 0;
- ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
- /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
- /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
- if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
- == ahd->qoutfifonext_valid_tag)
- retval |= AHD_RUN_QOUTFIFO;
-#ifdef AHD_TARGET_MODE
- if ((ahd->flags & AHD_TARGETROLE) != 0
- && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
- ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
- ahd->shared_data_map.dmamap,
- ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
- /*len*/sizeof(struct target_cmd),
- BUS_DMASYNC_POSTREAD);
- if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
- retval |= AHD_RUN_TQINFIFO;
- }
-#endif
- return (retval);
-}
-
-/*
- * Catch an interrupt from the adapter
- */
-static __inline int
-ahd_intr(struct ahd_softc *ahd)
-{
- u_int intstat;
-
- if ((ahd->pause & INTEN) == 0) {
- /*
- * Our interrupt is not enabled on the chip
- * and may be disabled for re-entrancy reasons,
- * so just return. This is likely just a shared
- * interrupt.
- */
- return (0);
- }
-
- /*
- * Instead of directly reading the interrupt status register,
- * infer the cause of the interrupt by checking our in-core
- * completion queues. This avoids a costly PCI bus read in
- * most cases.
- */
- if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
- && (ahd_check_cmdcmpltqueues(ahd) != 0))
- intstat = CMDCMPLT;
- else
- intstat = ahd_inb(ahd, INTSTAT);
-
- if ((intstat & INT_PEND) == 0)
- return (0);
-
- if (intstat & CMDCMPLT) {
- ahd_outb(ahd, CLRINT, CLRCMDINT);
-
- /*
- * Ensure that the chip sees that we've cleared
- * this interrupt before we walk the output fifo.
- * Otherwise, we may, due to posted bus writes,
- * clear the interrupt after we finish the scan,
- * and after the sequencer has added new entries
- * and asserted the interrupt again.
- */
- if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
- if (ahd_is_paused(ahd)) {
- /*
- * Potentially lost SEQINT.
- * If SEQINTCODE is non-zero,
- * simulate the SEQINT.
- */
- if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
- intstat |= SEQINT;
- }
- } else {
- ahd_flush_device_writes(ahd);
- }
- ahd_run_qoutfifo(ahd);
- ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
- ahd->cmdcmplt_total++;
-#ifdef AHD_TARGET_MODE
- if ((ahd->flags & AHD_TARGETROLE) != 0)
- ahd_run_tqinfifo(ahd, /*paused*/FALSE);
-#endif
- }
-
- /*
- * Handle statuses that may invalidate our cached
- * copy of INTSTAT separately.
- */
- if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
- /* Hot eject. Do nothing */
- } else if (intstat & HWERRINT) {
- ahd_handle_hwerrint(ahd);
- } else if ((intstat & (PCIINT|SPLTINT)) != 0) {
- ahd->bus_intr(ahd);
- } else {
-
- if ((intstat & SEQINT) != 0)
- ahd_handle_seqint(ahd, intstat);
-
- if ((intstat & SCSIINT) != 0)
- ahd_handle_scsiint(ahd, intstat);
- }
- return (1);
-}
+int ahd_intr(struct ahd_softc *ahd);
#endif /* _AIC79XX_INLINE_H_ */
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 0081aa357c8b..0f829b3b8ab7 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -193,7 +193,7 @@ struct ahd_linux_iocell_opts
#define AIC79XX_PRECOMP_INDEX 0
#define AIC79XX_SLEWRATE_INDEX 1
#define AIC79XX_AMPLITUDE_INDEX 2
-static struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
+static const struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
{
AIC79XX_DEFAULT_IOOPTS,
AIC79XX_DEFAULT_IOOPTS,
@@ -369,10 +369,167 @@ static void ahd_release_simq(struct ahd_softc *ahd);
static int ahd_linux_unit;
+/************************** OS Utility Wrappers *******************************/
+void ahd_delay(long);
+void
+ahd_delay(long usec)
+{
+ /*
+ * udelay on Linux can have problems for
+ * multi-millisecond waits. Wait at most
+ * 1024us per call.
+ */
+ while (usec > 0) {
+ udelay(usec % 1024);
+ usec -= 1024;
+ }
+}
+
+
+/***************************** Low Level I/O **********************************/
+uint8_t ahd_inb(struct ahd_softc * ahd, long port);
+void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
+void ahd_outw_atomic(struct ahd_softc * ahd,
+ long port, uint16_t val);
+void ahd_outsb(struct ahd_softc * ahd, long port,
+ uint8_t *, int count);
+void ahd_insb(struct ahd_softc * ahd, long port,
+ uint8_t *, int count);
+
+uint8_t
+ahd_inb(struct ahd_softc * ahd, long port)
+{
+ uint8_t x;
+
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ x = readb(ahd->bshs[0].maddr + port);
+ } else {
+ x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+ }
+ mb();
+ return (x);
+}
+
+#if 0 /* unused */
+static uint16_t
+ahd_inw_atomic(struct ahd_softc * ahd, long port)
+{
+ uint8_t x;
+
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ x = readw(ahd->bshs[0].maddr + port);
+ } else {
+ x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+ }
+ mb();
+ return (x);
+}
+#endif
+
+void
+ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
+{
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ writeb(val, ahd->bshs[0].maddr + port);
+ } else {
+ outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+ }
+ mb();
+}
+
+void
+ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
+{
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ writew(val, ahd->bshs[0].maddr + port);
+ } else {
+ outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+ }
+ mb();
+}
+
+void
+ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ ahd_outb(ahd, port, *array++);
+}
+
+void
+ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ *array++ = ahd_inb(ahd, port);
+}
+
+/******************************* PCI Routines *********************************/
+uint32_t
+ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width)
+{
+ switch (width) {
+ case 1:
+ {
+ uint8_t retval;
+
+ pci_read_config_byte(pci, reg, &retval);
+ return (retval);
+ }
+ case 2:
+ {
+ uint16_t retval;
+ pci_read_config_word(pci, reg, &retval);
+ return (retval);
+ }
+ case 4:
+ {
+ uint32_t retval;
+ pci_read_config_dword(pci, reg, &retval);
+ return (retval);
+ }
+ default:
+ panic("ahd_pci_read_config: Read size too big");
+ /* NOTREACHED */
+ return (0);
+ }
+}
+
+void
+ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width)
+{
+ switch (width) {
+ case 1:
+ pci_write_config_byte(pci, reg, value);
+ break;
+ case 2:
+ pci_write_config_word(pci, reg, value);
+ break;
+ case 4:
+ pci_write_config_dword(pci, reg, value);
+ break;
+ default:
+ panic("ahd_pci_write_config: Write size too big");
+ /* NOTREACHED */
+ }
+}
+
/****************************** Inlines ***************************************/
-static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
+static void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
-static __inline void
+static void
ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
{
struct scsi_cmnd *cmd;
@@ -400,13 +557,11 @@ ahd_linux_info(struct Scsi_Host *host)
bp = &buffer[0];
ahd = *(struct ahd_softc **)host->hostdata;
memset(bp, 0, sizeof(buffer));
- strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
- strcat(bp, AIC79XX_DRIVER_VERSION);
- strcat(bp, "\n");
- strcat(bp, " <");
+ strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev " AIC79XX_DRIVER_VERSION "\n"
+ " <");
strcat(bp, ahd->description);
- strcat(bp, ">\n");
- strcat(bp, " ");
+ strcat(bp, ">\n"
+ " ");
ahd_controller_info(ahd, ahd_info);
strcat(bp, ahd_info);
@@ -432,7 +587,7 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
return rtn;
}
-static inline struct scsi_target **
+static struct scsi_target **
ahd_linux_target_in_softc(struct scsi_target *starget)
{
struct ahd_softc *ahd =
@@ -991,7 +1146,7 @@ aic79xx_setup(char *s)
char *p;
char *end;
- static struct {
+ static const struct {
const char *name;
uint32_t *flag;
} options[] = {
@@ -1223,7 +1378,7 @@ ahd_platform_init(struct ahd_softc *ahd)
* Lookup and commit any modified IO Cell options.
*/
if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
- struct ahd_linux_iocell_opts *iocell_opts;
+ const struct ahd_linux_iocell_opts *iocell_opts;
iocell_opts = &aic79xx_iocell_info[ahd->unit];
if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
@@ -2613,7 +2768,7 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
uint8_t precomp;
if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
- struct ahd_linux_iocell_opts *iocell_opts;
+ const struct ahd_linux_iocell_opts *iocell_opts;
iocell_opts = &aic79xx_iocell_info[ahd->unit];
precomp = iocell_opts->precomp;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 853998be1474..8d6612c19922 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -222,22 +222,6 @@ typedef struct timer_list ahd_timer_t;
/***************************** Timer Facilities *******************************/
#define ahd_timer_init init_timer
#define ahd_timer_stop del_timer_sync
-typedef void ahd_linux_callback_t (u_long);
-static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec,
- ahd_callback_t *func, void *arg);
-
-static __inline void
-ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
-{
- struct ahd_softc *ahd;
-
- ahd = (struct ahd_softc *)arg;
- del_timer(timer);
- timer->data = (u_long)arg;
- timer->expires = jiffies + (usec * HZ)/1000000;
- timer->function = (ahd_linux_callback_t*)func;
- add_timer(timer);
-}
/***************************** SMP support ************************************/
#include <linux/spinlock.h>
@@ -376,7 +360,7 @@ struct ahd_platform_data {
#define AHD_LINUX_NOIRQ ((uint32_t)~0)
uint32_t irq; /* IRQ for this adapter */
uint32_t bios_address;
- uint32_t mem_busaddr; /* Mem Base Addr */
+ resource_size_t mem_busaddr; /* Mem Base Addr */
};
/************************** OS Utility Wrappers *******************************/
@@ -386,111 +370,18 @@ struct ahd_platform_data {
#define malloc(size, type, flags) kmalloc(size, flags)
#define free(ptr, type) kfree(ptr)
-static __inline void ahd_delay(long);
-static __inline void
-ahd_delay(long usec)
-{
- /*
- * udelay on Linux can have problems for
- * multi-millisecond waits. Wait at most
- * 1024us per call.
- */
- while (usec > 0) {
- udelay(usec % 1024);
- usec -= 1024;
- }
-}
-
+void ahd_delay(long);
/***************************** Low Level I/O **********************************/
-static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port);
-static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port);
-static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
-static __inline void ahd_outw_atomic(struct ahd_softc * ahd,
+uint8_t ahd_inb(struct ahd_softc * ahd, long port);
+void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
+void ahd_outw_atomic(struct ahd_softc * ahd,
long port, uint16_t val);
-static __inline void ahd_outsb(struct ahd_softc * ahd, long port,
+void ahd_outsb(struct ahd_softc * ahd, long port,
uint8_t *, int count);
-static __inline void ahd_insb(struct ahd_softc * ahd, long port,
+void ahd_insb(struct ahd_softc * ahd, long port,
uint8_t *, int count);
-static __inline uint8_t
-ahd_inb(struct ahd_softc * ahd, long port)
-{
- uint8_t x;
-
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- x = readb(ahd->bshs[0].maddr + port);
- } else {
- x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
- }
- mb();
- return (x);
-}
-
-static __inline uint16_t
-ahd_inw_atomic(struct ahd_softc * ahd, long port)
-{
- uint8_t x;
-
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- x = readw(ahd->bshs[0].maddr + port);
- } else {
- x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
- }
- mb();
- return (x);
-}
-
-static __inline void
-ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
-{
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- writeb(val, ahd->bshs[0].maddr + port);
- } else {
- outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
- }
- mb();
-}
-
-static __inline void
-ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
-{
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- writew(val, ahd->bshs[0].maddr + port);
- } else {
- outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
- }
- mb();
-}
-
-static __inline void
-ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- ahd_outb(ahd, port, *array++);
-}
-
-static __inline void
-ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- *array++ = ahd_inb(ahd, port);
-}
-
/**************************** Initialization **********************************/
int ahd_linux_register_host(struct ahd_softc *,
struct scsi_host_template *);
@@ -593,62 +484,12 @@ void ahd_linux_pci_exit(void);
int ahd_pci_map_registers(struct ahd_softc *ahd);
int ahd_pci_map_int(struct ahd_softc *ahd);
-static __inline uint32_t ahd_pci_read_config(ahd_dev_softc_t pci,
+uint32_t ahd_pci_read_config(ahd_dev_softc_t pci,
int reg, int width);
-
-static __inline uint32_t
-ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width)
-{
- switch (width) {
- case 1:
- {
- uint8_t retval;
-
- pci_read_config_byte(pci, reg, &retval);
- return (retval);
- }
- case 2:
- {
- uint16_t retval;
- pci_read_config_word(pci, reg, &retval);
- return (retval);
- }
- case 4:
- {
- uint32_t retval;
- pci_read_config_dword(pci, reg, &retval);
- return (retval);
- }
- default:
- panic("ahd_pci_read_config: Read size too big");
- /* NOTREACHED */
- return (0);
- }
-}
-
-static __inline void ahd_pci_write_config(ahd_dev_softc_t pci,
+void ahd_pci_write_config(ahd_dev_softc_t pci,
int reg, uint32_t value,
int width);
-static __inline void
-ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width)
-{
- switch (width) {
- case 1:
- pci_write_config_byte(pci, reg, value);
- break;
- case 2:
- pci_write_config_word(pci, reg, value);
- break;
- case 4:
- pci_write_config_dword(pci, reg, value);
- break;
- default:
- panic("ahd_pci_write_config: Write size too big");
- /* NOTREACHED */
- }
-}
-
static __inline int ahd_get_pci_function(ahd_dev_softc_t);
static __inline int
ahd_get_pci_function(ahd_dev_softc_t pci)
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index dfaaae5e73ae..6593056867f6 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -49,7 +49,7 @@
ID2C(x), \
ID2C(IDIROC(x))
-static struct pci_device_id ahd_linux_pci_id_table[] = {
+static const struct pci_device_id ahd_linux_pci_id_table[] = {
/* aic7901 based controllers */
ID(ID_AHA_29320A),
ID(ID_AHA_29320ALP),
@@ -159,7 +159,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
char buf[80];
struct ahd_softc *ahd;
ahd_dev_softc_t pci;
- struct ahd_pci_identity *entry;
+ const struct ahd_pci_identity *entry;
char *name;
int error;
struct device *dev = &pdev->dev;
@@ -249,8 +249,8 @@ ahd_linux_pci_exit(void)
}
static int
-ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
- u_long *base2)
+ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, resource_size_t *base,
+ resource_size_t *base2)
{
*base = pci_resource_start(ahd->dev_softc, 0);
/*
@@ -272,11 +272,11 @@ ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
static int
ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
- u_long *bus_addr,
+ resource_size_t *bus_addr,
uint8_t __iomem **maddr)
{
- u_long start;
- u_long base_page;
+ resource_size_t start;
+ resource_size_t base_page;
u_long base_offset;
int error = 0;
@@ -310,7 +310,7 @@ int
ahd_pci_map_registers(struct ahd_softc *ahd)
{
uint32_t command;
- u_long base;
+ resource_size_t base;
uint8_t __iomem *maddr;
int error;
@@ -346,31 +346,32 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
} else
command |= PCIM_CMD_MEMEN;
} else if (bootverbose) {
- printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx "
+ printf("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
"unavailable. Cannot memory map device.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
ahd_get_pci_function(ahd->dev_softc),
- base);
+ (unsigned long long)base);
}
if (maddr == NULL) {
- u_long base2;
+ resource_size_t base2;
error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2);
if (error == 0) {
ahd->tags[0] = BUS_SPACE_PIO;
ahd->tags[1] = BUS_SPACE_PIO;
- ahd->bshs[0].ioport = base;
- ahd->bshs[1].ioport = base2;
+ ahd->bshs[0].ioport = (u_long)base;
+ ahd->bshs[1].ioport = (u_long)base2;
command |= PCIM_CMD_PORTEN;
} else {
- printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx"
- "unavailable. Cannot map device.\n",
+ printf("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
+ "0x%llx unavailable. Cannot map device.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
ahd_get_pci_function(ahd->dev_softc),
- base, base2);
+ (unsigned long long)base,
+ (unsigned long long)base2);
}
}
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index c9f79fdf9131..c25b6adffbf9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -97,7 +97,7 @@ static ahd_device_setup_t ahd_aic7901A_setup;
static ahd_device_setup_t ahd_aic7902_setup;
static ahd_device_setup_t ahd_aic790X_setup;
-static struct ahd_pci_identity ahd_pci_ident_table [] =
+static const struct ahd_pci_identity ahd_pci_ident_table[] =
{
/* aic7901 based controllers */
{
@@ -253,7 +253,7 @@ static void ahd_configure_termination(struct ahd_softc *ahd,
static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
static void ahd_pci_intr(struct ahd_softc *ahd);
-struct ahd_pci_identity *
+const struct ahd_pci_identity *
ahd_find_pci_device(ahd_dev_softc_t pci)
{
uint64_t full_id;
@@ -261,7 +261,7 @@ ahd_find_pci_device(ahd_dev_softc_t pci)
uint16_t vendor;
uint16_t subdevice;
uint16_t subvendor;
- struct ahd_pci_identity *entry;
+ const struct ahd_pci_identity *entry;
u_int i;
vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
@@ -292,7 +292,7 @@ ahd_find_pci_device(ahd_dev_softc_t pci)
}
int
-ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
+ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry)
{
struct scb_data *shared_scb_data;
u_int command;
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 6b28bebcbca0..014bed716e7c 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -57,7 +57,7 @@ static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
* Table of syncrates that don't follow the "divisible by 4"
* rule. This table will be expanded in future SCSI specs.
*/
-static struct {
+static const struct {
u_int period_factor;
u_int period; /* in 100ths of ns */
} scsi_syncrates[] = {
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
index 2068e00d2c75..c21ceab8e913 100644
--- a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
@@ -48,13 +48,6 @@ ahd_reg_print_t ahd_error_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrerr_print;
-#else
-#define ahd_clrerr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CLRERR", 0x04, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_hcntrl_print;
#else
#define ahd_hcntrl_print(regvalue, cur_col, wrap) \
@@ -167,13 +160,6 @@ ahd_reg_print_t ahd_sg_cache_shadow_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_arbctl_print;
-#else
-#define ahd_arbctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "ARBCTL", 0x1b, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_sg_cache_pre_print;
#else
#define ahd_sg_cache_pre_print(regvalue, cur_col, wrap) \
@@ -188,20 +174,6 @@ ahd_reg_print_t ahd_lqin_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_typeptr_print;
-#else
-#define ahd_typeptr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "TYPEPTR", 0x20, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_tagptr_print;
-#else
-#define ahd_tagptr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "TAGPTR", 0x21, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_lunptr_print;
#else
#define ahd_lunptr_print(regvalue, cur_col, wrap) \
@@ -209,20 +181,6 @@ ahd_reg_print_t ahd_lunptr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_datalenptr_print;
-#else
-#define ahd_datalenptr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DATALENPTR", 0x23, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_statlenptr_print;
-#else
-#define ahd_statlenptr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "STATLENPTR", 0x24, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_cmdlenptr_print;
#else
#define ahd_cmdlenptr_print(regvalue, cur_col, wrap) \
@@ -258,13 +216,6 @@ ahd_reg_print_t ahd_qnextptr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_idptr_print;
-#else
-#define ahd_idptr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "IDPTR", 0x2a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_abrtbyteptr_print;
#else
#define ahd_abrtbyteptr_print(regvalue, cur_col, wrap) \
@@ -279,27 +230,6 @@ ahd_reg_print_t ahd_abrtbitptr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_maxcmdbytes_print;
-#else
-#define ahd_maxcmdbytes_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "MAXCMDBYTES", 0x2d, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_maxcmd2rcv_print;
-#else
-#define ahd_maxcmd2rcv_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "MAXCMD2RCV", 0x2e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_shortthresh_print;
-#else
-#define ahd_shortthresh_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SHORTTHRESH", 0x2f, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_lunlen_print;
#else
#define ahd_lunlen_print(regvalue, cur_col, wrap) \
@@ -328,41 +258,6 @@ ahd_reg_print_t ahd_maxcmdcnt_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqrsvd01_print;
-#else
-#define ahd_lqrsvd01_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "LQRSVD01", 0x34, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqrsvd16_print;
-#else
-#define ahd_lqrsvd16_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "LQRSVD16", 0x35, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqrsvd17_print;
-#else
-#define ahd_lqrsvd17_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "LQRSVD17", 0x36, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmdrsvd0_print;
-#else
-#define ahd_cmdrsvd0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMDRSVD0", 0x37, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqctl0_print;
-#else
-#define ahd_lqctl0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "LQCTL0", 0x38, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_lqctl1_print;
#else
#define ahd_lqctl1_print(regvalue, cur_col, wrap) \
@@ -370,13 +265,6 @@ ahd_reg_print_t ahd_lqctl1_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scsbist0_print;
-#else
-#define ahd_scsbist0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCSBIST0", 0x39, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_lqctl2_print;
#else
#define ahd_lqctl2_print(regvalue, cur_col, wrap) \
@@ -384,13 +272,6 @@ ahd_reg_print_t ahd_lqctl2_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scsbist1_print;
-#else
-#define ahd_scsbist1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCSBIST1", 0x3a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_scsiseq0_print;
#else
#define ahd_scsiseq0_print(regvalue, cur_col, wrap) \
@@ -412,20 +293,6 @@ ahd_reg_print_t ahd_sxfrctl0_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dlcount_print;
-#else
-#define ahd_dlcount_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DLCOUNT", 0x3c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_businitid_print;
-#else
-#define ahd_businitid_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "BUSINITID", 0x3c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_sxfrctl1_print;
#else
#define ahd_sxfrctl1_print(regvalue, cur_col, wrap) \
@@ -433,20 +300,6 @@ ahd_reg_print_t ahd_sxfrctl1_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_bustargid_print;
-#else
-#define ahd_bustargid_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "BUSTARGID", 0x3e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sxfrctl2_print;
-#else
-#define ahd_sxfrctl2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SXFRCTL2", 0x3e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_dffstat_print;
#else
#define ahd_dffstat_print(regvalue, cur_col, wrap) \
@@ -454,17 +307,17 @@ ahd_reg_print_t ahd_dffstat_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scsisigo_print;
+ahd_reg_print_t ahd_multargid_print;
#else
-#define ahd_scsisigo_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCSISIGO", 0x40, regvalue, cur_col, wrap)
+#define ahd_multargid_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "MULTARGID", 0x40, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_multargid_print;
+ahd_reg_print_t ahd_scsisigo_print;
#else
-#define ahd_multargid_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "MULTARGID", 0x40, regvalue, cur_col, wrap)
+#define ahd_scsisigo_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SCSISIGO", 0x40, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -482,13 +335,6 @@ ahd_reg_print_t ahd_scsiphase_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scsidat0_img_print;
-#else
-#define ahd_scsidat0_img_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCSIDAT0_IMG", 0x43, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_scsidat_print;
#else
#define ahd_scsidat_print(regvalue, cur_col, wrap) \
@@ -531,13 +377,6 @@ ahd_reg_print_t ahd_sblkctl_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrsint0_print;
-#else
-#define ahd_clrsint0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CLRSINT0", 0x4b, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_sstat0_print;
#else
#define ahd_sstat0_print(regvalue, cur_col, wrap) \
@@ -552,10 +391,10 @@ ahd_reg_print_t ahd_simode0_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrsint1_print;
+ahd_reg_print_t ahd_clrsint0_print;
#else
-#define ahd_clrsint1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CLRSINT1", 0x4c, regvalue, cur_col, wrap)
+#define ahd_clrsint0_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "CLRSINT0", 0x4b, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -566,17 +405,17 @@ ahd_reg_print_t ahd_sstat1_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sstat2_print;
+ahd_reg_print_t ahd_clrsint1_print;
#else
-#define ahd_sstat2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SSTAT2", 0x4d, regvalue, cur_col, wrap)
+#define ahd_clrsint1_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "CLRSINT1", 0x4c, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_simode2_print;
+ahd_reg_print_t ahd_sstat2_print;
#else
-#define ahd_simode2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SIMODE2", 0x4d, regvalue, cur_col, wrap)
+#define ahd_sstat2_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SSTAT2", 0x4d, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -622,17 +461,17 @@ ahd_reg_print_t ahd_lqistat0_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrlqiint0_print;
+ahd_reg_print_t ahd_lqimode0_print;
#else
-#define ahd_clrlqiint0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CLRLQIINT0", 0x50, regvalue, cur_col, wrap)
+#define ahd_lqimode0_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "LQIMODE0", 0x50, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqimode0_print;
+ahd_reg_print_t ahd_clrlqiint0_print;
#else
-#define ahd_lqimode0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "LQIMODE0", 0x50, regvalue, cur_col, wrap)
+#define ahd_clrlqiint0_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "CLRLQIINT0", 0x50, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -790,13 +629,6 @@ ahd_reg_print_t ahd_seqintsrc_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_currscb_print;
-#else
-#define ahd_currscb_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CURRSCB", 0x5c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_seqimode_print;
#else
#define ahd_seqimode_print(regvalue, cur_col, wrap) \
@@ -804,24 +636,17 @@ ahd_reg_print_t ahd_seqimode_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_mdffstat_print;
-#else
-#define ahd_mdffstat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "MDFFSTAT", 0x5d, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_crccontrol_print;
+ahd_reg_print_t ahd_currscb_print;
#else
-#define ahd_crccontrol_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CRCCONTROL", 0x5d, regvalue, cur_col, wrap)
+#define ahd_currscb_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "CURRSCB", 0x5c, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfftag_print;
+ahd_reg_print_t ahd_mdffstat_print;
#else
-#define ahd_dfftag_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFFTAG", 0x5e, regvalue, cur_col, wrap)
+#define ahd_mdffstat_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "MDFFSTAT", 0x5d, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -832,20 +657,6 @@ ahd_reg_print_t ahd_lastscb_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scsitest_print;
-#else
-#define ahd_scsitest_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCSITEST", 0x5e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_iopdnctl_print;
-#else
-#define ahd_iopdnctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "IOPDNCTL", 0x5f, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_shaddr_print;
#else
#define ahd_shaddr_print(regvalue, cur_col, wrap) \
@@ -860,13 +671,6 @@ ahd_reg_print_t ahd_negoaddr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dgrpcrci_print;
-#else
-#define ahd_dgrpcrci_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DGRPCRCI", 0x60, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_negperiod_print;
#else
#define ahd_negperiod_print(regvalue, cur_col, wrap) \
@@ -874,13 +678,6 @@ ahd_reg_print_t ahd_negperiod_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_packcrci_print;
-#else
-#define ahd_packcrci_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PACKCRCI", 0x62, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_negoffset_print;
#else
#define ahd_negoffset_print(regvalue, cur_col, wrap) \
@@ -930,13 +727,6 @@ ahd_reg_print_t ahd_iownid_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll960ctl0_print;
-#else
-#define ahd_pll960ctl0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLL960CTL0", 0x68, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_shcnt_print;
#else
#define ahd_shcnt_print(regvalue, cur_col, wrap) \
@@ -951,27 +741,6 @@ ahd_reg_print_t ahd_townid_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll960ctl1_print;
-#else
-#define ahd_pll960ctl1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLL960CTL1", 0x69, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll960cnt0_print;
-#else
-#define ahd_pll960cnt0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLL960CNT0", 0x6a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_xsig_print;
-#else
-#define ahd_xsig_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "XSIG", 0x6a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_seloid_print;
#else
#define ahd_seloid_print(regvalue, cur_col, wrap) \
@@ -979,41 +748,6 @@ ahd_reg_print_t ahd_seloid_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll400ctl0_print;
-#else
-#define ahd_pll400ctl0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLL400CTL0", 0x6c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_fairness_print;
-#else
-#define ahd_fairness_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "FAIRNESS", 0x6c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll400ctl1_print;
-#else
-#define ahd_pll400ctl1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLL400CTL1", 0x6d, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_unfairness_print;
-#else
-#define ahd_unfairness_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "UNFAIRNESS", 0x6e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll400cnt0_print;
-#else
-#define ahd_pll400cnt0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLL400CNT0", 0x6e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_haddr_print;
#else
#define ahd_haddr_print(regvalue, cur_col, wrap) \
@@ -1021,27 +755,6 @@ ahd_reg_print_t ahd_haddr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_plldelay_print;
-#else
-#define ahd_plldelay_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "PLLDELAY", 0x70, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_hodmaadr_print;
-#else
-#define ahd_hodmaadr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "HODMAADR", 0x70, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_hodmacnt_print;
-#else
-#define ahd_hodmacnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "HODMACNT", 0x78, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_hcnt_print;
#else
#define ahd_hcnt_print(regvalue, cur_col, wrap) \
@@ -1049,10 +762,10 @@ ahd_reg_print_t ahd_hcnt_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_hodmaen_print;
+ahd_reg_print_t ahd_sghaddr_print;
#else
-#define ahd_hodmaen_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "HODMAEN", 0x7a, regvalue, cur_col, wrap)
+#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -1063,10 +776,10 @@ ahd_reg_print_t ahd_scbhaddr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sghaddr_print;
+ahd_reg_print_t ahd_sghcnt_print;
#else
-#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
+#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -1077,13 +790,6 @@ ahd_reg_print_t ahd_scbhcnt_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sghcnt_print;
-#else
-#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_dff_thrsh_print;
#else
#define ahd_dff_thrsh_print(regvalue, cur_col, wrap) \
@@ -1091,132 +797,6 @@ ahd_reg_print_t ahd_dff_thrsh_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_romaddr_print;
-#else
-#define ahd_romaddr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "ROMADDR", 0x8a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_romcntrl_print;
-#else
-#define ahd_romcntrl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "ROMCNTRL", 0x8d, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_romdata_print;
-#else
-#define ahd_romdata_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "ROMDATA", 0x8e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcrxmsg0_print;
-#else
-#define ahd_cmcrxmsg0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCRXMSG0", 0x90, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_roenable_print;
-#else
-#define ahd_roenable_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "ROENABLE", 0x90, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg0_print;
-#else
-#define ahd_ovlyrxmsg0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYRXMSG0", 0x90, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg0_print;
-#else
-#define ahd_dchrxmsg0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DCHRXMSG0", 0x90, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg1_print;
-#else
-#define ahd_ovlyrxmsg1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYRXMSG1", 0x91, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_nsenable_print;
-#else
-#define ahd_nsenable_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "NSENABLE", 0x91, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcrxmsg1_print;
-#else
-#define ahd_cmcrxmsg1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCRXMSG1", 0x91, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg1_print;
-#else
-#define ahd_dchrxmsg1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DCHRXMSG1", 0x91, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg2_print;
-#else
-#define ahd_dchrxmsg2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DCHRXMSG2", 0x92, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcrxmsg2_print;
-#else
-#define ahd_cmcrxmsg2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCRXMSG2", 0x92, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ost_print;
-#else
-#define ahd_ost_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OST", 0x92, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg2_print;
-#else
-#define ahd_ovlyrxmsg2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYRXMSG2", 0x92, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg3_print;
-#else
-#define ahd_dchrxmsg3_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DCHRXMSG3", 0x93, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg3_print;
-#else
-#define ahd_ovlyrxmsg3_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYRXMSG3", 0x93, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcrxmsg3_print;
-#else
-#define ahd_cmcrxmsg3_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCRXMSG3", 0x93, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_pcixctl_print;
#else
#define ahd_pcixctl_print(regvalue, cur_col, wrap) \
@@ -1224,34 +804,6 @@ ahd_reg_print_t ahd_pcixctl_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyseqbcnt_print;
-#else
-#define ahd_ovlyseqbcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYSEQBCNT", 0x94, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchseqbcnt_print;
-#else
-#define ahd_dchseqbcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DCHSEQBCNT", 0x94, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcseqbcnt_print;
-#else
-#define ahd_cmcseqbcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCSEQBCNT", 0x94, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcspltstat0_print;
-#else
-#define ahd_cmcspltstat0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_dchspltstat0_print;
#else
#define ahd_dchspltstat0_print(regvalue, cur_col, wrap) \
@@ -1259,27 +811,6 @@ ahd_reg_print_t ahd_dchspltstat0_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyspltstat0_print;
-#else
-#define ahd_ovlyspltstat0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcspltstat1_print;
-#else
-#define ahd_cmcspltstat1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyspltstat1_print;
-#else
-#define ahd_ovlyspltstat1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_dchspltstat1_print;
#else
#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \
@@ -1287,90 +818,6 @@ ahd_reg_print_t ahd_dchspltstat1_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgrxmsg0_print;
-#else
-#define ahd_sgrxmsg0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGRXMSG0", 0x98, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutadr0_print;
-#else
-#define ahd_slvspltoutadr0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTADR0", 0x98, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgrxmsg1_print;
-#else
-#define ahd_sgrxmsg1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGRXMSG1", 0x99, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutadr1_print;
-#else
-#define ahd_slvspltoutadr1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTADR1", 0x99, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgrxmsg2_print;
-#else
-#define ahd_sgrxmsg2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGRXMSG2", 0x9a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutadr2_print;
-#else
-#define ahd_slvspltoutadr2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTADR2", 0x9a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgrxmsg3_print;
-#else
-#define ahd_sgrxmsg3_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGRXMSG3", 0x9b, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutadr3_print;
-#else
-#define ahd_slvspltoutadr3_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTADR3", 0x9b, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgseqbcnt_print;
-#else
-#define ahd_sgseqbcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGSEQBCNT", 0x9c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutattr0_print;
-#else
-#define ahd_slvspltoutattr0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTATTR0", 0x9c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutattr1_print;
-#else
-#define ahd_slvspltoutattr1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTATTR1", 0x9d, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_slvspltoutattr2_print;
-#else
-#define ahd_slvspltoutattr2_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SLVSPLTOUTATTR2", 0x9e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_sgspltstat0_print;
#else
#define ahd_sgspltstat0_print(regvalue, cur_col, wrap) \
@@ -1385,13 +832,6 @@ ahd_reg_print_t ahd_sgspltstat1_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sfunct_print;
-#else
-#define ahd_sfunct_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_df0pcistat_print;
#else
#define ahd_df0pcistat_print(regvalue, cur_col, wrap) \
@@ -1406,41 +846,6 @@ ahd_reg_print_t ahd_reg0_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_df1pcistat_print;
-#else
-#define ahd_df1pcistat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DF1PCISTAT", 0xa1, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgpcistat_print;
-#else
-#define ahd_sgpcistat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SGPCISTAT", 0xa2, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_reg1_print;
-#else
-#define ahd_reg1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "REG1", 0xa2, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcpcistat_print;
-#else
-#define ahd_cmcpcistat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMCPCISTAT", 0xa3, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlypcistat_print;
-#else
-#define ahd_ovlypcistat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYPCISTAT", 0xa4, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_reg_isr_print;
#else
#define ahd_reg_isr_print(regvalue, cur_col, wrap) \
@@ -1455,13 +860,6 @@ ahd_reg_print_t ahd_sg_state_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_msipcistat_print;
-#else
-#define ahd_msipcistat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "MSIPCISTAT", 0xa6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_targpcistat_print;
#else
#define ahd_targpcistat_print(regvalue, cur_col, wrap) \
@@ -1469,13 +867,6 @@ ahd_reg_print_t ahd_targpcistat_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_data_count_odd_print;
-#else
-#define ahd_data_count_odd_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DATA_COUNT_ODD", 0xa7, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_scbptr_print;
#else
#define ahd_scbptr_print(regvalue, cur_col, wrap) \
@@ -1483,13 +874,6 @@ ahd_reg_print_t ahd_scbptr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccscbacnt_print;
-#else
-#define ahd_ccscbacnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CCSCBACNT", 0xab, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_scbautoptr_print;
#else
#define ahd_scbautoptr_print(regvalue, cur_col, wrap) \
@@ -1504,13 +888,6 @@ ahd_reg_print_t ahd_ccsgaddr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccscbadr_bk_print;
-#else
-#define ahd_ccscbadr_bk_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CCSCBADR_BK", 0xac, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_ccscbaddr_print;
#else
#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \
@@ -1518,13 +895,6 @@ ahd_reg_print_t ahd_ccscbaddr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmc_rambist_print;
-#else
-#define ahd_cmc_rambist_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "CMC_RAMBIST", 0xad, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_ccscbctl_print;
#else
#define ahd_ccscbctl_print(regvalue, cur_col, wrap) \
@@ -1546,13 +916,6 @@ ahd_reg_print_t ahd_ccsgram_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_flexadr_print;
-#else
-#define ahd_flexadr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "FLEXADR", 0xb0, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_ccscbram_print;
#else
#define ahd_ccscbram_print(regvalue, cur_col, wrap) \
@@ -1560,27 +923,6 @@ ahd_reg_print_t ahd_ccscbram_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_flexcnt_print;
-#else
-#define ahd_flexcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "FLEXCNT", 0xb3, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_flexdmastat_print;
-#else
-#define ahd_flexdmastat_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "FLEXDMASTAT", 0xb5, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_flexdata_print;
-#else
-#define ahd_flexdata_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "FLEXDATA", 0xb6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_brddat_print;
#else
#define ahd_brddat_print(regvalue, cur_col, wrap) \
@@ -1623,27 +965,6 @@ ahd_reg_print_t ahd_seestat_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scbcnt_print;
-#else
-#define ahd_scbcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCBCNT", 0xbf, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfwaddr_print;
-#else
-#define ahd_dfwaddr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFWADDR", 0xc0, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dspfltrctl_print;
-#else
-#define ahd_dspfltrctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DSPFLTRCTL", 0xc0, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_dspdatactl_print;
#else
#define ahd_dspdatactl_print(regvalue, cur_col, wrap) \
@@ -1651,27 +972,6 @@ ahd_reg_print_t ahd_dspdatactl_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfraddr_print;
-#else
-#define ahd_dfraddr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFRADDR", 0xc2, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dspreqctl_print;
-#else
-#define ahd_dspreqctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DSPREQCTL", 0xc2, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dspackctl_print;
-#else
-#define ahd_dspackctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DSPACKCTL", 0xc3, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_dfdat_print;
#else
#define ahd_dfdat_print(regvalue, cur_col, wrap) \
@@ -1693,76 +993,6 @@ ahd_reg_print_t ahd_wrtbiasctl_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_rcvrbiosctl_print;
-#else
-#define ahd_rcvrbiosctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "RCVRBIOSCTL", 0xc6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_wrtbiascalc_print;
-#else
-#define ahd_wrtbiascalc_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "WRTBIASCALC", 0xc7, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_rcvrbiascalc_print;
-#else
-#define ahd_rcvrbiascalc_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "RCVRBIASCALC", 0xc8, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfptrs_print;
-#else
-#define ahd_dfptrs_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFPTRS", 0xc8, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_skewcalc_print;
-#else
-#define ahd_skewcalc_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SKEWCALC", 0xc9, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfbkptr_print;
-#else
-#define ahd_dfbkptr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFBKPTR", 0xc9, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfdbctl_print;
-#else
-#define ahd_dfdbctl_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFDBCTL", 0xcb, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfscnt_print;
-#else
-#define ahd_dfscnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFSCNT", 0xcc, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfbcnt_print;
-#else
-#define ahd_dfbcnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "DFBCNT", 0xce, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyaddr_print;
-#else
-#define ahd_ovlyaddr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "OVLYADDR", 0xd4, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_seqctl0_print;
#else
#define ahd_seqctl0_print(regvalue, cur_col, wrap) \
@@ -1770,13 +1000,6 @@ ahd_reg_print_t ahd_seqctl0_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_seqctl1_print;
-#else
-#define ahd_seqctl1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SEQCTL1", 0xd7, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_flags_print;
#else
#define ahd_flags_print(regvalue, cur_col, wrap) \
@@ -1826,20 +1049,6 @@ ahd_reg_print_t ahd_dindex_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_brkaddr0_print;
-#else
-#define ahd_brkaddr0_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "BRKADDR0", 0xe6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_brkaddr1_print;
-#else
-#define ahd_brkaddr1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "BRKADDR1", 0xe6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_allones_print;
#else
#define ahd_allones_print(regvalue, cur_col, wrap) \
@@ -1875,13 +1084,6 @@ ahd_reg_print_t ahd_dindir_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_function1_print;
-#else
-#define ahd_function1_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "FUNCTION1", 0xf0, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_stack_print;
#else
#define ahd_stack_print(regvalue, cur_col, wrap) \
@@ -1903,13 +1105,6 @@ ahd_reg_print_t ahd_curaddr_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lastaddr_print;
-#else
-#define ahd_lastaddr_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "LASTADDR", 0xf6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_intvec2_addr_print;
#else
#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \
@@ -1931,24 +1126,17 @@ ahd_reg_print_t ahd_accum_save_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_waiting_scb_tails_print;
-#else
-#define ahd_waiting_scb_tails_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "WAITING_SCB_TAILS", 0x100, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ahd_pci_config_base_print;
+ahd_reg_print_t ahd_sram_base_print;
#else
-#define ahd_ahd_pci_config_base_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "AHD_PCI_CONFIG_BASE", 0x100, regvalue, cur_col, wrap)
+#define ahd_sram_base_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SRAM_BASE", 0x100, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sram_base_print;
+ahd_reg_print_t ahd_waiting_scb_tails_print;
#else
-#define ahd_sram_base_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SRAM_BASE", 0x100, regvalue, cur_col, wrap)
+#define ahd_waiting_scb_tails_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "WAITING_SCB_TAILS", 0x100, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -2218,17 +1406,17 @@ ahd_reg_print_t ahd_mk_message_scsiid_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_base_print;
+ahd_reg_print_t ahd_scb_residual_datacnt_print;
#else
-#define ahd_scb_base_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCB_BASE", 0x180, regvalue, cur_col, wrap)
+#define ahd_scb_residual_datacnt_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT", 0x180, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_residual_datacnt_print;
+ahd_reg_print_t ahd_scb_base_print;
#else
-#define ahd_scb_residual_datacnt_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT", 0x180, regvalue, cur_col, wrap)
+#define ahd_scb_base_print(regvalue, cur_col, wrap) \
+ ahd_print_register(NULL, 0, "SCB_BASE", 0x180, regvalue, cur_col, wrap)
#endif
#if AIC_DEBUG_REGISTERS
@@ -2246,27 +1434,6 @@ ahd_reg_print_t ahd_scb_scsi_status_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_target_phases_print;
-#else
-#define ahd_scb_target_phases_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCB_TARGET_PHASES", 0x189, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_target_data_dir_print;
-#else
-#define ahd_scb_target_data_dir_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCB_TARGET_DATA_DIR", 0x18a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_target_itag_print;
-#else
-#define ahd_scb_target_itag_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCB_TARGET_ITAG", 0x18b, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_scb_sense_busaddr_print;
#else
#define ahd_scb_sense_busaddr_print(regvalue, cur_col, wrap) \
@@ -2365,13 +1532,6 @@ ahd_reg_print_t ahd_scb_next2_print;
#endif
#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_spare_print;
-#else
-#define ahd_scb_spare_print(regvalue, cur_col, wrap) \
- ahd_print_register(NULL, 0, "SCB_SPARE", 0x1b0, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
ahd_reg_print_t ahd_scb_disconnected_lists_print;
#else
#define ahd_scb_disconnected_lists_print(regvalue, cur_col, wrap) \
@@ -2557,10 +1717,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SG_CACHE_PRE 0x1b
-#define LQIN 0x20
-
#define TYPEPTR 0x20
+#define LQIN 0x20
+
#define TAGPTR 0x21
#define LUNPTR 0x22
@@ -2620,14 +1780,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SINGLECMD 0x02
#define ABORTPENDING 0x01
-#define SCSBIST0 0x39
-#define GSBISTERR 0x40
-#define GSBISTDONE 0x20
-#define GSBISTRUN 0x10
-#define OSBISTERR 0x04
-#define OSBISTDONE 0x02
-#define OSBISTRUN 0x01
-
#define LQCTL2 0x39
#define LQIRETRY 0x80
#define LQICONTINUE 0x40
@@ -2638,10 +1790,13 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define LQOTOIDLE 0x02
#define LQOPAUSE 0x01
-#define SCSBIST1 0x3a
-#define NTBISTERR 0x04
-#define NTBISTDONE 0x02
-#define NTBISTRUN 0x01
+#define SCSBIST0 0x39
+#define GSBISTERR 0x40
+#define GSBISTDONE 0x20
+#define GSBISTRUN 0x10
+#define OSBISTERR 0x04
+#define OSBISTDONE 0x02
+#define OSBISTRUN 0x01
#define SCSISEQ0 0x3a
#define TEMODEO 0x80
@@ -2650,8 +1805,15 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define FORCEBUSFREE 0x10
#define SCSIRSTO 0x01
+#define SCSBIST1 0x3a
+#define NTBISTERR 0x04
+#define NTBISTDONE 0x02
+#define NTBISTRUN 0x01
+
#define SCSISEQ1 0x3b
+#define BUSINITID 0x3c
+
#define SXFRCTL0 0x3c
#define DFON 0x80
#define DFPEXP 0x40
@@ -2660,8 +1822,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define DLCOUNT 0x3c
-#define BUSINITID 0x3c
-
#define SXFRCTL1 0x3d
#define BITBUCKET 0x80
#define ENSACHK 0x40
@@ -2686,6 +1846,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define CURRFIFO_1 0x01
#define CURRFIFO_0 0x00
+#define MULTARGID 0x40
+
#define SCSISIGO 0x40
#define CDO 0x80
#define IOO 0x40
@@ -2696,8 +1858,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define REQO 0x02
#define ACKO 0x01
-#define MULTARGID 0x40
-
#define SCSISIGI 0x41
#define ATNI 0x10
#define SELI 0x08
@@ -2744,15 +1904,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define ENAB20 0x04
#define SELWIDE 0x02
-#define CLRSINT0 0x4b
-#define CLRSELDO 0x40
-#define CLRSELDI 0x20
-#define CLRSELINGO 0x10
-#define CLRIOERR 0x08
-#define CLROVERRUN 0x04
-#define CLRSPIORDY 0x02
-#define CLRARBDO 0x01
-
#define SSTAT0 0x4b
#define TARGET 0x80
#define SELDO 0x40
@@ -2772,14 +1923,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define ENSPIORDY 0x02
#define ENARBDO 0x01
-#define CLRSINT1 0x4c
-#define CLRSELTIMEO 0x80
-#define CLRATNO 0x40
-#define CLRSCSIRSTI 0x20
-#define CLRBUSFREE 0x08
-#define CLRSCSIPERR 0x04
-#define CLRSTRB2FAST 0x02
-#define CLRREQINIT 0x01
+#define CLRSINT0 0x4b
+#define CLRSELDO 0x40
+#define CLRSELDI 0x20
+#define CLRSELINGO 0x10
+#define CLRIOERR 0x08
+#define CLROVERRUN 0x04
+#define CLRSPIORDY 0x02
+#define CLRARBDO 0x01
#define SSTAT1 0x4c
#define SELTO 0x80
@@ -2791,6 +1942,15 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define STRB2FAST 0x02
#define REQINIT 0x01
+#define CLRSINT1 0x4c
+#define CLRSELTIMEO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRSTRB2FAST 0x02
+#define CLRREQINIT 0x01
+
#define SSTAT2 0x4d
#define BUSFREETIME 0xc0
#define NONPACKREQ 0x20
@@ -2838,14 +1998,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define LQIATNLQ 0x02
#define LQIATNCMD 0x01
-#define CLRLQIINT0 0x50
-#define CLRLQIATNQAS 0x20
-#define CLRLQICRCT1 0x10
-#define CLRLQICRCT2 0x08
-#define CLRLQIBADLQT 0x04
-#define CLRLQIATNLQ 0x02
-#define CLRLQIATNCMD 0x01
-
#define LQIMODE0 0x50
#define ENLQIATNQASK 0x20
#define ENLQICRCT1 0x10
@@ -2854,6 +2006,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define ENLQIATNLQ 0x02
#define ENLQIATNCMD 0x01
+#define CLRLQIINT0 0x50
+#define CLRLQIATNQAS 0x20
+#define CLRLQICRCT1 0x10
+#define CLRLQICRCT2 0x08
+#define CLRLQIBADLQT 0x04
+#define CLRLQIATNLQ 0x02
+#define CLRLQIATNCMD 0x01
+
#define LQIMODE1 0x51
#define ENLQIPHASE_LQ 0x80
#define ENLQIPHASE_NLQ 0x40
@@ -2976,6 +2136,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define LQOSCSCTL 0x5a
#define LQOH2A_VERSION 0x80
+#define LQOBUSETDLY 0x40
+#define LQONOHOLDLACK 0x02
#define LQONOCHKOVER 0x01
#define NEXTSCB 0x5a
@@ -2998,8 +2160,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define CFG4ICMD 0x02
#define CFG4TCMD 0x01
-#define CURRSCB 0x5c
-
#define SEQIMODE 0x5c
#define ENCTXTDONE 0x40
#define ENSAVEPTRS 0x20
@@ -3009,6 +2169,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define ENCFG4ICMD 0x02
#define ENCFG4TCMD 0x01
+#define CURRSCB 0x5c
+
#define MDFFSTAT 0x5d
#define SHCNTNEGATIVE 0x40
#define SHCNTMINUS1 0x20
@@ -3023,29 +2185,29 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define DFFTAG 0x5e
-#define LASTSCB 0x5e
-
#define SCSITEST 0x5e
#define CNTRTEST 0x08
#define SEL_TXPLL_DEBUG 0x04
+#define LASTSCB 0x5e
+
#define IOPDNCTL 0x5f
#define DISABLE_OE 0x80
#define PDN_IDIST 0x04
#define PDN_DIFFSENSE 0x01
+#define DGRPCRCI 0x60
+
#define SHADDR 0x60
#define NEGOADDR 0x60
-#define DGRPCRCI 0x60
-
#define NEGPERIOD 0x61
-#define PACKCRCI 0x62
-
#define NEGOFFSET 0x62
+#define PACKCRCI 0x62
+
#define NEGPPROPTS 0x63
#define PPROPT_PACE 0x08
#define PPROPT_QAS 0x04
@@ -3066,6 +2228,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define ANNEXDAT 0x66
#define SCSCHKN 0x66
+#define BIDICHKDIS 0x80
#define STSELSKIDDIS 0x40
#define CURRFIFODEF 0x20
#define WIDERESEN 0x10
@@ -3090,6 +2253,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SELOID 0x6b
+#define FAIRNESS 0x6c
+
#define PLL400CTL0 0x6c
#define PLL_VCOSEL 0x80
#define PLL_PWDN 0x40
@@ -3099,8 +2264,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define PLL_DLPF 0x02
#define PLL_ENFBM 0x01
-#define FAIRNESS 0x6c
-
#define PLL400CTL1 0x6d
#define PLL_CNTEN 0x80
#define PLL_CNTCLR 0x40
@@ -3112,25 +2275,25 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define HADDR 0x70
+#define HODMAADR 0x70
+
#define PLLDELAY 0x70
#define SPLIT_DROP_REQ 0x80
-#define HODMAADR 0x70
+#define HCNT 0x78
#define HODMACNT 0x78
-#define HCNT 0x78
-
#define HODMAEN 0x7a
-#define SCBHADDR 0x7c
-
#define SGHADDR 0x7c
-#define SCBHCNT 0x84
+#define SCBHADDR 0x7c
#define SGHCNT 0x84
+#define SCBHCNT 0x84
+
#define DFF_THRSH 0x88
#define WR_DFTHRSH 0x70
#define RD_DFTHRSH 0x07
@@ -3163,6 +2326,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define CMCRXMSG0 0x90
+#define OVLYRXMSG0 0x90
+
+#define DCHRXMSG0 0x90
+
#define ROENABLE 0x90
#define MSIROEN 0x20
#define OVLYROEN 0x10
@@ -3171,11 +2338,11 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define DCH1ROEN 0x02
#define DCH0ROEN 0x01
-#define OVLYRXMSG0 0x90
+#define OVLYRXMSG1 0x91
-#define DCHRXMSG0 0x90
+#define CMCRXMSG1 0x91
-#define OVLYRXMSG1 0x91
+#define DCHRXMSG1 0x91
#define NSENABLE 0x91
#define MSINSEN 0x20
@@ -3185,10 +2352,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define DCH1NSEN 0x02
#define DCH0NSEN 0x01
-#define CMCRXMSG1 0x91
-
-#define DCHRXMSG1 0x91
-
#define DCHRXMSG2 0x92
#define CMCRXMSG2 0x92
@@ -3212,24 +2375,24 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define TSCSERREN 0x02
#define CMPABCDIS 0x01
+#define CMCSEQBCNT 0x94
+
#define OVLYSEQBCNT 0x94
#define DCHSEQBCNT 0x94
-#define CMCSEQBCNT 0x94
-
-#define CMCSPLTSTAT0 0x96
-
#define DCHSPLTSTAT0 0x96
#define OVLYSPLTSTAT0 0x96
-#define CMCSPLTSTAT1 0x97
+#define CMCSPLTSTAT0 0x96
#define OVLYSPLTSTAT1 0x97
#define DCHSPLTSTAT1 0x97
+#define CMCSPLTSTAT1 0x97
+
#define SGRXMSG0 0x98
#define CDNUM 0xf8
#define CFNUM 0x07
@@ -3257,18 +2420,15 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define TAG_NUM 0x1f
#define RLXORD 0x10
-#define SGSEQBCNT 0x9c
-
#define SLVSPLTOUTATTR0 0x9c
#define LOWER_BCNT 0xff
+#define SGSEQBCNT 0x9c
+
#define SLVSPLTOUTATTR1 0x9d
#define CMPLT_DNUM 0xf8
#define CMPLT_FNUM 0x07
-#define SLVSPLTOUTATTR2 0x9e
-#define CMPLT_BNUM 0xff
-
#define SGSPLTSTAT0 0x9e
#define STAETERM 0x80
#define SCBCERR 0x40
@@ -3279,6 +2439,9 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define RXSCEMSG 0x02
#define RXSPLTRSP 0x01
+#define SLVSPLTOUTATTR2 0x9e
+#define CMPLT_BNUM 0xff
+
#define SGSPLTSTAT1 0x9f
#define RXDATABUCKET 0x01
@@ -3334,10 +2497,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define CCSGADDR 0xac
-#define CCSCBADR_BK 0xac
-
#define CCSCBADDR 0xac
+#define CCSCBADR_BK 0xac
+
#define CMC_RAMBIST 0xad
#define SG_ELEMENT_SIZE 0x80
#define SCBRAMBIST_FAIL 0x40
@@ -3391,9 +2554,9 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SEEDAT 0xbc
#define SEECTL 0xbe
+#define SEEOP_EWDS 0x40
#define SEEOP_WALL 0x40
#define SEEOP_EWEN 0x40
-#define SEEOP_EWDS 0x40
#define SEEOPCODE 0x70
#define SEERST 0x02
#define SEESTART 0x01
@@ -3410,25 +2573,25 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SCBCNT 0xbf
-#define DFWADDR 0xc0
-
#define DSPFLTRCTL 0xc0
#define FLTRDISABLE 0x20
#define EDGESENSE 0x10
#define DSPFCNTSEL 0x0f
+#define DFWADDR 0xc0
+
#define DSPDATACTL 0xc1
#define BYPASSENAB 0x80
#define DESQDIS 0x10
#define RCVROFFSTDIS 0x04
#define XMITOFFSTDIS 0x02
-#define DFRADDR 0xc2
-
#define DSPREQCTL 0xc2
#define MANREQCTL 0xc0
#define MANREQDLY 0x3f
+#define DFRADDR 0xc2
+
#define DSPACKCTL 0xc3
#define MANACKCTL 0xc0
#define MANACKDLY 0x3f
@@ -3449,14 +2612,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define WRTBIASCALC 0xc7
-#define RCVRBIASCALC 0xc8
-
#define DFPTRS 0xc8
-#define SKEWCALC 0xc9
+#define RCVRBIASCALC 0xc8
#define DFBKPTR 0xc9
+#define SKEWCALC 0xc9
+
#define DFDBCTL 0xcb
#define DFF_CIO_WR_RDY 0x20
#define DFF_CIO_RD_RDY 0x10
@@ -3541,12 +2704,12 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define ACCUM_SAVE 0xfa
-#define WAITING_SCB_TAILS 0x100
-
#define AHD_PCI_CONFIG_BASE 0x100
#define SRAM_BASE 0x100
+#define WAITING_SCB_TAILS 0x100
+
#define WAITING_TID_HEAD 0x120
#define WAITING_TID_TAIL 0x122
@@ -3575,8 +2738,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define PRELOADEN 0x80
#define WIDEODD 0x40
#define SCSIEN 0x20
-#define SDMAEN 0x10
#define SDMAENACK 0x10
+#define SDMAEN 0x10
#define HDMAEN 0x08
#define HDMAENACK 0x08
#define DIRECTION 0x04
@@ -3674,12 +2837,12 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define MK_MESSAGE_SCSIID 0x162
-#define SCB_BASE 0x180
-
#define SCB_RESIDUAL_DATACNT 0x180
#define SCB_CDB_STORE 0x180
#define SCB_HOST_CDB_PTR 0x180
+#define SCB_BASE 0x180
+
#define SCB_RESIDUAL_SGPTR 0x184
#define SG_ADDR_MASK 0xf8
#define SG_OVERRUN_RESID 0x02
@@ -3747,6 +2910,17 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SCB_DISCONNECTED_LISTS 0x1b8
+#define CMD_GROUP_CODE_SHIFT 0x05
+#define STIMESEL_MIN 0x18
+#define STIMESEL_SHIFT 0x03
+#define INVALID_ADDR 0x80
+#define AHD_PRECOMP_MASK 0x07
+#define TARGET_DATA_IN 0x01
+#define CCSCBADDR_MAX 0x80
+#define NUMDSPS 0x14
+#define SEEOP_EWEN_ADDR 0xc0
+#define AHD_ANNEXCOL_PER_DEV0 0x04
+#define DST_MODE_SHIFT 0x04
#define AHD_TIMER_MAX_US 0x18ffe7
#define AHD_TIMER_MAX_TICKS 0xffff
#define AHD_SENSE_BUFSIZE 0x100
@@ -3781,43 +2955,32 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define LUNLEN_SINGLE_LEVEL_LUN 0x0f
#define NVRAM_SCB_OFFSET 0x2c
#define STATUS_PKT_SENSE 0xff
-#define CMD_GROUP_CODE_SHIFT 0x05
#define MAX_OFFSET_PACED_BUG 0x7f
#define STIMESEL_BUG_ADJ 0x08
-#define STIMESEL_MIN 0x18
-#define STIMESEL_SHIFT 0x03
#define CCSGRAM_MAXSEGS 0x10
-#define INVALID_ADDR 0x80
#define SEEOP_ERAL_ADDR 0x80
#define AHD_SLEWRATE_DEF_REVB 0x08
#define AHD_PRECOMP_CUTBACK_17 0x04
-#define AHD_PRECOMP_MASK 0x07
#define SRC_MODE_SHIFT 0x00
#define PKT_OVERRUN_BUFSIZE 0x200
#define SCB_TRANSFER_SIZE_1BYTE_LUN 0x30
-#define TARGET_DATA_IN 0x01
#define HOST_MSG 0xff
#define MAX_OFFSET 0xfe
#define BUS_16_BIT 0x01
-#define CCSCBADDR_MAX 0x80
-#define NUMDSPS 0x14
-#define SEEOP_EWEN_ADDR 0xc0
-#define AHD_ANNEXCOL_PER_DEV0 0x04
-#define DST_MODE_SHIFT 0x04
/* Downloaded Constant Definitions */
+#define SG_SIZEOF 0x04
+#define SG_PREFETCH_ALIGN_MASK 0x02
+#define SG_PREFETCH_CNT_LIMIT 0x01
#define CACHELINE_MASK 0x07
#define SCB_TRANSFER_SIZE 0x06
#define PKT_OVERRUN_BUFOFFSET 0x05
-#define SG_SIZEOF 0x04
#define SG_PREFETCH_ADDR_MASK 0x03
-#define SG_PREFETCH_ALIGN_MASK 0x02
-#define SG_PREFETCH_CNT_LIMIT 0x01
#define SG_PREFETCH_CNT 0x00
#define DOWNLOAD_CONST_COUNT 0x08
/* Exported Labels */
-#define LABEL_seq_isr 0x28f
#define LABEL_timer_isr 0x28b
+#define LABEL_seq_isr 0x28f
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
index db38a61a8cb4..c4c8a96bf5a3 100644
--- a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
@@ -8,7 +8,7 @@
#include "aic79xx_osm.h"
-static ahd_reg_parse_entry_t MODE_PTR_parse_table[] = {
+static const ahd_reg_parse_entry_t MODE_PTR_parse_table[] = {
{ "SRC_MODE", 0x07, 0x07 },
{ "DST_MODE", 0x70, 0x70 }
};
@@ -20,7 +20,7 @@ ahd_mode_ptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x00, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t INTSTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t INTSTAT_parse_table[] = {
{ "SPLTINT", 0x01, 0x01 },
{ "CMDCMPLT", 0x02, 0x02 },
{ "SEQINT", 0x04, 0x04 },
@@ -39,7 +39,7 @@ ahd_intstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x01, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQINTCODE_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQINTCODE_parse_table[] = {
{ "NO_SEQINT", 0x00, 0xff },
{ "BAD_PHASE", 0x01, 0xff },
{ "SEND_REJECT", 0x02, 0xff },
@@ -76,7 +76,7 @@ ahd_seqintcode_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x02, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRINT_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRINT_parse_table[] = {
{ "CLRSPLTINT", 0x01, 0x01 },
{ "CLRCMDINT", 0x02, 0x02 },
{ "CLRSEQINT", 0x04, 0x04 },
@@ -94,7 +94,7 @@ ahd_clrint_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x03, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t ERROR_parse_table[] = {
+static const ahd_reg_parse_entry_t ERROR_parse_table[] = {
{ "DSCTMOUT", 0x02, 0x02 },
{ "ILLOPCODE", 0x04, 0x04 },
{ "SQPARERR", 0x08, 0x08 },
@@ -111,24 +111,7 @@ ahd_error_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x04, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRERR_parse_table[] = {
- { "CLRDSCTMOUT", 0x02, 0x02 },
- { "CLRILLOPCODE", 0x04, 0x04 },
- { "CLRSQPARERR", 0x08, 0x08 },
- { "CLRDPARERR", 0x10, 0x10 },
- { "CLRMPARERR", 0x20, 0x20 },
- { "CLRCIOACCESFAIL", 0x40, 0x40 },
- { "CLRCIOPARERR", 0x80, 0x80 }
-};
-
-int
-ahd_clrerr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CLRERR_parse_table, 7, "CLRERR",
- 0x04, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t HCNTRL_parse_table[] = {
+static const ahd_reg_parse_entry_t HCNTRL_parse_table[] = {
{ "CHIPRST", 0x01, 0x01 },
{ "CHIPRSTACK", 0x01, 0x01 },
{ "INTEN", 0x02, 0x02 },
@@ -160,7 +143,7 @@ ahd_hescb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x08, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
+static const ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
{ "ENINT_COALESCE", 0x40, 0x40 },
{ "HOST_TQINPOS", 0x80, 0x80 }
};
@@ -172,7 +155,7 @@ ahd_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQINTSTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQINTSTAT_parse_table[] = {
{ "SEQ_SPLTINT", 0x01, 0x01 },
{ "SEQ_PCIINT", 0x02, 0x02 },
{ "SEQ_SCSIINT", 0x04, 0x04 },
@@ -187,7 +170,7 @@ ahd_seqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0c, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
{ "CLRSEQ_SPLTINT", 0x01, 0x01 },
{ "CLRSEQ_PCIINT", 0x02, 0x02 },
{ "CLRSEQ_SCSIINT", 0x04, 0x04 },
@@ -230,7 +213,7 @@ ahd_sdscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x14, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
+static const ahd_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
{ "SCB_QSIZE_4", 0x00, 0x0f },
{ "SCB_QSIZE_8", 0x01, 0x0f },
{ "SCB_QSIZE_16", 0x02, 0x0f },
@@ -258,7 +241,7 @@ ahd_qoff_ctlsta_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x16, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t INTCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t INTCTL_parse_table[] = {
{ "SPLTINTEN", 0x01, 0x01 },
{ "SEQINTEN", 0x02, 0x02 },
{ "SCSIINTEN", 0x04, 0x04 },
@@ -276,7 +259,7 @@ ahd_intctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x18, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DFCNTRL_parse_table[] = {
+static const ahd_reg_parse_entry_t DFCNTRL_parse_table[] = {
{ "DIRECTIONEN", 0x01, 0x01 },
{ "FIFOFLUSH", 0x02, 0x02 },
{ "FIFOFLUSHACK", 0x02, 0x02 },
@@ -297,7 +280,7 @@ ahd_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x19, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
+static const ahd_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
{ "CIOPARCKEN", 0x01, 0x01 },
{ "DISABLE_TWATE", 0x02, 0x02 },
{ "EXTREQLCK", 0x10, 0x10 },
@@ -313,7 +296,7 @@ ahd_dscommand0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x19, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DFSTATUS_parse_table[] = {
+static const ahd_reg_parse_entry_t DFSTATUS_parse_table[] = {
{ "FIFOEMP", 0x01, 0x01 },
{ "FIFOFULL", 0x02, 0x02 },
{ "DFTHRESH", 0x04, 0x04 },
@@ -330,7 +313,7 @@ ahd_dfstatus_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
+static const ahd_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
{ "LAST_SEG_DONE", 0x01, 0x01 },
{ "LAST_SEG", 0x02, 0x02 },
{ "ODD_SEG", 0x04, 0x04 },
@@ -344,20 +327,7 @@ ahd_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t ARBCTL_parse_table[] = {
- { "USE_TIME", 0x07, 0x07 },
- { "RETRY_SWEN", 0x08, 0x08 },
- { "RESET_HARB", 0x80, 0x80 }
-};
-
-int
-ahd_arbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(ARBCTL_parse_table, 3, "ARBCTL",
- 0x1b, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
+static const ahd_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
{ "LAST_SEG", 0x02, 0x02 },
{ "ODD_SEG", 0x04, 0x04 },
{ "SG_ADDR_MASK", 0xf8, 0xf8 }
@@ -378,20 +348,6 @@ ahd_lqin_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_typeptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "TYPEPTR",
- 0x20, regvalue, cur_col, wrap));
-}
-
-int
-ahd_tagptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "TAGPTR",
- 0x21, regvalue, cur_col, wrap));
-}
-
-int
ahd_lunptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "LUNPTR",
@@ -399,20 +355,6 @@ ahd_lunptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_datalenptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DATALENPTR",
- 0x23, regvalue, cur_col, wrap));
-}
-
-int
-ahd_statlenptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "STATLENPTR",
- 0x24, regvalue, cur_col, wrap));
-}
-
-int
ahd_cmdlenptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "CMDLENPTR",
@@ -448,13 +390,6 @@ ahd_qnextptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_idptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "IDPTR",
- 0x2a, regvalue, cur_col, wrap));
-}
-
-int
ahd_abrtbyteptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "ABRTBYTEPTR",
@@ -468,28 +403,7 @@ ahd_abrtbitptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x2c, regvalue, cur_col, wrap));
}
-int
-ahd_maxcmdbytes_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "MAXCMDBYTES",
- 0x2d, regvalue, cur_col, wrap));
-}
-
-int
-ahd_maxcmd2rcv_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "MAXCMD2RCV",
- 0x2e, regvalue, cur_col, wrap));
-}
-
-int
-ahd_shortthresh_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SHORTTHRESH",
- 0x2f, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t LUNLEN_parse_table[] = {
+static const ahd_reg_parse_entry_t LUNLEN_parse_table[] = {
{ "ILUNLEN", 0x0f, 0x0f },
{ "TLUNLEN", 0xf0, 0xf0 }
};
@@ -522,49 +436,7 @@ ahd_maxcmdcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x33, regvalue, cur_col, wrap));
}
-int
-ahd_lqrsvd01_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "LQRSVD01",
- 0x34, regvalue, cur_col, wrap));
-}
-
-int
-ahd_lqrsvd16_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "LQRSVD16",
- 0x35, regvalue, cur_col, wrap));
-}
-
-int
-ahd_lqrsvd17_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "LQRSVD17",
- 0x36, regvalue, cur_col, wrap));
-}
-
-int
-ahd_cmdrsvd0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "CMDRSVD0",
- 0x37, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t LQCTL0_parse_table[] = {
- { "LQ0INITGCLT", 0x03, 0x03 },
- { "LQ0TARGCLT", 0x0c, 0x0c },
- { "LQIINITGCLT", 0x30, 0x30 },
- { "LQITARGCLT", 0xc0, 0xc0 }
-};
-
-int
-ahd_lqctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(LQCTL0_parse_table, 4, "LQCTL0",
- 0x38, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t LQCTL1_parse_table[] = {
+static const ahd_reg_parse_entry_t LQCTL1_parse_table[] = {
{ "ABORTPENDING", 0x01, 0x01 },
{ "SINGLECMD", 0x02, 0x02 },
{ "PCI2PCI", 0x04, 0x04 }
@@ -577,23 +449,7 @@ ahd_lqctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x38, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSBIST0_parse_table[] = {
- { "OSBISTRUN", 0x01, 0x01 },
- { "OSBISTDONE", 0x02, 0x02 },
- { "OSBISTERR", 0x04, 0x04 },
- { "GSBISTRUN", 0x10, 0x10 },
- { "GSBISTDONE", 0x20, 0x20 },
- { "GSBISTERR", 0x40, 0x40 }
-};
-
-int
-ahd_scsbist0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SCSBIST0_parse_table, 6, "SCSBIST0",
- 0x39, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t LQCTL2_parse_table[] = {
+static const ahd_reg_parse_entry_t LQCTL2_parse_table[] = {
{ "LQOPAUSE", 0x01, 0x01 },
{ "LQOTOIDLE", 0x02, 0x02 },
{ "LQOCONTINUE", 0x04, 0x04 },
@@ -611,20 +467,7 @@ ahd_lqctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x39, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSBIST1_parse_table[] = {
- { "NTBISTRUN", 0x01, 0x01 },
- { "NTBISTDONE", 0x02, 0x02 },
- { "NTBISTERR", 0x04, 0x04 }
-};
-
-int
-ahd_scsbist1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SCSBIST1_parse_table, 3, "SCSBIST1",
- 0x3a, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SCSISEQ0_parse_table[] = {
+static const ahd_reg_parse_entry_t SCSISEQ0_parse_table[] = {
{ "SCSIRSTO", 0x01, 0x01 },
{ "FORCEBUSFREE", 0x10, 0x10 },
{ "ENARBO", 0x20, 0x20 },
@@ -639,7 +482,7 @@ ahd_scsiseq0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSISEQ1_parse_table[] = {
+static const ahd_reg_parse_entry_t SCSISEQ1_parse_table[] = {
{ "ALTSTIM", 0x01, 0x01 },
{ "ENAUTOATNP", 0x02, 0x02 },
{ "MANUALP", 0x0c, 0x0c },
@@ -655,7 +498,7 @@ ahd_scsiseq1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SXFRCTL0_parse_table[] = {
+static const ahd_reg_parse_entry_t SXFRCTL0_parse_table[] = {
{ "SPIOEN", 0x08, 0x08 },
{ "BIOSCANCELEN", 0x10, 0x10 },
{ "DFPEXP", 0x40, 0x40 },
@@ -669,21 +512,7 @@ ahd_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3c, regvalue, cur_col, wrap));
}
-int
-ahd_dlcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DLCOUNT",
- 0x3c, regvalue, cur_col, wrap));
-}
-
-int
-ahd_businitid_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "BUSINITID",
- 0x3c, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SXFRCTL1_parse_table[] = {
+static const ahd_reg_parse_entry_t SXFRCTL1_parse_table[] = {
{ "STPWEN", 0x01, 0x01 },
{ "ACTNEGEN", 0x02, 0x02 },
{ "ENSTIMER", 0x04, 0x04 },
@@ -700,27 +529,7 @@ ahd_sxfrctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3d, regvalue, cur_col, wrap));
}
-int
-ahd_bustargid_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "BUSTARGID",
- 0x3e, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SXFRCTL2_parse_table[] = {
- { "ASU", 0x07, 0x07 },
- { "CMDDMAEN", 0x08, 0x08 },
- { "AUTORSTDIS", 0x10, 0x10 }
-};
-
-int
-ahd_sxfrctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SXFRCTL2_parse_table, 3, "SXFRCTL2",
- 0x3e, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DFFSTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t DFFSTAT_parse_table[] = {
{ "CURRFIFO_0", 0x00, 0x03 },
{ "CURRFIFO_1", 0x01, 0x03 },
{ "CURRFIFO_NONE", 0x03, 0x03 },
@@ -736,7 +545,14 @@ ahd_dffstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3f, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSISIGO_parse_table[] = {
+int
+ahd_multargid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+ return (ahd_print_register(NULL, 0, "MULTARGID",
+ 0x40, regvalue, cur_col, wrap));
+}
+
+static const ahd_reg_parse_entry_t SCSISIGO_parse_table[] = {
{ "P_DATAOUT", 0x00, 0xe0 },
{ "P_DATAOUT_DT", 0x20, 0xe0 },
{ "P_DATAIN", 0x40, 0xe0 },
@@ -763,14 +579,7 @@ ahd_scsisigo_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x40, regvalue, cur_col, wrap));
}
-int
-ahd_multargid_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "MULTARGID",
- 0x40, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SCSISIGI_parse_table[] = {
+static const ahd_reg_parse_entry_t SCSISIGI_parse_table[] = {
{ "P_DATAOUT", 0x00, 0xe0 },
{ "P_DATAOUT_DT", 0x20, 0xe0 },
{ "P_DATAIN", 0x40, 0xe0 },
@@ -797,7 +606,7 @@ ahd_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x41, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSIPHASE_parse_table[] = {
+static const ahd_reg_parse_entry_t SCSIPHASE_parse_table[] = {
{ "DATA_OUT_PHASE", 0x01, 0x03 },
{ "DATA_IN_PHASE", 0x02, 0x03 },
{ "DATA_PHASE_MASK", 0x03, 0x03 },
@@ -815,13 +624,6 @@ ahd_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_scsidat0_img_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SCSIDAT0_IMG",
- 0x43, regvalue, cur_col, wrap));
-}
-
-int
ahd_scsidat_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "SCSIDAT",
@@ -835,7 +637,7 @@ ahd_scsibus_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x46, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t TARGIDIN_parse_table[] = {
+static const ahd_reg_parse_entry_t TARGIDIN_parse_table[] = {
{ "TARGID", 0x0f, 0x0f },
{ "CLKOUT", 0x80, 0x80 }
};
@@ -847,7 +649,7 @@ ahd_targidin_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x48, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SELID_parse_table[] = {
+static const ahd_reg_parse_entry_t SELID_parse_table[] = {
{ "ONEBIT", 0x08, 0x08 },
{ "SELID_MASK", 0xf0, 0xf0 }
};
@@ -859,7 +661,7 @@ ahd_selid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x49, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t OPTIONMODE_parse_table[] = {
+static const ahd_reg_parse_entry_t OPTIONMODE_parse_table[] = {
{ "AUTO_MSGOUT_DE", 0x02, 0x02 },
{ "ENDGFORMCHK", 0x04, 0x04 },
{ "BUSFREEREV", 0x10, 0x10 },
@@ -876,7 +678,7 @@ ahd_optionmode_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
{ "SELWIDE", 0x02, 0x02 },
{ "ENAB20", 0x04, 0x04 },
{ "ENAB40", 0x08, 0x08 },
@@ -891,24 +693,7 @@ ahd_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRSINT0_parse_table[] = {
- { "CLRARBDO", 0x01, 0x01 },
- { "CLRSPIORDY", 0x02, 0x02 },
- { "CLROVERRUN", 0x04, 0x04 },
- { "CLRIOERR", 0x08, 0x08 },
- { "CLRSELINGO", 0x10, 0x10 },
- { "CLRSELDI", 0x20, 0x20 },
- { "CLRSELDO", 0x40, 0x40 }
-};
-
-int
-ahd_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CLRSINT0_parse_table, 7, "CLRSINT0",
- 0x4b, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
+static const ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
{ "ARBDO", 0x01, 0x01 },
{ "SPIORDY", 0x02, 0x02 },
{ "OVERRUN", 0x04, 0x04 },
@@ -926,7 +711,7 @@ ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SIMODE0_parse_table[] = {
+static const ahd_reg_parse_entry_t SIMODE0_parse_table[] = {
{ "ENARBDO", 0x01, 0x01 },
{ "ENSPIORDY", 0x02, 0x02 },
{ "ENOVERRUN", 0x04, 0x04 },
@@ -943,24 +728,24 @@ ahd_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRSINT1_parse_table[] = {
- { "CLRREQINIT", 0x01, 0x01 },
- { "CLRSTRB2FAST", 0x02, 0x02 },
- { "CLRSCSIPERR", 0x04, 0x04 },
- { "CLRBUSFREE", 0x08, 0x08 },
- { "CLRSCSIRSTI", 0x20, 0x20 },
- { "CLRATNO", 0x40, 0x40 },
- { "CLRSELTIMEO", 0x80, 0x80 }
+static const ahd_reg_parse_entry_t CLRSINT0_parse_table[] = {
+ { "CLRARBDO", 0x01, 0x01 },
+ { "CLRSPIORDY", 0x02, 0x02 },
+ { "CLROVERRUN", 0x04, 0x04 },
+ { "CLRIOERR", 0x08, 0x08 },
+ { "CLRSELINGO", 0x10, 0x10 },
+ { "CLRSELDI", 0x20, 0x20 },
+ { "CLRSELDO", 0x40, 0x40 }
};
int
-ahd_clrsint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(CLRSINT1_parse_table, 7, "CLRSINT1",
- 0x4c, regvalue, cur_col, wrap));
+ return (ahd_print_register(CLRSINT0_parse_table, 7, "CLRSINT0",
+ 0x4b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SSTAT1_parse_table[] = {
+static const ahd_reg_parse_entry_t SSTAT1_parse_table[] = {
{ "REQINIT", 0x01, 0x01 },
{ "STRB2FAST", 0x02, 0x02 },
{ "SCSIPERR", 0x04, 0x04 },
@@ -978,7 +763,24 @@ ahd_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4c, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SSTAT2_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRSINT1_parse_table[] = {
+ { "CLRREQINIT", 0x01, 0x01 },
+ { "CLRSTRB2FAST", 0x02, 0x02 },
+ { "CLRSCSIPERR", 0x04, 0x04 },
+ { "CLRBUSFREE", 0x08, 0x08 },
+ { "CLRSCSIRSTI", 0x20, 0x20 },
+ { "CLRATNO", 0x40, 0x40 },
+ { "CLRSELTIMEO", 0x80, 0x80 }
+};
+
+int
+ahd_clrsint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+ return (ahd_print_register(CLRSINT1_parse_table, 7, "CLRSINT1",
+ 0x4c, regvalue, cur_col, wrap));
+}
+
+static const ahd_reg_parse_entry_t SSTAT2_parse_table[] = {
{ "BUSFREE_LQO", 0x40, 0xc0 },
{ "BUSFREE_DFF0", 0x80, 0xc0 },
{ "BUSFREE_DFF1", 0xc0, 0xc0 },
@@ -998,20 +800,7 @@ ahd_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4d, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SIMODE2_parse_table[] = {
- { "ENDMADONE", 0x01, 0x01 },
- { "ENSDONE", 0x02, 0x02 },
- { "ENWIDE_RES", 0x04, 0x04 }
-};
-
-int
-ahd_simode2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SIMODE2_parse_table, 3, "SIMODE2",
- 0x4d, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CLRSINT2_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRSINT2_parse_table[] = {
{ "CLRDMADONE", 0x01, 0x01 },
{ "CLRSDONE", 0x02, 0x02 },
{ "CLRWIDE_RES", 0x04, 0x04 },
@@ -1025,7 +814,7 @@ ahd_clrsint2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4d, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t PERRDIAG_parse_table[] = {
+static const ahd_reg_parse_entry_t PERRDIAG_parse_table[] = {
{ "DTERR", 0x01, 0x01 },
{ "DGFORMERR", 0x02, 0x02 },
{ "CRCERR", 0x04, 0x04 },
@@ -1064,7 +853,7 @@ ahd_lqostate_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x4f, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQISTAT0_parse_table[] = {
+static const ahd_reg_parse_entry_t LQISTAT0_parse_table[] = {
{ "LQIATNCMD", 0x01, 0x01 },
{ "LQIATNLQ", 0x02, 0x02 },
{ "LQIBADLQT", 0x04, 0x04 },
@@ -1080,23 +869,7 @@ ahd_lqistat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x50, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRLQIINT0_parse_table[] = {
- { "CLRLQIATNCMD", 0x01, 0x01 },
- { "CLRLQIATNLQ", 0x02, 0x02 },
- { "CLRLQIBADLQT", 0x04, 0x04 },
- { "CLRLQICRCT2", 0x08, 0x08 },
- { "CLRLQICRCT1", 0x10, 0x10 },
- { "CLRLQIATNQAS", 0x20, 0x20 }
-};
-
-int
-ahd_clrlqiint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CLRLQIINT0_parse_table, 6, "CLRLQIINT0",
- 0x50, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t LQIMODE0_parse_table[] = {
+static const ahd_reg_parse_entry_t LQIMODE0_parse_table[] = {
{ "ENLQIATNCMD", 0x01, 0x01 },
{ "ENLQIATNLQ", 0x02, 0x02 },
{ "ENLQIBADLQT", 0x04, 0x04 },
@@ -1112,7 +885,23 @@ ahd_lqimode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x50, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQIMODE1_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRLQIINT0_parse_table[] = {
+ { "CLRLQIATNCMD", 0x01, 0x01 },
+ { "CLRLQIATNLQ", 0x02, 0x02 },
+ { "CLRLQIBADLQT", 0x04, 0x04 },
+ { "CLRLQICRCT2", 0x08, 0x08 },
+ { "CLRLQICRCT1", 0x10, 0x10 },
+ { "CLRLQIATNQAS", 0x20, 0x20 }
+};
+
+int
+ahd_clrlqiint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+ return (ahd_print_register(CLRLQIINT0_parse_table, 6, "CLRLQIINT0",
+ 0x50, regvalue, cur_col, wrap));
+}
+
+static const ahd_reg_parse_entry_t LQIMODE1_parse_table[] = {
{ "ENLQIOVERI_NLQ", 0x01, 0x01 },
{ "ENLQIOVERI_LQ", 0x02, 0x02 },
{ "ENLQIBADLQI", 0x04, 0x04 },
@@ -1130,7 +919,7 @@ ahd_lqimode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x51, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQISTAT1_parse_table[] = {
+static const ahd_reg_parse_entry_t LQISTAT1_parse_table[] = {
{ "LQIOVERI_NLQ", 0x01, 0x01 },
{ "LQIOVERI_LQ", 0x02, 0x02 },
{ "LQIBADLQI", 0x04, 0x04 },
@@ -1148,7 +937,7 @@ ahd_lqistat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x51, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRLQIINT1_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRLQIINT1_parse_table[] = {
{ "CLRLQIOVERI_NLQ", 0x01, 0x01 },
{ "CLRLQIOVERI_LQ", 0x02, 0x02 },
{ "CLRLQIBADLQI", 0x04, 0x04 },
@@ -1166,7 +955,7 @@ ahd_clrlqiint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x51, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQISTAT2_parse_table[] = {
+static const ahd_reg_parse_entry_t LQISTAT2_parse_table[] = {
{ "LQIGSAVAIL", 0x01, 0x01 },
{ "LQISTOPCMD", 0x02, 0x02 },
{ "LQISTOPLQ", 0x04, 0x04 },
@@ -1184,7 +973,7 @@ ahd_lqistat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x52, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SSTAT3_parse_table[] = {
+static const ahd_reg_parse_entry_t SSTAT3_parse_table[] = {
{ "OSRAMPERR", 0x01, 0x01 },
{ "NTRAMPERR", 0x02, 0x02 }
};
@@ -1196,7 +985,7 @@ ahd_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x53, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SIMODE3_parse_table[] = {
+static const ahd_reg_parse_entry_t SIMODE3_parse_table[] = {
{ "ENOSRAMPERR", 0x01, 0x01 },
{ "ENNTRAMPERR", 0x02, 0x02 }
};
@@ -1208,7 +997,7 @@ ahd_simode3_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x53, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRSINT3_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRSINT3_parse_table[] = {
{ "CLROSRAMPERR", 0x01, 0x01 },
{ "CLRNTRAMPERR", 0x02, 0x02 }
};
@@ -1220,7 +1009,7 @@ ahd_clrsint3_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x53, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQOSTAT0_parse_table[] = {
+static const ahd_reg_parse_entry_t LQOSTAT0_parse_table[] = {
{ "LQOTCRC", 0x01, 0x01 },
{ "LQOATNPKT", 0x02, 0x02 },
{ "LQOATNLQ", 0x04, 0x04 },
@@ -1235,7 +1024,7 @@ ahd_lqostat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x54, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRLQOINT0_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRLQOINT0_parse_table[] = {
{ "CLRLQOTCRC", 0x01, 0x01 },
{ "CLRLQOATNPKT", 0x02, 0x02 },
{ "CLRLQOATNLQ", 0x04, 0x04 },
@@ -1250,7 +1039,7 @@ ahd_clrlqoint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x54, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
+static const ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
{ "ENLQOTCRC", 0x01, 0x01 },
{ "ENLQOATNPKT", 0x02, 0x02 },
{ "ENLQOATNLQ", 0x04, 0x04 },
@@ -1265,7 +1054,7 @@ ahd_lqomode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x54, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
+static const ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
{ "ENLQOPHACHGINPKT", 0x01, 0x01 },
{ "ENLQOBUSFREE", 0x02, 0x02 },
{ "ENLQOBADQAS", 0x04, 0x04 },
@@ -1280,7 +1069,7 @@ ahd_lqomode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x55, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQOSTAT1_parse_table[] = {
+static const ahd_reg_parse_entry_t LQOSTAT1_parse_table[] = {
{ "LQOPHACHGINPKT", 0x01, 0x01 },
{ "LQOBUSFREE", 0x02, 0x02 },
{ "LQOBADQAS", 0x04, 0x04 },
@@ -1295,7 +1084,7 @@ ahd_lqostat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x55, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRLQOINT1_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRLQOINT1_parse_table[] = {
{ "CLRLQOPHACHGINPKT", 0x01, 0x01 },
{ "CLRLQOBUSFREE", 0x02, 0x02 },
{ "CLRLQOBADQAS", 0x04, 0x04 },
@@ -1310,7 +1099,7 @@ ahd_clrlqoint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x55, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQOSTAT2_parse_table[] = {
+static const ahd_reg_parse_entry_t LQOSTAT2_parse_table[] = {
{ "LQOSTOP0", 0x01, 0x01 },
{ "LQOPHACHGOUTPKT", 0x02, 0x02 },
{ "LQOWAITFIFO", 0x10, 0x10 },
@@ -1331,7 +1120,7 @@ ahd_os_space_cnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x56, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SIMODE1_parse_table[] = {
+static const ahd_reg_parse_entry_t SIMODE1_parse_table[] = {
{ "ENREQINIT", 0x01, 0x01 },
{ "ENSTRB2FAST", 0x02, 0x02 },
{ "ENSCSIPERR", 0x04, 0x04 },
@@ -1356,7 +1145,7 @@ ahd_gsfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x58, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DFFSXFRCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t DFFSXFRCTL_parse_table[] = {
{ "RSTCHN", 0x01, 0x01 },
{ "CLRCHN", 0x02, 0x02 },
{ "CLRSHCNT", 0x04, 0x04 },
@@ -1370,15 +1159,17 @@ ahd_dffsxfrctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LQOSCSCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t LQOSCSCTL_parse_table[] = {
{ "LQONOCHKOVER", 0x01, 0x01 },
+ { "LQONOHOLDLACK", 0x02, 0x02 },
+ { "LQOBUSETDLY", 0x40, 0x40 },
{ "LQOH2A_VERSION", 0x80, 0x80 }
};
int
ahd_lqoscsctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(LQOSCSCTL_parse_table, 2, "LQOSCSCTL",
+ return (ahd_print_register(LQOSCSCTL_parse_table, 4, "LQOSCSCTL",
0x5a, regvalue, cur_col, wrap));
}
@@ -1389,7 +1180,7 @@ ahd_nextscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CLRSEQINTSRC_parse_table[] = {
+static const ahd_reg_parse_entry_t CLRSEQINTSRC_parse_table[] = {
{ "CLRCFG4TCMD", 0x01, 0x01 },
{ "CLRCFG4ICMD", 0x02, 0x02 },
{ "CLRCFG4TSTAT", 0x04, 0x04 },
@@ -1406,7 +1197,7 @@ ahd_clrseqintsrc_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQINTSRC_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQINTSRC_parse_table[] = {
{ "CFG4TCMD", 0x01, 0x01 },
{ "CFG4ICMD", 0x02, 0x02 },
{ "CFG4TSTAT", 0x04, 0x04 },
@@ -1423,14 +1214,7 @@ ahd_seqintsrc_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5b, regvalue, cur_col, wrap));
}
-int
-ahd_currscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "CURRSCB",
- 0x5c, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SEQIMODE_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQIMODE_parse_table[] = {
{ "ENCFG4TCMD", 0x01, 0x01 },
{ "ENCFG4ICMD", 0x02, 0x02 },
{ "ENCFG4TSTAT", 0x04, 0x04 },
@@ -1447,7 +1231,14 @@ ahd_seqimode_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5c, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t MDFFSTAT_parse_table[] = {
+int
+ahd_currscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+ return (ahd_print_register(NULL, 0, "CURRSCB",
+ 0x5c, regvalue, cur_col, wrap));
+}
+
+static const ahd_reg_parse_entry_t MDFFSTAT_parse_table[] = {
{ "FIFOFREE", 0x01, 0x01 },
{ "DATAINFIFO", 0x02, 0x02 },
{ "DLZERO", 0x04, 0x04 },
@@ -1464,24 +1255,6 @@ ahd_mdffstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5d, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CRCCONTROL_parse_table[] = {
- { "CRCVALCHKEN", 0x40, 0x40 }
-};
-
-int
-ahd_crccontrol_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CRCCONTROL_parse_table, 1, "CRCCONTROL",
- 0x5d, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dfftag_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFFTAG",
- 0x5e, regvalue, cur_col, wrap));
-}
-
int
ahd_lastscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -1489,31 +1262,6 @@ ahd_lastscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5e, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSITEST_parse_table[] = {
- { "SEL_TXPLL_DEBUG", 0x04, 0x04 },
- { "CNTRTEST", 0x08, 0x08 }
-};
-
-int
-ahd_scsitest_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SCSITEST_parse_table, 2, "SCSITEST",
- 0x5e, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t IOPDNCTL_parse_table[] = {
- { "PDN_DIFFSENSE", 0x01, 0x01 },
- { "PDN_IDIST", 0x04, 0x04 },
- { "DISABLE_OE", 0x80, 0x80 }
-};
-
-int
-ahd_iopdnctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(IOPDNCTL_parse_table, 3, "IOPDNCTL",
- 0x5f, regvalue, cur_col, wrap));
-}
-
int
ahd_shaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -1529,13 +1277,6 @@ ahd_negoaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_dgrpcrci_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DGRPCRCI",
- 0x60, regvalue, cur_col, wrap));
-}
-
-int
ahd_negperiod_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "NEGPERIOD",
@@ -1543,20 +1284,13 @@ ahd_negperiod_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_packcrci_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "PACKCRCI",
- 0x62, regvalue, cur_col, wrap));
-}
-
-int
ahd_negoffset_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "NEGOFFSET",
0x62, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t NEGPPROPTS_parse_table[] = {
+static const ahd_reg_parse_entry_t NEGPPROPTS_parse_table[] = {
{ "PPROPT_IUT", 0x01, 0x01 },
{ "PPROPT_DT", 0x02, 0x02 },
{ "PPROPT_QAS", 0x04, 0x04 },
@@ -1570,7 +1304,7 @@ ahd_negppropts_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x63, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t NEGCONOPTS_parse_table[] = {
+static const ahd_reg_parse_entry_t NEGCONOPTS_parse_table[] = {
{ "WIDEXFER", 0x01, 0x01 },
{ "ENAUTOATNO", 0x02, 0x02 },
{ "ENAUTOATNI", 0x04, 0x04 },
@@ -1601,20 +1335,21 @@ ahd_annexdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x66, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSCHKN_parse_table[] = {
+static const ahd_reg_parse_entry_t SCSCHKN_parse_table[] = {
{ "LSTSGCLRDIS", 0x01, 0x01 },
{ "SHVALIDSTDIS", 0x02, 0x02 },
{ "DFFACTCLR", 0x04, 0x04 },
{ "SDONEMSKDIS", 0x08, 0x08 },
{ "WIDERESEN", 0x10, 0x10 },
{ "CURRFIFODEF", 0x20, 0x20 },
- { "STSELSKIDDIS", 0x40, 0x40 }
+ { "STSELSKIDDIS", 0x40, 0x40 },
+ { "BIDICHKDIS", 0x80, 0x80 }
};
int
ahd_scschkn_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(SCSCHKN_parse_table, 7, "SCSCHKN",
+ return (ahd_print_register(SCSCHKN_parse_table, 8, "SCSCHKN",
0x66, regvalue, cur_col, wrap));
}
@@ -1625,23 +1360,6 @@ ahd_iownid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x67, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t PLL960CTL0_parse_table[] = {
- { "PLL_ENFBM", 0x01, 0x01 },
- { "PLL_DLPF", 0x02, 0x02 },
- { "PLL_ENLPF", 0x04, 0x04 },
- { "PLL_ENLUD", 0x08, 0x08 },
- { "PLL_NS", 0x30, 0x30 },
- { "PLL_PWDN", 0x40, 0x40 },
- { "PLL_VCOSEL", 0x80, 0x80 }
-};
-
-int
-ahd_pll960ctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(PLL960CTL0_parse_table, 7, "PLL960CTL0",
- 0x68, regvalue, cur_col, wrap));
-}
-
int
ahd_shcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -1656,33 +1374,6 @@ ahd_townid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x69, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t PLL960CTL1_parse_table[] = {
- { "PLL_RST", 0x01, 0x01 },
- { "PLL_CNTCLR", 0x40, 0x40 },
- { "PLL_CNTEN", 0x80, 0x80 }
-};
-
-int
-ahd_pll960ctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(PLL960CTL1_parse_table, 3, "PLL960CTL1",
- 0x69, regvalue, cur_col, wrap));
-}
-
-int
-ahd_pll960cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "PLL960CNT0",
- 0x6a, regvalue, cur_col, wrap));
-}
-
-int
-ahd_xsig_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "XSIG",
- 0x6a, regvalue, cur_col, wrap));
-}
-
int
ahd_seloid_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -1690,57 +1381,6 @@ ahd_seloid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x6b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t PLL400CTL0_parse_table[] = {
- { "PLL_ENFBM", 0x01, 0x01 },
- { "PLL_DLPF", 0x02, 0x02 },
- { "PLL_ENLPF", 0x04, 0x04 },
- { "PLL_ENLUD", 0x08, 0x08 },
- { "PLL_NS", 0x30, 0x30 },
- { "PLL_PWDN", 0x40, 0x40 },
- { "PLL_VCOSEL", 0x80, 0x80 }
-};
-
-int
-ahd_pll400ctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(PLL400CTL0_parse_table, 7, "PLL400CTL0",
- 0x6c, regvalue, cur_col, wrap));
-}
-
-int
-ahd_fairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "FAIRNESS",
- 0x6c, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t PLL400CTL1_parse_table[] = {
- { "PLL_RST", 0x01, 0x01 },
- { "PLL_CNTCLR", 0x40, 0x40 },
- { "PLL_CNTEN", 0x80, 0x80 }
-};
-
-int
-ahd_pll400ctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(PLL400CTL1_parse_table, 3, "PLL400CTL1",
- 0x6d, regvalue, cur_col, wrap));
-}
-
-int
-ahd_unfairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "UNFAIRNESS",
- 0x6e, regvalue, cur_col, wrap));
-}
-
-int
-ahd_pll400cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "PLL400CNT0",
- 0x6e, regvalue, cur_col, wrap));
-}
-
int
ahd_haddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -1748,31 +1388,6 @@ ahd_haddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x70, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t PLLDELAY_parse_table[] = {
- { "SPLIT_DROP_REQ", 0x80, 0x80 }
-};
-
-int
-ahd_plldelay_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(PLLDELAY_parse_table, 1, "PLLDELAY",
- 0x70, regvalue, cur_col, wrap));
-}
-
-int
-ahd_hodmaadr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "HODMAADR",
- 0x70, regvalue, cur_col, wrap));
-}
-
-int
-ahd_hodmacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "HODMACNT",
- 0x78, regvalue, cur_col, wrap));
-}
-
int
ahd_hcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -1781,10 +1396,10 @@ ahd_hcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_hodmaen_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(NULL, 0, "HODMAEN",
- 0x7a, regvalue, cur_col, wrap));
+ return (ahd_print_register(NULL, 0, "SGHADDR",
+ 0x7c, regvalue, cur_col, wrap));
}
int
@@ -1795,10 +1410,10 @@ ahd_scbhaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(NULL, 0, "SGHADDR",
- 0x7c, regvalue, cur_col, wrap));
+ return (ahd_print_register(NULL, 0, "SGHCNT",
+ 0x84, regvalue, cur_col, wrap));
}
int
@@ -1808,14 +1423,7 @@ ahd_scbhcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x84, regvalue, cur_col, wrap));
}
-int
-ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SGHCNT",
- 0x84, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DFF_THRSH_parse_table[] = {
+static const ahd_reg_parse_entry_t DFF_THRSH_parse_table[] = {
{ "WR_DFTHRSH_MIN", 0x00, 0x70 },
{ "RD_DFTHRSH_MIN", 0x00, 0x07 },
{ "RD_DFTHRSH_25", 0x01, 0x07 },
@@ -1843,209 +1451,7 @@ ahd_dff_thrsh_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x88, regvalue, cur_col, wrap));
}
-int
-ahd_romaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "ROMADDR",
- 0x8a, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t ROMCNTRL_parse_table[] = {
- { "RDY", 0x01, 0x01 },
- { "REPEAT", 0x02, 0x02 },
- { "ROMSPD", 0x18, 0x18 },
- { "ROMOP", 0xe0, 0xe0 }
-};
-
-int
-ahd_romcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(ROMCNTRL_parse_table, 4, "ROMCNTRL",
- 0x8d, regvalue, cur_col, wrap));
-}
-
-int
-ahd_romdata_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "ROMDATA",
- 0x8e, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCRXMSG0_parse_table[] = {
- { "CFNUM", 0x07, 0x07 },
- { "CDNUM", 0xf8, 0xf8 }
-};
-
-int
-ahd_cmcrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCRXMSG0_parse_table, 2, "CMCRXMSG0",
- 0x90, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t ROENABLE_parse_table[] = {
- { "DCH0ROEN", 0x01, 0x01 },
- { "DCH1ROEN", 0x02, 0x02 },
- { "SGROEN", 0x04, 0x04 },
- { "CMCROEN", 0x08, 0x08 },
- { "OVLYROEN", 0x10, 0x10 },
- { "MSIROEN", 0x20, 0x20 }
-};
-
-int
-ahd_roenable_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(ROENABLE_parse_table, 6, "ROENABLE",
- 0x90, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t OVLYRXMSG0_parse_table[] = {
- { "CFNUM", 0x07, 0x07 },
- { "CDNUM", 0xf8, 0xf8 }
-};
-
-int
-ahd_ovlyrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYRXMSG0_parse_table, 2, "OVLYRXMSG0",
- 0x90, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DCHRXMSG0_parse_table[] = {
- { "CFNUM", 0x07, 0x07 },
- { "CDNUM", 0xf8, 0xf8 }
-};
-
-int
-ahd_dchrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DCHRXMSG0_parse_table, 2, "DCHRXMSG0",
- 0x90, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t OVLYRXMSG1_parse_table[] = {
- { "CBNUM", 0xff, 0xff }
-};
-
-int
-ahd_ovlyrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYRXMSG1_parse_table, 1, "OVLYRXMSG1",
- 0x91, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t NSENABLE_parse_table[] = {
- { "DCH0NSEN", 0x01, 0x01 },
- { "DCH1NSEN", 0x02, 0x02 },
- { "SGNSEN", 0x04, 0x04 },
- { "CMCNSEN", 0x08, 0x08 },
- { "OVLYNSEN", 0x10, 0x10 },
- { "MSINSEN", 0x20, 0x20 }
-};
-
-int
-ahd_nsenable_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NSENABLE_parse_table, 6, "NSENABLE",
- 0x91, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCRXMSG1_parse_table[] = {
- { "CBNUM", 0xff, 0xff }
-};
-
-int
-ahd_cmcrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCRXMSG1_parse_table, 1, "CMCRXMSG1",
- 0x91, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DCHRXMSG1_parse_table[] = {
- { "CBNUM", 0xff, 0xff }
-};
-
-int
-ahd_dchrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DCHRXMSG1_parse_table, 1, "DCHRXMSG1",
- 0x91, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DCHRXMSG2_parse_table[] = {
- { "MINDEX", 0xff, 0xff }
-};
-
-int
-ahd_dchrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DCHRXMSG2_parse_table, 1, "DCHRXMSG2",
- 0x92, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCRXMSG2_parse_table[] = {
- { "MINDEX", 0xff, 0xff }
-};
-
-int
-ahd_cmcrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCRXMSG2_parse_table, 1, "CMCRXMSG2",
- 0x92, regvalue, cur_col, wrap));
-}
-
-int
-ahd_ost_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "OST",
- 0x92, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t OVLYRXMSG2_parse_table[] = {
- { "MINDEX", 0xff, 0xff }
-};
-
-int
-ahd_ovlyrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYRXMSG2_parse_table, 1, "OVLYRXMSG2",
- 0x92, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DCHRXMSG3_parse_table[] = {
- { "MCLASS", 0x0f, 0x0f }
-};
-
-int
-ahd_dchrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DCHRXMSG3_parse_table, 1, "DCHRXMSG3",
- 0x93, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t OVLYRXMSG3_parse_table[] = {
- { "MCLASS", 0x0f, 0x0f }
-};
-
-int
-ahd_ovlyrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYRXMSG3_parse_table, 1, "OVLYRXMSG3",
- 0x93, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCRXMSG3_parse_table[] = {
- { "MCLASS", 0x0f, 0x0f }
-};
-
-int
-ahd_cmcrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCRXMSG3_parse_table, 1, "CMCRXMSG3",
- 0x93, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t PCIXCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t PCIXCTL_parse_table[] = {
{ "CMPABCDIS", 0x01, 0x01 },
{ "TSCSERREN", 0x02, 0x02 },
{ "SRSPDPEEN", 0x04, 0x04 },
@@ -2062,46 +1468,7 @@ ahd_pcixctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x93, regvalue, cur_col, wrap));
}
-int
-ahd_ovlyseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "OVLYSEQBCNT",
- 0x94, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dchseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DCHSEQBCNT",
- 0x94, regvalue, cur_col, wrap));
-}
-
-int
-ahd_cmcseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "CMCSEQBCNT",
- 0x94, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCSPLTSTAT0_parse_table[] = {
- { "RXSPLTRSP", 0x01, 0x01 },
- { "RXSCEMSG", 0x02, 0x02 },
- { "RXOVRUN", 0x04, 0x04 },
- { "CNTNOTCMPLT", 0x08, 0x08 },
- { "SCDATBUCKET", 0x10, 0x10 },
- { "SCADERR", 0x20, 0x20 },
- { "SCBCERR", 0x40, 0x40 },
- { "STAETERM", 0x80, 0x80 }
-};
-
-int
-ahd_cmcspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCSPLTSTAT0_parse_table, 8, "CMCSPLTSTAT0",
- 0x96, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
+static const ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
{ "RXSPLTRSP", 0x01, 0x01 },
{ "RXSCEMSG", 0x02, 0x02 },
{ "RXOVRUN", 0x04, 0x04 },
@@ -2119,47 +1486,7 @@ ahd_dchspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x96, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
- { "RXSPLTRSP", 0x01, 0x01 },
- { "RXSCEMSG", 0x02, 0x02 },
- { "RXOVRUN", 0x04, 0x04 },
- { "CNTNOTCMPLT", 0x08, 0x08 },
- { "SCDATBUCKET", 0x10, 0x10 },
- { "SCADERR", 0x20, 0x20 },
- { "SCBCERR", 0x40, 0x40 },
- { "STAETERM", 0x80, 0x80 }
-};
-
-int
-ahd_ovlyspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYSPLTSTAT0_parse_table, 8, "OVLYSPLTSTAT0",
- 0x96, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCSPLTSTAT1_parse_table[] = {
- { "RXDATABUCKET", 0x01, 0x01 }
-};
-
-int
-ahd_cmcspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCSPLTSTAT1_parse_table, 1, "CMCSPLTSTAT1",
- 0x97, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t OVLYSPLTSTAT1_parse_table[] = {
- { "RXDATABUCKET", 0x01, 0x01 }
-};
-
-int
-ahd_ovlyspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYSPLTSTAT1_parse_table, 1, "OVLYSPLTSTAT1",
- 0x97, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
+static const ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
{ "RXDATABUCKET", 0x01, 0x01 }
};
@@ -2170,139 +1497,7 @@ ahd_dchspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x97, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SGRXMSG0_parse_table[] = {
- { "CFNUM", 0x07, 0x07 },
- { "CDNUM", 0xf8, 0xf8 }
-};
-
-int
-ahd_sgrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SGRXMSG0_parse_table, 2, "SGRXMSG0",
- 0x98, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTADR0_parse_table[] = {
- { "LOWER_ADDR", 0x7f, 0x7f }
-};
-
-int
-ahd_slvspltoutadr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTADR0_parse_table, 1, "SLVSPLTOUTADR0",
- 0x98, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SGRXMSG1_parse_table[] = {
- { "CBNUM", 0xff, 0xff }
-};
-
-int
-ahd_sgrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SGRXMSG1_parse_table, 1, "SGRXMSG1",
- 0x99, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTADR1_parse_table[] = {
- { "REQ_FNUM", 0x07, 0x07 },
- { "REQ_DNUM", 0xf8, 0xf8 }
-};
-
-int
-ahd_slvspltoutadr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTADR1_parse_table, 2, "SLVSPLTOUTADR1",
- 0x99, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SGRXMSG2_parse_table[] = {
- { "MINDEX", 0xff, 0xff }
-};
-
-int
-ahd_sgrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SGRXMSG2_parse_table, 1, "SGRXMSG2",
- 0x9a, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTADR2_parse_table[] = {
- { "REQ_BNUM", 0xff, 0xff }
-};
-
-int
-ahd_slvspltoutadr2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTADR2_parse_table, 1, "SLVSPLTOUTADR2",
- 0x9a, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SGRXMSG3_parse_table[] = {
- { "MCLASS", 0x0f, 0x0f }
-};
-
-int
-ahd_sgrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SGRXMSG3_parse_table, 1, "SGRXMSG3",
- 0x9b, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTADR3_parse_table[] = {
- { "RLXORD", 0x10, 0x10 },
- { "TAG_NUM", 0x1f, 0x1f }
-};
-
-int
-ahd_slvspltoutadr3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTADR3_parse_table, 2, "SLVSPLTOUTADR3",
- 0x9b, regvalue, cur_col, wrap));
-}
-
-int
-ahd_sgseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SGSEQBCNT",
- 0x9c, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTATTR0_parse_table[] = {
- { "LOWER_BCNT", 0xff, 0xff }
-};
-
-int
-ahd_slvspltoutattr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTATTR0_parse_table, 1, "SLVSPLTOUTATTR0",
- 0x9c, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTATTR1_parse_table[] = {
- { "CMPLT_FNUM", 0x07, 0x07 },
- { "CMPLT_DNUM", 0xf8, 0xf8 }
-};
-
-int
-ahd_slvspltoutattr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTATTR1_parse_table, 2, "SLVSPLTOUTATTR1",
- 0x9d, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SLVSPLTOUTATTR2_parse_table[] = {
- { "CMPLT_BNUM", 0xff, 0xff }
-};
-
-int
-ahd_slvspltoutattr2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SLVSPLTOUTATTR2_parse_table, 1, "SLVSPLTOUTATTR2",
- 0x9e, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SGSPLTSTAT0_parse_table[] = {
+static const ahd_reg_parse_entry_t SGSPLTSTAT0_parse_table[] = {
{ "RXSPLTRSP", 0x01, 0x01 },
{ "RXSCEMSG", 0x02, 0x02 },
{ "RXOVRUN", 0x04, 0x04 },
@@ -2320,7 +1515,7 @@ ahd_sgspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x9e, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
+static const ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
{ "RXDATABUCKET", 0x01, 0x01 }
};
@@ -2331,19 +1526,7 @@ ahd_sgspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x9f, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SFUNCT_parse_table[] = {
- { "TEST_NUM", 0x0f, 0x0f },
- { "TEST_GROUP", 0xf0, 0xf0 }
-};
-
-int
-ahd_sfunct_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SFUNCT_parse_table, 2, "SFUNCT",
- 0x9f, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DF0PCISTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t DF0PCISTAT_parse_table[] = {
{ "DPR", 0x01, 0x01 },
{ "TWATERR", 0x02, 0x02 },
{ "RDPERR", 0x04, 0x04 },
@@ -2368,83 +1551,6 @@ ahd_reg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xa0, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DF1PCISTAT_parse_table[] = {
- { "DPR", 0x01, 0x01 },
- { "TWATERR", 0x02, 0x02 },
- { "RDPERR", 0x04, 0x04 },
- { "SCAAPERR", 0x08, 0x08 },
- { "RTA", 0x10, 0x10 },
- { "RMA", 0x20, 0x20 },
- { "SSE", 0x40, 0x40 },
- { "DPE", 0x80, 0x80 }
-};
-
-int
-ahd_df1pcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DF1PCISTAT_parse_table, 8, "DF1PCISTAT",
- 0xa1, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SGPCISTAT_parse_table[] = {
- { "DPR", 0x01, 0x01 },
- { "RDPERR", 0x04, 0x04 },
- { "SCAAPERR", 0x08, 0x08 },
- { "RTA", 0x10, 0x10 },
- { "RMA", 0x20, 0x20 },
- { "SSE", 0x40, 0x40 },
- { "DPE", 0x80, 0x80 }
-};
-
-int
-ahd_sgpcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SGPCISTAT_parse_table, 7, "SGPCISTAT",
- 0xa2, regvalue, cur_col, wrap));
-}
-
-int
-ahd_reg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "REG1",
- 0xa2, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CMCPCISTAT_parse_table[] = {
- { "DPR", 0x01, 0x01 },
- { "TWATERR", 0x02, 0x02 },
- { "RDPERR", 0x04, 0x04 },
- { "SCAAPERR", 0x08, 0x08 },
- { "RTA", 0x10, 0x10 },
- { "RMA", 0x20, 0x20 },
- { "SSE", 0x40, 0x40 },
- { "DPE", 0x80, 0x80 }
-};
-
-int
-ahd_cmcpcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMCPCISTAT_parse_table, 8, "CMCPCISTAT",
- 0xa3, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t OVLYPCISTAT_parse_table[] = {
- { "DPR", 0x01, 0x01 },
- { "RDPERR", 0x04, 0x04 },
- { "SCAAPERR", 0x08, 0x08 },
- { "RTA", 0x10, 0x10 },
- { "RMA", 0x20, 0x20 },
- { "SSE", 0x40, 0x40 },
- { "DPE", 0x80, 0x80 }
-};
-
-int
-ahd_ovlypcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(OVLYPCISTAT_parse_table, 7, "OVLYPCISTAT",
- 0xa4, regvalue, cur_col, wrap));
-}
-
int
ahd_reg_isr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -2452,7 +1558,7 @@ ahd_reg_isr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xa4, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SG_STATE_parse_table[] = {
+static const ahd_reg_parse_entry_t SG_STATE_parse_table[] = {
{ "SEGS_AVAIL", 0x01, 0x01 },
{ "LOADING_NEEDED", 0x02, 0x02 },
{ "FETCH_INPROG", 0x04, 0x04 }
@@ -2465,23 +1571,7 @@ ahd_sg_state_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xa6, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t MSIPCISTAT_parse_table[] = {
- { "DPR", 0x01, 0x01 },
- { "TWATERR", 0x02, 0x02 },
- { "CLRPENDMSI", 0x08, 0x08 },
- { "RTA", 0x10, 0x10 },
- { "RMA", 0x20, 0x20 },
- { "SSE", 0x40, 0x40 }
-};
-
-int
-ahd_msipcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(MSIPCISTAT_parse_table, 6, "MSIPCISTAT",
- 0xa6, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t TARGPCISTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t TARGPCISTAT_parse_table[] = {
{ "TWATERR", 0x02, 0x02 },
{ "STA", 0x08, 0x08 },
{ "SSE", 0x40, 0x40 },
@@ -2496,27 +1586,13 @@ ahd_targpcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_data_count_odd_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DATA_COUNT_ODD",
- 0xa7, regvalue, cur_col, wrap));
-}
-
-int
ahd_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "SCBPTR",
0xa8, regvalue, cur_col, wrap));
}
-int
-ahd_ccscbacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "CCSCBACNT",
- 0xab, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SCBAUTOPTR_parse_table[] = {
+static const ahd_reg_parse_entry_t SCBAUTOPTR_parse_table[] = {
{ "SCBPTR_OFF", 0x07, 0x07 },
{ "SCBPTR_ADDR", 0x38, 0x38 },
{ "AUSCBPTR_EN", 0x80, 0x80 }
@@ -2537,36 +1613,13 @@ ahd_ccsgaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_ccscbadr_bk_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "CCSCBADR_BK",
- 0xac, regvalue, cur_col, wrap));
-}
-
-int
ahd_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "CCSCBADDR",
0xac, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CMC_RAMBIST_parse_table[] = {
- { "CMC_BUFFER_BIST_EN", 0x01, 0x01 },
- { "CMC_BUFFER_BIST_FAIL",0x02, 0x02 },
- { "SG_BIST_EN", 0x10, 0x10 },
- { "SG_BIST_FAIL", 0x20, 0x20 },
- { "SCBRAMBIST_FAIL", 0x40, 0x40 },
- { "SG_ELEMENT_SIZE", 0x80, 0x80 }
-};
-
-int
-ahd_cmc_rambist_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(CMC_RAMBIST_parse_table, 6, "CMC_RAMBIST",
- 0xad, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t CCSCBCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t CCSCBCTL_parse_table[] = {
{ "CCSCBRESET", 0x01, 0x01 },
{ "CCSCBDIR", 0x04, 0x04 },
{ "CCSCBEN", 0x08, 0x08 },
@@ -2582,7 +1635,7 @@ ahd_ccscbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xad, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
{ "CCSGRESET", 0x01, 0x01 },
{ "SG_FETCH_REQ", 0x02, 0x02 },
{ "CCSGENACK", 0x08, 0x08 },
@@ -2606,13 +1659,6 @@ ahd_ccsgram_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_flexadr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "FLEXADR",
- 0xb0, regvalue, cur_col, wrap));
-}
-
-int
ahd_ccscbram_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "CCSCBRAM",
@@ -2620,39 +1666,13 @@ ahd_ccscbram_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_flexcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "FLEXCNT",
- 0xb3, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t FLEXDMASTAT_parse_table[] = {
- { "FLEXDMADONE", 0x01, 0x01 },
- { "FLEXDMAERR", 0x02, 0x02 }
-};
-
-int
-ahd_flexdmastat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(FLEXDMASTAT_parse_table, 2, "FLEXDMASTAT",
- 0xb5, regvalue, cur_col, wrap));
-}
-
-int
-ahd_flexdata_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "FLEXDATA",
- 0xb6, regvalue, cur_col, wrap));
-}
-
-int
ahd_brddat_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "BRDDAT",
0xb8, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t BRDCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t BRDCTL_parse_table[] = {
{ "BRDSTB", 0x01, 0x01 },
{ "BRDRW", 0x02, 0x02 },
{ "BRDEN", 0x04, 0x04 },
@@ -2682,7 +1702,7 @@ ahd_seedat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xbc, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEECTL_parse_table[] = {
+static const ahd_reg_parse_entry_t SEECTL_parse_table[] = {
{ "SEEOP_ERAL", 0x40, 0x70 },
{ "SEEOP_WRITE", 0x50, 0x70 },
{ "SEEOP_READ", 0x60, 0x70 },
@@ -2702,7 +1722,7 @@ ahd_seectl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xbe, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEESTAT_parse_table[] = {
+static const ahd_reg_parse_entry_t SEESTAT_parse_table[] = {
{ "SEESTART", 0x01, 0x01 },
{ "SEEBUSY", 0x02, 0x02 },
{ "SEEARBACK", 0x04, 0x04 },
@@ -2718,34 +1738,7 @@ ahd_seestat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xbe, regvalue, cur_col, wrap));
}
-int
-ahd_scbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SCBCNT",
- 0xbf, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dfwaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFWADDR",
- 0xc0, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DSPFLTRCTL_parse_table[] = {
- { "DSPFCNTSEL", 0x0f, 0x0f },
- { "EDGESENSE", 0x10, 0x10 },
- { "FLTRDISABLE", 0x20, 0x20 }
-};
-
-int
-ahd_dspfltrctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DSPFLTRCTL_parse_table, 3, "DSPFLTRCTL",
- 0xc0, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DSPDATACTL_parse_table[] = {
+static const ahd_reg_parse_entry_t DSPDATACTL_parse_table[] = {
{ "XMITOFFSTDIS", 0x02, 0x02 },
{ "RCVROFFSTDIS", 0x04, 0x04 },
{ "DESQDIS", 0x10, 0x10 },
@@ -2760,44 +1753,13 @@ ahd_dspdatactl_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_dfraddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFRADDR",
- 0xc2, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DSPREQCTL_parse_table[] = {
- { "MANREQDLY", 0x3f, 0x3f },
- { "MANREQCTL", 0xc0, 0xc0 }
-};
-
-int
-ahd_dspreqctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DSPREQCTL_parse_table, 2, "DSPREQCTL",
- 0xc2, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DSPACKCTL_parse_table[] = {
- { "MANACKDLY", 0x3f, 0x3f },
- { "MANACKCTL", 0xc0, 0xc0 }
-};
-
-int
-ahd_dspackctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DSPACKCTL_parse_table, 2, "DSPACKCTL",
- 0xc3, regvalue, cur_col, wrap));
-}
-
-int
ahd_dfdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "DFDAT",
0xc4, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DSPSELECT_parse_table[] = {
+static const ahd_reg_parse_entry_t DSPSELECT_parse_table[] = {
{ "DSPSEL", 0x1f, 0x1f },
{ "AUTOINCEN", 0x80, 0x80 }
};
@@ -2809,7 +1771,7 @@ ahd_dspselect_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xc4, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t WRTBIASCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t WRTBIASCTL_parse_table[] = {
{ "XMITMANVAL", 0x3f, 0x3f },
{ "AUTOXBCDIS", 0x80, 0x80 }
};
@@ -2821,91 +1783,7 @@ ahd_wrtbiasctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xc5, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t RCVRBIOSCTL_parse_table[] = {
- { "RCVRMANVAL", 0x3f, 0x3f },
- { "AUTORBCDIS", 0x80, 0x80 }
-};
-
-int
-ahd_rcvrbiosctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(RCVRBIOSCTL_parse_table, 2, "RCVRBIOSCTL",
- 0xc6, regvalue, cur_col, wrap));
-}
-
-int
-ahd_wrtbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "WRTBIASCALC",
- 0xc7, regvalue, cur_col, wrap));
-}
-
-int
-ahd_rcvrbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "RCVRBIASCALC",
- 0xc8, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dfptrs_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFPTRS",
- 0xc8, regvalue, cur_col, wrap));
-}
-
-int
-ahd_skewcalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SKEWCALC",
- 0xc9, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dfbkptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFBKPTR",
- 0xc9, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t DFDBCTL_parse_table[] = {
- { "DFF_RAMBIST_EN", 0x01, 0x01 },
- { "DFF_RAMBIST_DONE", 0x02, 0x02 },
- { "DFF_RAMBIST_FAIL", 0x04, 0x04 },
- { "DFF_DIR_ERR", 0x08, 0x08 },
- { "DFF_CIO_RD_RDY", 0x10, 0x10 },
- { "DFF_CIO_WR_RDY", 0x20, 0x20 }
-};
-
-int
-ahd_dfdbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(DFDBCTL_parse_table, 6, "DFDBCTL",
- 0xcb, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dfscnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFSCNT",
- 0xcc, regvalue, cur_col, wrap));
-}
-
-int
-ahd_dfbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "DFBCNT",
- 0xce, regvalue, cur_col, wrap));
-}
-
-int
-ahd_ovlyaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "OVLYADDR",
- 0xd4, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SEQCTL0_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQCTL0_parse_table[] = {
{ "LOADRAM", 0x01, 0x01 },
{ "SEQRESET", 0x02, 0x02 },
{ "STEP", 0x04, 0x04 },
@@ -2923,21 +1801,7 @@ ahd_seqctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xd6, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQCTL1_parse_table[] = {
- { "RAMBIST_EN", 0x01, 0x01 },
- { "RAMBIST_FAIL", 0x02, 0x02 },
- { "RAMBIST_DONE", 0x04, 0x04 },
- { "OVRLAY_DATA_CHK", 0x08, 0x08 }
-};
-
-int
-ahd_seqctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(SEQCTL1_parse_table, 4, "SEQCTL1",
- 0xd7, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t FLAGS_parse_table[] = {
+static const ahd_reg_parse_entry_t FLAGS_parse_table[] = {
{ "CARRY", 0x01, 0x01 },
{ "ZERO", 0x02, 0x02 }
};
@@ -2949,7 +1813,7 @@ ahd_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xd8, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQINTCTL_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQINTCTL_parse_table[] = {
{ "IRET", 0x01, 0x01 },
{ "INTMASK1", 0x02, 0x02 },
{ "INTMASK2", 0x04, 0x04 },
@@ -3002,24 +1866,6 @@ ahd_dindex_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_brkaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "BRKADDR0",
- 0xe6, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t BRKADDR1_parse_table[] = {
- { "BRKDIS", 0x80, 0x80 }
-};
-
-int
-ahd_brkaddr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(BRKADDR1_parse_table, 1, "BRKADDR1",
- 0xe6, regvalue, cur_col, wrap));
-}
-
-int
ahd_allones_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "ALLONES",
@@ -3055,13 +1901,6 @@ ahd_dindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_function1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "FUNCTION1",
- 0xf0, regvalue, cur_col, wrap));
-}
-
-int
ahd_stack_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "STACK",
@@ -3083,13 +1922,6 @@ ahd_curaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_lastaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "LASTADDR",
- 0xf6, regvalue, cur_col, wrap));
-}
-
-int
ahd_intvec2_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "INTVEC2_ADDR",
@@ -3111,23 +1943,16 @@ ahd_accum_save_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_waiting_scb_tails_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "WAITING_SCB_TAILS",
- 0x100, regvalue, cur_col, wrap));
-}
-
-int
-ahd_ahd_pci_config_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(NULL, 0, "AHD_PCI_CONFIG_BASE",
+ return (ahd_print_register(NULL, 0, "SRAM_BASE",
0x100, regvalue, cur_col, wrap));
}
int
-ahd_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_waiting_scb_tails_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(NULL, 0, "SRAM_BASE",
+ return (ahd_print_register(NULL, 0, "WAITING_SCB_TAILS",
0x100, regvalue, cur_col, wrap));
}
@@ -3215,7 +2040,7 @@ ahd_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x137, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t DMAPARAMS_parse_table[] = {
+static const ahd_reg_parse_entry_t DMAPARAMS_parse_table[] = {
{ "FIFORESET", 0x01, 0x01 },
{ "FIFOFLUSH", 0x02, 0x02 },
{ "DIRECTION", 0x04, 0x04 },
@@ -3235,7 +2060,7 @@ ahd_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x138, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
{ "NO_DISCONNECT", 0x01, 0x01 },
{ "SPHASE_PENDING", 0x02, 0x02 },
{ "DPHASE_PENDING", 0x04, 0x04 },
@@ -3268,7 +2093,7 @@ ahd_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x13b, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t LASTPHASE_parse_table[] = {
+static const ahd_reg_parse_entry_t LASTPHASE_parse_table[] = {
{ "P_DATAOUT", 0x00, 0xe0 },
{ "P_DATAOUT_DT", 0x20, 0xe0 },
{ "P_DATAIN", 0x40, 0xe0 },
@@ -3326,7 +2151,7 @@ ahd_qoutfifo_next_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x144, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t ARG_1_parse_table[] = {
+static const ahd_reg_parse_entry_t ARG_1_parse_table[] = {
{ "CONT_MSG_LOOP_TARG", 0x02, 0x02 },
{ "CONT_MSG_LOOP_READ", 0x03, 0x03 },
{ "CONT_MSG_LOOP_WRITE",0x04, 0x04 },
@@ -3358,7 +2183,7 @@ ahd_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x14a, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
+static const ahd_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
{ "ALTSTIM", 0x01, 0x01 },
{ "ENAUTOATNP", 0x02, 0x02 },
{ "MANUALP", 0x0c, 0x0c },
@@ -3381,7 +2206,7 @@ ahd_initiator_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x14c, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
+static const ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
{ "PENDING_MK_MESSAGE", 0x01, 0x01 },
{ "TARGET_MSG_PENDING", 0x02, 0x02 },
{ "SELECTOUT_QFROZEN", 0x04, 0x04 }
@@ -3465,20 +2290,20 @@ ahd_mk_message_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_scb_residual_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(NULL, 0, "SCB_BASE",
+ return (ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT",
0x180, regvalue, cur_col, wrap));
}
int
-ahd_scb_residual_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
- return (ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT",
+ return (ahd_print_register(NULL, 0, "SCB_BASE",
0x180, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_RESIDUAL_SGPTR_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_RESIDUAL_SGPTR_parse_table[] = {
{ "SG_LIST_NULL", 0x01, 0x01 },
{ "SG_OVERRUN_RESID", 0x02, 0x02 },
{ "SG_ADDR_MASK", 0xf8, 0xf8 }
@@ -3499,27 +2324,6 @@ ahd_scb_scsi_status_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_scb_target_phases_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SCB_TARGET_PHASES",
- 0x189, regvalue, cur_col, wrap));
-}
-
-int
-ahd_scb_target_data_dir_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SCB_TARGET_DATA_DIR",
- 0x18a, regvalue, cur_col, wrap));
-}
-
-int
-ahd_scb_target_itag_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SCB_TARGET_ITAG",
- 0x18b, regvalue, cur_col, wrap));
-}
-
-int
ahd_scb_sense_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "SCB_SENSE_BUSADDR",
@@ -3533,7 +2337,7 @@ ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x190, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
{ "SCB_TAG_TYPE", 0x03, 0x03 },
{ "DISCONNECTED", 0x04, 0x04 },
{ "STATUS_RCVD", 0x08, 0x08 },
@@ -3550,7 +2354,7 @@ ahd_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x192, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
{ "OID", 0x0f, 0x0f },
{ "TID", 0xf0, 0xf0 }
};
@@ -3562,7 +2366,7 @@ ahd_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x193, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_LUN_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_LUN_parse_table[] = {
{ "LID", 0xff, 0xff }
};
@@ -3573,7 +2377,7 @@ ahd_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x194, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_TASK_ATTRIBUTE_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_TASK_ATTRIBUTE_parse_table[] = {
{ "SCB_XFERLEN_ODD", 0x01, 0x01 }
};
@@ -3584,7 +2388,7 @@ ahd_scb_task_attribute_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x195, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = {
{ "SCB_CDB_LEN_PTR", 0x80, 0x80 }
};
@@ -3609,7 +2413,7 @@ ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x198, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
{ "SG_HIGH_ADDR_BITS", 0x7f, 0x7f },
{ "SG_LAST_SEG", 0x80, 0x80 }
};
@@ -3621,7 +2425,7 @@ ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1a0, regvalue, cur_col, wrap));
}
-static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
+static const ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
{ "SG_LIST_NULL", 0x01, 0x01 },
{ "SG_FULL_RESID", 0x02, 0x02 },
{ "SG_STATUS_VALID", 0x04, 0x04 }
@@ -3656,13 +2460,6 @@ ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahd_scb_spare_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahd_print_register(NULL, 0, "SCB_SPARE",
- 0x1b0, regvalue, cur_col, wrap));
-}
-
-int
ahd_scb_disconnected_lists_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(NULL, 0, "SCB_DISCONNECTED_LISTS",
diff --git a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
index 11bed07e90b7..4b51e232392f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
@@ -5,7 +5,7 @@
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $
*/
-static uint8_t seqprog[] = {
+static const uint8_t seqprog[] = {
0xff, 0x02, 0x06, 0x78,
0x00, 0xea, 0x6e, 0x59,
0x01, 0xea, 0x04, 0x30,
@@ -1027,7 +1027,7 @@ ahd_patch0_func(struct ahd_softc *ahd)
return (0);
}
-static struct patch {
+static const struct patch {
ahd_patch_func_t *patch_func;
uint32_t begin :10,
skip_instr :10,
@@ -1166,7 +1166,7 @@ static struct patch {
{ ahd_patch23_func, 815, 11, 1 }
};
-static struct cs {
+static const struct cs {
uint16_t begin;
uint16_t end;
} critical_sections[] = {
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index c0344e617651..e4e651cca3e4 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -736,7 +736,7 @@ struct ahc_syncrate {
#define ST_SXFR 0x010 /* Rate Single Transition Only */
#define DT_SXFR 0x040 /* Rate Double Transition Only */
uint8_t period; /* Period to send to SCSI target */
- char *rate;
+ const char *rate;
};
/* Safe and valid period for async negotiations. */
@@ -1114,7 +1114,7 @@ typedef int (ahc_device_setup_t)(struct ahc_softc *);
struct ahc_pci_identity {
uint64_t full_id;
uint64_t id_mask;
- char *name;
+ const char *name;
ahc_device_setup_t *setup;
};
@@ -1133,15 +1133,11 @@ extern const int ahc_num_aic7770_devs;
/*************************** Function Declarations ****************************/
/******************************************************************************/
-u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
-void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
-void ahc_busy_tcl(struct ahc_softc *ahc,
- u_int tcl, u_int busyid);
/***************************** PCI Front End *********************************/
-struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
+const struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *,
- struct ahc_pci_identity *);
+ const struct ahc_pci_identity *);
int ahc_pci_test_register_access(struct ahc_softc *);
#ifdef CONFIG_PM
void ahc_pci_resume(struct ahc_softc *ahc);
@@ -1155,9 +1151,6 @@ int aic7770_config(struct ahc_softc *ahc,
/************************** SCB and SCB queue management **********************/
int ahc_probe_scbs(struct ahc_softc *);
-void ahc_run_untagged_queues(struct ahc_softc *ahc);
-void ahc_run_untagged_queue(struct ahc_softc *ahc,
- struct scb_tailq *queue);
void ahc_qinfifo_requeue_tail(struct ahc_softc *ahc,
struct scb *scb);
int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
@@ -1178,22 +1171,8 @@ int ahc_resume(struct ahc_softc *ahc);
#endif
void ahc_set_unit(struct ahc_softc *, int);
void ahc_set_name(struct ahc_softc *, char *);
-void ahc_alloc_scbs(struct ahc_softc *ahc);
void ahc_free(struct ahc_softc *ahc);
int ahc_reset(struct ahc_softc *ahc, int reinit);
-void ahc_shutdown(void *arg);
-
-/*************************** Interrupt Services *******************************/
-void ahc_clear_intstat(struct ahc_softc *ahc);
-void ahc_run_qoutfifo(struct ahc_softc *ahc);
-#ifdef AHC_TARGET_MODE
-void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
-#endif
-void ahc_handle_brkadrint(struct ahc_softc *ahc);
-void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
-void ahc_handle_scsiint(struct ahc_softc *ahc,
- u_int intstat);
-void ahc_clear_critical_section(struct ahc_softc *ahc);
/***************************** Error Recovery *********************************/
typedef enum {
@@ -1214,36 +1193,19 @@ int ahc_search_disc_list(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
int stop_on_first, int remove,
int save_state);
-void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
int ahc_reset_channel(struct ahc_softc *ahc, char channel,
int initiate_reset);
-int ahc_abort_scbs(struct ahc_softc *ahc, int target,
- char channel, int lun, u_int tag,
- role_t role, uint32_t status);
-void ahc_restart(struct ahc_softc *ahc);
-void ahc_calc_residual(struct ahc_softc *ahc,
- struct scb *scb);
+
/*************************** Utility Functions ********************************/
-struct ahc_phase_table_entry*
- ahc_lookup_phase_entry(int phase);
void ahc_compile_devinfo(struct ahc_devinfo *devinfo,
u_int our_id, u_int target,
u_int lun, char channel,
role_t role);
/************************** Transfer Negotiation ******************************/
-struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
+const struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
u_int *ppr_options, u_int maxsync);
u_int ahc_find_period(struct ahc_softc *ahc,
u_int scsirate, u_int maxsync);
-void ahc_validate_offset(struct ahc_softc *ahc,
- struct ahc_initiator_tinfo *tinfo,
- struct ahc_syncrate *syncrate,
- u_int *offset, int wide,
- role_t role);
-void ahc_validate_width(struct ahc_softc *ahc,
- struct ahc_initiator_tinfo *tinfo,
- u_int *bus_width,
- role_t role);
/*
* Negotiation types. These are used to qualify if we should renegotiate
* even if our goal and current transport parameters are identical.
@@ -1263,7 +1225,7 @@ void ahc_set_width(struct ahc_softc *ahc,
u_int width, u_int type, int paused);
void ahc_set_syncrate(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
- struct ahc_syncrate *syncrate,
+ const struct ahc_syncrate *syncrate,
u_int period, u_int offset,
u_int ppr_options,
u_int type, int paused);
@@ -1305,11 +1267,10 @@ extern uint32_t ahc_debug;
#define AHC_SHOW_MASKED_ERRORS 0x1000
#define AHC_DEBUG_SEQUENCER 0x2000
#endif
-void ahc_print_scb(struct scb *scb);
void ahc_print_devinfo(struct ahc_softc *ahc,
struct ahc_devinfo *dev);
void ahc_dump_card_state(struct ahc_softc *ahc);
-int ahc_print_register(ahc_reg_parse_entry_t *table,
+int ahc_print_register(const ahc_reg_parse_entry_t *table,
u_int num_entries,
const char *name,
u_int address,
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index e196d83b93c7..0d2f763c3427 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -238,6 +238,7 @@ register SXFRCTL2 {
register OPTIONMODE {
address 0x008
access_mode RW
+ count 2
field AUTORATEEN 0x80
field AUTOACKEN 0x40
field ATNMGMNTEN 0x20
@@ -254,6 +255,7 @@ register TARGCRCCNT {
address 0x00a
size 2
access_mode RW
+ count 2
}
/*
@@ -344,6 +346,7 @@ register SSTAT2 {
register SSTAT3 {
address 0x00e
access_mode RO
+ count 2
mask SCSICNT 0xf0
mask OFFCNT 0x0f
mask U2OFFCNT 0x7f
@@ -367,6 +370,7 @@ register SCSIID_ULTRA2 {
register SIMODE0 {
address 0x010
access_mode RW
+ count 2
field ENSELDO 0x40
field ENSELDI 0x20
field ENSELINGO 0x10
@@ -429,6 +433,7 @@ register SHADDR {
register SELTIMER {
address 0x018
access_mode RW
+ count 1
field STAGE6 0x20
field STAGE5 0x10
field STAGE4 0x08
@@ -467,6 +472,7 @@ register TARGID {
address 0x01b
size 2
access_mode RW
+ count 14
}
/*
@@ -480,6 +486,7 @@ register TARGID {
register SPIOCAP {
address 0x01b
access_mode RW
+ count 10
field SOFT1 0x80
field SOFT0 0x40
field SOFTCMDEN 0x20
@@ -492,6 +499,7 @@ register SPIOCAP {
register BRDCTL {
address 0x01d
+ count 11
field BRDDAT7 0x80
field BRDDAT6 0x40
field BRDDAT5 0x20
@@ -534,6 +542,7 @@ register BRDCTL {
*/
register SEECTL {
address 0x01e
+ count 11
field EXTARBACK 0x80
field EXTARBREQ 0x40
field SEEMS 0x20
@@ -570,6 +579,7 @@ register SBLKCTL {
register SEQCTL {
address 0x060
access_mode RW
+ count 15
field PERRORDIS 0x80
field PAUSEDIS 0x40
field FAILDIS 0x20
@@ -590,6 +600,7 @@ register SEQCTL {
register SEQRAM {
address 0x061
access_mode RW
+ count 2
}
/*
@@ -604,6 +615,7 @@ register SEQADDR0 {
register SEQADDR1 {
address 0x063
access_mode RW
+ count 8
mask SEQADDR1_MASK 0x01
}
@@ -649,6 +661,7 @@ register NONE {
register FLAGS {
address 0x06b
access_mode RO
+ count 18
field ZERO 0x02
field CARRY 0x01
}
@@ -671,6 +684,7 @@ register FUNCTION1 {
register STACK {
address 0x06f
access_mode RO
+ count 5
}
const STACK_SIZE 4
@@ -692,6 +706,7 @@ register BCTL {
register DSCOMMAND0 {
address 0x084
access_mode RW
+ count 7
field CACHETHEN 0x80 /* Cache Threshold enable */
field DPARCKEN 0x40 /* Data Parity Check Enable */
field MPARCKEN 0x20 /* Memory Parity Check Enable */
@@ -717,6 +732,7 @@ register DSCOMMAND1 {
register BUSTIME {
address 0x085
access_mode RW
+ count 2
mask BOFF 0xf0
mask BON 0x0f
}
@@ -727,6 +743,7 @@ register BUSTIME {
register BUSSPD {
address 0x086
access_mode RW
+ count 2
mask DFTHRSH 0xc0
mask STBOFF 0x38
mask STBON 0x07
@@ -737,6 +754,7 @@ register BUSSPD {
/* aic7850/55/60/70/80/95 only */
register DSPCISTATUS {
address 0x086
+ count 4
mask DFTHRSH_100 0xc0
}
@@ -758,6 +776,7 @@ const SEQ_MAILBOX_SHIFT 0
register HCNTRL {
address 0x087
access_mode RW
+ count 14
field POWRDN 0x40
field SWINT 0x10
field IRQMS 0x08
@@ -869,6 +888,7 @@ register INTSTAT {
register ERROR {
address 0x092
access_mode RO
+ count 26
field CIOPARERR 0x80 /* Ultra2 only */
field PCIERRSTAT 0x40 /* PCI only */
field MPARERR 0x20 /* PCI only */
@@ -885,6 +905,7 @@ register ERROR {
register CLRINT {
address 0x092
access_mode WO
+ count 24
field CLRPARERR 0x10 /* PCI only */
field CLRBRKADRINT 0x08
field CLRSCSIINT 0x04
@@ -943,6 +964,7 @@ register DFDAT {
register SCBCNT {
address 0x09a
access_mode RW
+ count 1
field SCBAUTO 0x80
mask SCBCNT_MASK 0x1f
}
@@ -954,6 +976,7 @@ register SCBCNT {
register QINFIFO {
address 0x09b
access_mode RW
+ count 12
}
/*
@@ -972,11 +995,13 @@ register QINCNT {
register QOUTFIFO {
address 0x09d
access_mode WO
+ count 7
}
register CRCCONTROL1 {
address 0x09d
access_mode RW
+ count 3
field CRCONSEEN 0x80
field CRCVALCHKEN 0x40
field CRCENDCHKEN 0x20
@@ -1013,6 +1038,7 @@ register SCSIPHASE {
register SFUNCT {
address 0x09f
access_mode RW
+ count 4
field ALT_MODE 0x80
}
@@ -1095,6 +1121,7 @@ scb {
}
SCB_SCSIOFFSET {
size 1
+ count 1
}
SCB_NEXT {
size 1
@@ -1118,6 +1145,7 @@ const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
register SEECTL_2840 {
address 0x0c0
access_mode RW
+ count 2
field CS_2840 0x04
field CK_2840 0x02
field DO_2840 0x01
@@ -1126,6 +1154,7 @@ register SEECTL_2840 {
register STATUS_2840 {
address 0x0c1
access_mode RW
+ count 4
field EEPROM_TF 0x80
mask BIOS_SEL 0x60
mask ADSEL 0x1e
@@ -1161,6 +1190,7 @@ register CCSGCTL {
register CCSCBCNT {
address 0xEF
+ count 1
}
register CCSCBCTL {
@@ -1187,6 +1217,7 @@ register CCSCBRAM {
register SCBBADDR {
address 0x0F0
access_mode RW
+ count 3
}
register CCSCBPTR {
@@ -1195,6 +1226,7 @@ register CCSCBPTR {
register HNSCB_QOFF {
address 0x0F4
+ count 4
}
register SNSCB_QOFF {
@@ -1234,6 +1266,7 @@ register DFF_THRSH {
mask WR_DFTHRSH_85 0x50
mask WR_DFTHRSH_90 0x60
mask WR_DFTHRSH_MAX 0x70
+ count 4
}
register SG_CACHE_PRE {
@@ -1287,6 +1320,7 @@ scratch_ram {
ULTRA_ENB {
alias CMDSIZE_TABLE
size 2
+ count 2
}
/*
* Bit vector of targets that have disconnection disabled as set by
@@ -1296,6 +1330,7 @@ scratch_ram {
*/
DISC_DSB {
size 2
+ count 6
}
CMDSIZE_TABLE_TAIL {
size 4
@@ -1323,6 +1358,7 @@ scratch_ram {
/* Parameters for DMA Logic */
DMAPARAMS {
size 1
+ count 12
field PRELOADEN 0x80
field WIDEODD 0x40
field SCSIEN 0x20
@@ -1436,11 +1472,12 @@ scratch_ram {
KERNEL_TQINPOS {
size 1
}
- TQINPOS {
+ TQINPOS {
size 1
}
ARG_1 {
size 1
+ count 1
mask SEND_MSG 0x80
mask SEND_SENSE 0x40
mask SEND_REJ 0x20
@@ -1495,6 +1532,7 @@ scratch_ram {
size 1
field HA_274_EXTENDED_TRANS 0x01
alias INITIATOR_TAG
+ count 1
}
SEQ_FLAGS2 {
@@ -1518,6 +1556,7 @@ scratch_ram {
*/
SCSICONF {
size 1
+ count 12
field TERM_ENB 0x80
field RESET_SCSI 0x40
field ENSPCHK 0x20
@@ -1527,16 +1566,19 @@ scratch_ram {
INTDEF {
address 0x05c
size 1
+ count 1
field EDGE_TRIG 0x80
mask VECTOR 0x0f
}
HOSTCONF {
address 0x05d
size 1
+ count 1
}
HA_274_BIOSCTRL {
address 0x05f
size 1
+ count 1
mask BIOSMODE 0x30
mask BIOSDISABLED 0x30
field CHANNEL_B_PRIMARY 0x08
@@ -1552,6 +1594,7 @@ scratch_ram {
*/
TARG_OFFSET {
size 16
+ count 1
}
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
index 3cb07e114e89..dd11999b77b6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
@@ -84,16 +84,16 @@ struct seeprom_cmd {
};
/* Short opcodes for the c46 */
-static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
-static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+static const struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
+static const struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
/* Long opcodes for the C56/C66 */
-static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
-static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+static const struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
+static const struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
/* Common opcodes */
-static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
-static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+static const struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
+static const struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
/*
* Wait for the SEERDY to go high; about 800 ns.
@@ -108,7 +108,7 @@ static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
* Send a START condition and the given command
*/
static void
-send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd)
+send_seeprom_cmd(struct seeprom_descriptor *sd, const struct seeprom_cmd *cmd)
{
uint8_t temp;
int i = 0;
@@ -227,7 +227,7 @@ int
ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
u_int start_addr, u_int count)
{
- struct seeprom_cmd *ewen, *ewds;
+ const struct seeprom_cmd *ewen, *ewds;
uint16_t v;
uint8_t temp;
int i, k;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 64e62ce59c15..0ae2b4605d09 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -51,8 +51,7 @@
#endif
/***************************** Lookup Tables **********************************/
-char *ahc_chip_names[] =
-{
+static const char *const ahc_chip_names[] = {
"NONE",
"aic7770",
"aic7850",
@@ -75,10 +74,10 @@ static const u_int num_chip_names = ARRAY_SIZE(ahc_chip_names);
*/
struct ahc_hard_error_entry {
uint8_t errno;
- char *errmesg;
+ const char *errmesg;
};
-static struct ahc_hard_error_entry ahc_hard_errors[] = {
+static const struct ahc_hard_error_entry ahc_hard_errors[] = {
{ ILLHADDR, "Illegal Host Access" },
{ ILLSADDR, "Illegal Sequencer Address referrenced" },
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
@@ -90,7 +89,7 @@ static struct ahc_hard_error_entry ahc_hard_errors[] = {
};
static const u_int num_errors = ARRAY_SIZE(ahc_hard_errors);
-static struct ahc_phase_table_entry ahc_phase_table[] =
+static const struct ahc_phase_table_entry ahc_phase_table[] =
{
{ P_DATAOUT, MSG_NOOP, "in Data-out phase" },
{ P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" },
@@ -115,7 +114,7 @@ static const u_int num_phases = ARRAY_SIZE(ahc_phase_table) - 1;
* Provides a mapping of tranfer periods in ns to the proper value to
* stick in the scsixfer reg.
*/
-static struct ahc_syncrate ahc_syncrates[] =
+static const struct ahc_syncrate ahc_syncrates[] =
{
/* ultra2 fast/ultra period rate */
{ 0x42, 0x000, 9, "80.0" },
@@ -148,7 +147,7 @@ static struct ahc_tmode_tstate*
static void ahc_free_tstate(struct ahc_softc *ahc,
u_int scsi_id, char channel, int force);
#endif
-static struct ahc_syncrate*
+static const struct ahc_syncrate*
ahc_devlimited_syncrate(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *,
u_int *period,
@@ -204,9 +203,9 @@ static void ahc_setup_target_msgin(struct ahc_softc *ahc,
#endif
static bus_dmamap_callback_t ahc_dmamap_cb;
-static void ahc_build_free_scb_list(struct ahc_softc *ahc);
-static int ahc_init_scbdata(struct ahc_softc *ahc);
-static void ahc_fini_scbdata(struct ahc_softc *ahc);
+static void ahc_build_free_scb_list(struct ahc_softc *ahc);
+static int ahc_init_scbdata(struct ahc_softc *ahc);
+static void ahc_fini_scbdata(struct ahc_softc *ahc);
static void ahc_qinfifo_requeue(struct ahc_softc *ahc,
struct scb *prev_scb,
struct scb *scb);
@@ -222,7 +221,7 @@ static void ahc_dumpseq(struct ahc_softc *ahc);
#endif
static int ahc_loadseq(struct ahc_softc *ahc);
static int ahc_check_patch(struct ahc_softc *ahc,
- struct patch **start_patch,
+ const struct patch **start_patch,
u_int start_instr, u_int *skip_addr);
static void ahc_download_instr(struct ahc_softc *ahc,
u_int instrptr, uint8_t *dconsts);
@@ -237,11 +236,582 @@ static void ahc_update_scsiid(struct ahc_softc *ahc,
static int ahc_handle_target_cmd(struct ahc_softc *ahc,
struct target_cmd *cmd);
#endif
+
+static u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
+static void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
+static void ahc_busy_tcl(struct ahc_softc *ahc,
+ u_int tcl, u_int busyid);
+
+/************************** SCB and SCB queue management **********************/
+static void ahc_run_untagged_queues(struct ahc_softc *ahc);
+static void ahc_run_untagged_queue(struct ahc_softc *ahc,
+ struct scb_tailq *queue);
+
+/****************************** Initialization ********************************/
+static void ahc_alloc_scbs(struct ahc_softc *ahc);
+static void ahc_shutdown(void *arg);
+
+/*************************** Interrupt Services *******************************/
+static void ahc_clear_intstat(struct ahc_softc *ahc);
+static void ahc_run_qoutfifo(struct ahc_softc *ahc);
+#ifdef AHC_TARGET_MODE
+static void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
+#endif
+static void ahc_handle_brkadrint(struct ahc_softc *ahc);
+static void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
+static void ahc_handle_scsiint(struct ahc_softc *ahc,
+ u_int intstat);
+static void ahc_clear_critical_section(struct ahc_softc *ahc);
+
+/***************************** Error Recovery *********************************/
+static void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
+static int ahc_abort_scbs(struct ahc_softc *ahc, int target,
+ char channel, int lun, u_int tag,
+ role_t role, uint32_t status);
+static void ahc_calc_residual(struct ahc_softc *ahc,
+ struct scb *scb);
+
+/*********************** Untagged Transaction Routines ************************/
+static inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
+static inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
+
+/*
+ * Block our completion routine from starting the next untagged
+ * transaction for this target or target lun.
+ */
+static inline void
+ahc_freeze_untagged_queues(struct ahc_softc *ahc)
+{
+ if ((ahc->flags & AHC_SCB_BTT) == 0)
+ ahc->untagged_queue_lock++;
+}
+
+/*
+ * Allow the next untagged transaction for this target or target lun
+ * to be executed. We use a counting semaphore to allow the lock
+ * to be acquired recursively. Once the count drops to zero, the
+ * transaction queues will be run.
+ */
+static inline void
+ahc_release_untagged_queues(struct ahc_softc *ahc)
+{
+ if ((ahc->flags & AHC_SCB_BTT) == 0) {
+ ahc->untagged_queue_lock--;
+ if (ahc->untagged_queue_lock == 0)
+ ahc_run_untagged_queues(ahc);
+ }
+}
+
/************************* Sequencer Execution Control ************************/
/*
- * Restart the sequencer program from address zero
+ * Work around any chip bugs related to halting sequencer execution.
+ * On Ultra2 controllers, we must clear the CIOBUS stretch signal by
+ * reading a register that will set this signal and deassert it.
+ * Without this workaround, if the chip is paused, by an interrupt or
+ * manual pause while accessing scb ram, accesses to certain registers
+ * will hang the system (infinite pci retries).
+ */
+static void
+ahc_pause_bug_fix(struct ahc_softc *ahc)
+{
+ if ((ahc->features & AHC_ULTRA2) != 0)
+ (void)ahc_inb(ahc, CCSCBCTL);
+}
+
+/*
+ * Determine whether the sequencer has halted code execution.
+ * Returns non-zero status if the sequencer is stopped.
+ */
+int
+ahc_is_paused(struct ahc_softc *ahc)
+{
+ return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
+}
+
+/*
+ * Request that the sequencer stop and wait, indefinitely, for it
+ * to stop. The sequencer will only acknowledge that it is paused
+ * once it has reached an instruction boundary and PAUSEDIS is
+ * cleared in the SEQCTL register. The sequencer may use PAUSEDIS
+ * for critical sections.
+ */
+void
+ahc_pause(struct ahc_softc *ahc)
+{
+ ahc_outb(ahc, HCNTRL, ahc->pause);
+
+ /*
+ * Since the sequencer can disable pausing in a critical section, we
+ * must loop until it actually stops.
+ */
+ while (ahc_is_paused(ahc) == 0)
+ ;
+
+ ahc_pause_bug_fix(ahc);
+}
+
+/*
+ * Allow the sequencer to continue program execution.
+ * We check here to ensure that no additional interrupt
+ * sources that would cause the sequencer to halt have been
+ * asserted. If, for example, a SCSI bus reset is detected
+ * while we are fielding a different, pausing, interrupt type,
+ * we don't want to release the sequencer before going back
+ * into our interrupt handler and dealing with this new
+ * condition.
+ */
+void
+ahc_unpause(struct ahc_softc *ahc)
+{
+ if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
+ ahc_outb(ahc, HCNTRL, ahc->unpause);
+}
+
+/************************** Memory mapping routines ***************************/
+static struct ahc_dma_seg *
+ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
+{
+ int sg_index;
+
+ sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
+ /* sg_list_phys points to entry 1, not 0 */
+ sg_index++;
+
+ return (&scb->sg_list[sg_index]);
+}
+
+static uint32_t
+ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
+{
+ int sg_index;
+
+ /* sg_list_phys points to entry 1, not 0 */
+ sg_index = sg - &scb->sg_list[1];
+
+ return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
+}
+
+static uint32_t
+ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
+{
+ return (ahc->scb_data->hscb_busaddr
+ + (sizeof(struct hardware_scb) * index));
+}
+
+static void
+ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
+{
+ ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
+ ahc->scb_data->hscb_dmamap,
+ /*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
+ /*len*/sizeof(*scb->hscb), op);
+}
+
+void
+ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
+{
+ if (scb->sg_count == 0)
+ return;
+
+ ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
+ /*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
+ * sizeof(struct ahc_dma_seg),
+ /*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
+}
+
+#ifdef AHC_TARGET_MODE
+static uint32_t
+ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
+{
+ return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
+}
+#endif
+
+/*********************** Miscelaneous Support Functions ***********************/
+/*
+ * Determine whether the sequencer reported a residual
+ * for this SCB/transaction.
+ */
+static void
+ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
+{
+ uint32_t sgptr;
+
+ sgptr = ahc_le32toh(scb->hscb->sgptr);
+ if ((sgptr & SG_RESID_VALID) != 0)
+ ahc_calc_residual(ahc, scb);
+}
+
+/*
+ * Return pointers to the transfer negotiation information
+ * for the specified our_id/remote_id pair.
+ */
+struct ahc_initiator_tinfo *
+ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
+ u_int remote_id, struct ahc_tmode_tstate **tstate)
+{
+ /*
+ * Transfer data structures are stored from the perspective
+ * of the target role. Since the parameters for a connection
+ * in the initiator role to a given target are the same as
+ * when the roles are reversed, we pretend we are the target.
+ */
+ if (channel == 'B')
+ our_id += 8;
+ *tstate = ahc->enabled_targets[our_id];
+ return (&(*tstate)->transinfo[remote_id]);
+}
+
+uint16_t
+ahc_inw(struct ahc_softc *ahc, u_int port)
+{
+ uint16_t r = ahc_inb(ahc, port+1) << 8;
+ return r | ahc_inb(ahc, port);
+}
+
+void
+ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
+{
+ ahc_outb(ahc, port, value & 0xFF);
+ ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+}
+
+uint32_t
+ahc_inl(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port))
+ | (ahc_inb(ahc, port+1) << 8)
+ | (ahc_inb(ahc, port+2) << 16)
+ | (ahc_inb(ahc, port+3) << 24));
+}
+
+void
+ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
+{
+ ahc_outb(ahc, port, (value) & 0xFF);
+ ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
+ ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
+ ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
+}
+
+uint64_t
+ahc_inq(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port))
+ | (ahc_inb(ahc, port+1) << 8)
+ | (ahc_inb(ahc, port+2) << 16)
+ | (ahc_inb(ahc, port+3) << 24)
+ | (((uint64_t)ahc_inb(ahc, port+4)) << 32)
+ | (((uint64_t)ahc_inb(ahc, port+5)) << 40)
+ | (((uint64_t)ahc_inb(ahc, port+6)) << 48)
+ | (((uint64_t)ahc_inb(ahc, port+7)) << 56));
+}
+
+void
+ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
+{
+ ahc_outb(ahc, port, value & 0xFF);
+ ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+ ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
+ ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
+ ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
+ ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
+ ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
+ ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new SCB.
+ */
+struct scb *
+ahc_get_scb(struct ahc_softc *ahc)
+{
+ struct scb *scb;
+
+ if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
+ ahc_alloc_scbs(ahc);
+ scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
+ if (scb == NULL)
+ return (NULL);
+ }
+ SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
+ return (scb);
+}
+
+/*
+ * Return an SCB resource to the free list.
+ */
+void
+ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+ struct hardware_scb *hscb;
+
+ hscb = scb->hscb;
+ /* Clean up for the next user */
+ ahc->scb_data->scbindex[hscb->tag] = NULL;
+ scb->flags = SCB_FREE;
+ hscb->control = 0;
+
+ SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
+
+ /* Notify the OSM that a resource is now available. */
+ ahc_platform_scb_free(ahc, scb);
+}
+
+struct scb *
+ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
+{
+ struct scb* scb;
+
+ scb = ahc->scb_data->scbindex[tag];
+ if (scb != NULL)
+ ahc_sync_scb(ahc, scb,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ return (scb);
+}
+
+static void
+ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
+{
+ struct hardware_scb *q_hscb;
+ u_int saved_tag;
+
+ /*
+ * Our queuing method is a bit tricky. The card
+ * knows in advance which HSCB to download, and we
+ * can't disappoint it. To achieve this, the next
+ * SCB to download is saved off in ahc->next_queued_scb.
+ * When we are called to queue "an arbitrary scb",
+ * we copy the contents of the incoming HSCB to the one
+ * the sequencer knows about, swap HSCB pointers and
+ * finally assign the SCB to the tag indexed location
+ * in the scb_array. This makes sure that we can still
+ * locate the correct SCB by SCB_TAG.
+ */
+ q_hscb = ahc->next_queued_scb->hscb;
+ saved_tag = q_hscb->tag;
+ memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+ if ((scb->flags & SCB_CDB32_PTR) != 0) {
+ q_hscb->shared_data.cdb_ptr =
+ ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
+ + offsetof(struct hardware_scb, cdb32));
+ }
+ q_hscb->tag = saved_tag;
+ q_hscb->next = scb->hscb->tag;
+
+ /* Now swap HSCB pointers. */
+ ahc->next_queued_scb->hscb = scb->hscb;
+ scb->hscb = q_hscb;
+
+ /* Now define the mapping from tag to SCB in the scbindex */
+ ahc->scb_data->scbindex[scb->hscb->tag] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
*/
void
+ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+ ahc_swap_with_next_hscb(ahc, scb);
+
+ if (scb->hscb->tag == SCB_LIST_NULL
+ || scb->hscb->next == SCB_LIST_NULL)
+ panic("Attempt to queue invalid SCB tag %x:%x\n",
+ scb->hscb->tag, scb->hscb->next);
+
+ /*
+ * Setup data "oddness".
+ */
+ scb->hscb->lun &= LID;
+ if (ahc_get_transfer_length(scb) & 0x1)
+ scb->hscb->lun |= SCB_XFERLEN_ODD;
+
+ /*
+ * Keep a history of SCBs we've downloaded in the qinfifo.
+ */
+ ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+
+ /*
+ * Make sure our data is consistent from the
+ * perspective of the adapter.
+ */
+ ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Tell the adapter about the newly queued SCB */
+ if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+ } else {
+ if ((ahc->features & AHC_AUTOPAUSE) == 0)
+ ahc_pause(ahc);
+ ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+ if ((ahc->features & AHC_AUTOPAUSE) == 0)
+ ahc_unpause(ahc);
+ }
+}
+
+struct scsi_sense_data *
+ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
+{
+ int offset;
+
+ offset = scb - ahc->scb_data->scbarray;
+ return (&ahc->scb_data->sense[offset]);
+}
+
+static uint32_t
+ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
+{
+ int offset;
+
+ offset = scb - ahc->scb_data->scbarray;
+ return (ahc->scb_data->sense_busaddr
+ + (offset * sizeof(struct scsi_sense_data)));
+}
+
+/************************** Interrupt Processing ******************************/
+static void
+ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
+{
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ /*offset*/0, /*len*/256, op);
+}
+
+static void
+ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
+{
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0) {
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, 0),
+ sizeof(struct target_cmd) * AHC_TMODE_CMDS,
+ op);
+ }
+#endif
+}
+
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHC_RUN_QOUTFIFO 0x1
+#define AHC_RUN_TQINFIFO 0x2
+static u_int
+ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
+{
+ u_int retval;
+
+ retval = 0;
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ /*offset*/ahc->qoutfifonext, /*len*/1,
+ BUS_DMASYNC_POSTREAD);
+ if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
+ retval |= AHC_RUN_QOUTFIFO;
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0
+ && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
+ /*len*/sizeof(struct target_cmd),
+ BUS_DMASYNC_POSTREAD);
+ if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
+ retval |= AHC_RUN_TQINFIFO;
+ }
+#endif
+ return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+int
+ahc_intr(struct ahc_softc *ahc)
+{
+ u_int intstat;
+
+ if ((ahc->pause & INTEN) == 0) {
+ /*
+ * Our interrupt is not enabled on the chip
+ * and may be disabled for re-entrancy reasons,
+ * so just return. This is likely just a shared
+ * interrupt.
+ */
+ return (0);
+ }
+ /*
+ * Instead of directly reading the interrupt status register,
+ * infer the cause of the interrupt by checking our in-core
+ * completion queues. This avoids a costly PCI bus read in
+ * most cases.
+ */
+ if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
+ && (ahc_check_cmdcmpltqueues(ahc) != 0))
+ intstat = CMDCMPLT;
+ else {
+ intstat = ahc_inb(ahc, INTSTAT);
+ }
+
+ if ((intstat & INT_PEND) == 0) {
+#if AHC_PCI_CONFIG > 0
+ if (ahc->unsolicited_ints > 500) {
+ ahc->unsolicited_ints = 0;
+ if ((ahc->chip & AHC_PCI) != 0
+ && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
+ ahc->bus_intr(ahc);
+ }
+#endif
+ ahc->unsolicited_ints++;
+ return (0);
+ }
+ ahc->unsolicited_ints = 0;
+
+ if (intstat & CMDCMPLT) {
+ ahc_outb(ahc, CLRINT, CLRCMDINT);
+
+ /*
+ * Ensure that the chip sees that we've cleared
+ * this interrupt before we walk the output fifo.
+ * Otherwise, we may, due to posted bus writes,
+ * clear the interrupt after we finish the scan,
+ * and after the sequencer has added new entries
+ * and asserted the interrupt again.
+ */
+ ahc_flush_device_writes(ahc);
+ ahc_run_qoutfifo(ahc);
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0)
+ ahc_run_tqinfifo(ahc, /*paused*/FALSE);
+#endif
+ }
+
+ /*
+ * Handle statuses that may invalidate our cached
+ * copy of INTSTAT separately.
+ */
+ if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
+ /* Hot eject. Do nothing */
+ } else if (intstat & BRKADRINT) {
+ ahc_handle_brkadrint(ahc);
+ } else if ((intstat & (SEQINT|SCSIINT)) != 0) {
+
+ ahc_pause_bug_fix(ahc);
+
+ if ((intstat & SEQINT) != 0)
+ ahc_handle_seqint(ahc, intstat);
+
+ if ((intstat & SCSIINT) != 0)
+ ahc_handle_scsiint(ahc, intstat);
+ }
+ return (1);
+}
+
+/************************* Sequencer Execution Control ************************/
+/*
+ * Restart the sequencer program from address zero
+ */
+static void
ahc_restart(struct ahc_softc *ahc)
{
@@ -302,7 +872,7 @@ ahc_restart(struct ahc_softc *ahc)
}
/************************* Input/Output Queues ********************************/
-void
+static void
ahc_run_qoutfifo(struct ahc_softc *ahc)
{
struct scb *scb;
@@ -349,7 +919,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
}
}
-void
+static void
ahc_run_untagged_queues(struct ahc_softc *ahc)
{
int i;
@@ -358,7 +928,7 @@ ahc_run_untagged_queues(struct ahc_softc *ahc)
ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]);
}
-void
+static void
ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
{
struct scb *scb;
@@ -374,7 +944,7 @@ ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
}
/************************* Interrupt Handling *********************************/
-void
+static void
ahc_handle_brkadrint(struct ahc_softc *ahc)
{
/*
@@ -403,7 +973,7 @@ ahc_handle_brkadrint(struct ahc_softc *ahc)
ahc_shutdown(ahc);
}
-void
+static void
ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
{
struct scb *scb;
@@ -954,7 +1524,7 @@ unpause:
ahc_unpause(ahc);
}
-void
+static void
ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
{
u_int scb_index;
@@ -1407,7 +1977,7 @@ ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
}
#define AHC_MAX_STEPS 2000
-void
+static void
ahc_clear_critical_section(struct ahc_softc *ahc)
{
int stepping;
@@ -1500,7 +2070,7 @@ ahc_clear_critical_section(struct ahc_softc *ahc)
/*
* Clear any pending interrupt status.
*/
-void
+static void
ahc_clear_intstat(struct ahc_softc *ahc)
{
/* Clear any interrupt conditions this may have caused */
@@ -1519,7 +2089,8 @@ ahc_clear_intstat(struct ahc_softc *ahc)
uint32_t ahc_debug = AHC_DEBUG_OPTS;
#endif
-void
+#if 0 /* unused */
+static void
ahc_print_scb(struct scb *scb)
{
int i;
@@ -1551,6 +2122,7 @@ ahc_print_scb(struct scb *scb)
}
}
}
+#endif
/************************* Transfer Negotiation *******************************/
/*
@@ -1634,7 +2206,7 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
* by the capabilities of the bus connectivity of and sync settings for
* the target.
*/
-struct ahc_syncrate *
+const struct ahc_syncrate *
ahc_devlimited_syncrate(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *tinfo,
u_int *period, u_int *ppr_options, role_t role)
@@ -1689,11 +2261,11 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc,
* Return the period and offset that should be sent to the target
* if this was the beginning of an SDTR.
*/
-struct ahc_syncrate *
+const struct ahc_syncrate *
ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
u_int *ppr_options, u_int maxsync)
{
- struct ahc_syncrate *syncrate;
+ const struct ahc_syncrate *syncrate;
if ((ahc->features & AHC_DT) == 0)
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
@@ -1768,7 +2340,7 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
u_int
ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
{
- struct ahc_syncrate *syncrate;
+ const struct ahc_syncrate *syncrate;
if ((ahc->features & AHC_ULTRA2) != 0)
scsirate &= SXFR_ULTRA2;
@@ -1806,10 +2378,10 @@ ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
* Truncate the given synchronous offset to a value the
* current adapter type and syncrate are capable of.
*/
-void
+static void
ahc_validate_offset(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *tinfo,
- struct ahc_syncrate *syncrate,
+ const struct ahc_syncrate *syncrate,
u_int *offset, int wide, role_t role)
{
u_int maxoffset;
@@ -1838,7 +2410,7 @@ ahc_validate_offset(struct ahc_softc *ahc,
* Truncate the given transfer width parameter to a value the
* current adapter type is capable of.
*/
-void
+static void
ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
u_int *bus_width, role_t role)
{
@@ -1913,7 +2485,7 @@ ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
*/
void
ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
- struct ahc_syncrate *syncrate, u_int period,
+ const struct ahc_syncrate *syncrate, u_int period,
u_int offset, u_int ppr_options, u_int type, int paused)
{
struct ahc_initiator_tinfo *tinfo;
@@ -2220,11 +2792,11 @@ ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
role);
}
-struct ahc_phase_table_entry*
+static const struct ahc_phase_table_entry*
ahc_lookup_phase_entry(int phase)
{
- struct ahc_phase_table_entry *entry;
- struct ahc_phase_table_entry *last_entry;
+ const struct ahc_phase_table_entry *entry;
+ const struct ahc_phase_table_entry *last_entry;
/*
* num_phases doesn't include the default entry which
@@ -2390,7 +2962,7 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
*/
struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
- struct ahc_syncrate *rate;
+ const struct ahc_syncrate *rate;
int dowide;
int dosync;
int doppr;
@@ -2655,7 +3227,7 @@ proto_violation_reset:
*/
static void
ahc_handle_message_phase(struct ahc_softc *ahc)
-{
+{
struct ahc_devinfo devinfo;
u_int bus_phase;
int end_session;
@@ -3056,7 +3628,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
switch (ahc->msgin_buf[2]) {
case MSG_EXT_SDTR:
{
- struct ahc_syncrate *syncrate;
+ const struct ahc_syncrate *syncrate;
u_int period;
u_int ppr_options;
u_int offset;
@@ -3231,7 +3803,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
}
case MSG_EXT_PPR:
{
- struct ahc_syncrate *syncrate;
+ const struct ahc_syncrate *syncrate;
u_int period;
u_int offset;
u_int bus_width;
@@ -3984,7 +4556,7 @@ ahc_free(struct ahc_softc *ahc)
return;
}
-void
+static void
ahc_shutdown(void *arg)
{
struct ahc_softc *ahc;
@@ -4388,7 +4960,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
free(scb_data->scbarray, M_DEVBUF);
}
-void
+static void
ahc_alloc_scbs(struct ahc_softc *ahc)
{
struct scb_data *scb_data;
@@ -5121,7 +5693,7 @@ ahc_resume(struct ahc_softc *ahc)
* Return the untagged transaction id for a given target/channel lun.
* Optionally, clear the entry.
*/
-u_int
+static u_int
ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
{
u_int scbid;
@@ -5142,7 +5714,7 @@ ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
return (scbid);
}
-void
+static void
ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
{
u_int target_offset;
@@ -5160,7 +5732,7 @@ ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
}
}
-void
+static void
ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid)
{
u_int target_offset;
@@ -5215,7 +5787,7 @@ ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
return match;
}
-void
+static void
ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
{
int target;
@@ -5707,7 +6279,7 @@ ahc_add_curscb_to_free_list(struct ahc_softc *ahc)
*/
static u_int
ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
-{
+{
u_int curscb, next;
/*
@@ -5756,7 +6328,7 @@ ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
* been modified from CAM_REQ_INPROG. This routine assumes that the sequencer
* is paused before it is called.
*/
-int
+static int
ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
int lun, u_int tag, role_t role, uint32_t status)
{
@@ -6078,7 +6650,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
/*
* Calculate the residual for a just completed SCB.
*/
-void
+static void
ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb)
{
struct hardware_scb *hscb;
@@ -6279,7 +6851,7 @@ ahc_loadseq(struct ahc_softc *ahc)
struct cs cs_table[num_critical_sections];
u_int begin_set[num_critical_sections];
u_int end_set[num_critical_sections];
- struct patch *cur_patch;
+ const struct patch *cur_patch;
u_int cs_count;
u_int cur_cs;
u_int i;
@@ -6384,11 +6956,11 @@ ahc_loadseq(struct ahc_softc *ahc)
}
static int
-ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch,
+ahc_check_patch(struct ahc_softc *ahc, const struct patch **start_patch,
u_int start_instr, u_int *skip_addr)
{
- struct patch *cur_patch;
- struct patch *last_patch;
+ const struct patch *cur_patch;
+ const struct patch *last_patch;
u_int num_patches;
num_patches = ARRAY_SIZE(patches);
@@ -6447,7 +7019,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
case AIC_OP_JE:
case AIC_OP_JZ:
{
- struct patch *cur_patch;
+ const struct patch *cur_patch;
int address_offset;
u_int address;
u_int skip_addr;
@@ -6545,7 +7117,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
}
int
-ahc_print_register(ahc_reg_parse_entry_t *table, u_int num_entries,
+ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries,
const char *name, u_int address, u_int value,
u_int *cur_column, u_int wrap_point)
{
@@ -7229,7 +7801,7 @@ ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask)
ahc_outb(ahc, SCSIID, scsiid);
}
-void
+static void
ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
{
struct target_cmd *cmd;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
index cba2f23bbe79..09bf2f4d78d5 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
@@ -46,179 +46,13 @@
#define _AIC7XXX_INLINE_H_
/************************* Sequencer Execution Control ************************/
-static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
-static __inline int ahc_is_paused(struct ahc_softc *ahc);
-static __inline void ahc_pause(struct ahc_softc *ahc);
-static __inline void ahc_unpause(struct ahc_softc *ahc);
-
-/*
- * Work around any chip bugs related to halting sequencer execution.
- * On Ultra2 controllers, we must clear the CIOBUS stretch signal by
- * reading a register that will set this signal and deassert it.
- * Without this workaround, if the chip is paused, by an interrupt or
- * manual pause while accessing scb ram, accesses to certain registers
- * will hang the system (infinite pci retries).
- */
-static __inline void
-ahc_pause_bug_fix(struct ahc_softc *ahc)
-{
- if ((ahc->features & AHC_ULTRA2) != 0)
- (void)ahc_inb(ahc, CCSCBCTL);
-}
-
-/*
- * Determine whether the sequencer has halted code execution.
- * Returns non-zero status if the sequencer is stopped.
- */
-static __inline int
-ahc_is_paused(struct ahc_softc *ahc)
-{
- return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
-}
-
-/*
- * Request that the sequencer stop and wait, indefinitely, for it
- * to stop. The sequencer will only acknowledge that it is paused
- * once it has reached an instruction boundary and PAUSEDIS is
- * cleared in the SEQCTL register. The sequencer may use PAUSEDIS
- * for critical sections.
- */
-static __inline void
-ahc_pause(struct ahc_softc *ahc)
-{
- ahc_outb(ahc, HCNTRL, ahc->pause);
-
- /*
- * Since the sequencer can disable pausing in a critical section, we
- * must loop until it actually stops.
- */
- while (ahc_is_paused(ahc) == 0)
- ;
-
- ahc_pause_bug_fix(ahc);
-}
-
-/*
- * Allow the sequencer to continue program execution.
- * We check here to ensure that no additional interrupt
- * sources that would cause the sequencer to halt have been
- * asserted. If, for example, a SCSI bus reset is detected
- * while we are fielding a different, pausing, interrupt type,
- * we don't want to release the sequencer before going back
- * into our interrupt handler and dealing with this new
- * condition.
- */
-static __inline void
-ahc_unpause(struct ahc_softc *ahc)
-{
- if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
- ahc_outb(ahc, HCNTRL, ahc->unpause);
-}
-
-/*********************** Untagged Transaction Routines ************************/
-static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
-static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
-
-/*
- * Block our completion routine from starting the next untagged
- * transaction for this target or target lun.
- */
-static __inline void
-ahc_freeze_untagged_queues(struct ahc_softc *ahc)
-{
- if ((ahc->flags & AHC_SCB_BTT) == 0)
- ahc->untagged_queue_lock++;
-}
-
-/*
- * Allow the next untagged transaction for this target or target lun
- * to be executed. We use a counting semaphore to allow the lock
- * to be acquired recursively. Once the count drops to zero, the
- * transaction queues will be run.
- */
-static __inline void
-ahc_release_untagged_queues(struct ahc_softc *ahc)
-{
- if ((ahc->flags & AHC_SCB_BTT) == 0) {
- ahc->untagged_queue_lock--;
- if (ahc->untagged_queue_lock == 0)
- ahc_run_untagged_queues(ahc);
- }
-}
+int ahc_is_paused(struct ahc_softc *ahc);
+void ahc_pause(struct ahc_softc *ahc);
+void ahc_unpause(struct ahc_softc *ahc);
/************************** Memory mapping routines ***************************/
-static __inline struct ahc_dma_seg *
- ahc_sg_bus_to_virt(struct scb *scb,
- uint32_t sg_busaddr);
-static __inline uint32_t
- ahc_sg_virt_to_bus(struct scb *scb,
- struct ahc_dma_seg *sg);
-static __inline uint32_t
- ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
-static __inline void ahc_sync_scb(struct ahc_softc *ahc,
- struct scb *scb, int op);
-static __inline void ahc_sync_sglist(struct ahc_softc *ahc,
- struct scb *scb, int op);
-static __inline uint32_t
- ahc_targetcmd_offset(struct ahc_softc *ahc,
- u_int index);
-
-static __inline struct ahc_dma_seg *
-ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
-{
- int sg_index;
-
- sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
- /* sg_list_phys points to entry 1, not 0 */
- sg_index++;
-
- return (&scb->sg_list[sg_index]);
-}
-
-static __inline uint32_t
-ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
-{
- int sg_index;
-
- /* sg_list_phys points to entry 1, not 0 */
- sg_index = sg - &scb->sg_list[1];
-
- return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
-}
-
-static __inline uint32_t
-ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
-{
- return (ahc->scb_data->hscb_busaddr
- + (sizeof(struct hardware_scb) * index));
-}
-
-static __inline void
-ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
-{
- ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
- ahc->scb_data->hscb_dmamap,
- /*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
- /*len*/sizeof(*scb->hscb), op);
-}
-
-static __inline void
-ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
-{
- if (scb->sg_count == 0)
- return;
-
- ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
- /*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
- * sizeof(struct ahc_dma_seg),
- /*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
-}
-
-static __inline uint32_t
-ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
-{
- return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
-}
+void ahc_sync_sglist(struct ahc_softc *ahc,
+ struct scb *scb, int op);
/******************************** Debugging ***********************************/
static __inline char *ahc_name(struct ahc_softc *ahc);
@@ -231,420 +65,34 @@ ahc_name(struct ahc_softc *ahc)
/*********************** Miscellaneous Support Functions ***********************/
-static __inline void ahc_update_residual(struct ahc_softc *ahc,
- struct scb *scb);
-static __inline struct ahc_initiator_tinfo *
- ahc_fetch_transinfo(struct ahc_softc *ahc,
- char channel, u_int our_id,
- u_int remote_id,
- struct ahc_tmode_tstate **tstate);
-static __inline uint16_t
- ahc_inw(struct ahc_softc *ahc, u_int port);
-static __inline void ahc_outw(struct ahc_softc *ahc, u_int port,
- u_int value);
-static __inline uint32_t
- ahc_inl(struct ahc_softc *ahc, u_int port);
-static __inline void ahc_outl(struct ahc_softc *ahc, u_int port,
- uint32_t value);
-static __inline uint64_t
- ahc_inq(struct ahc_softc *ahc, u_int port);
-static __inline void ahc_outq(struct ahc_softc *ahc, u_int port,
- uint64_t value);
-static __inline struct scb*
- ahc_get_scb(struct ahc_softc *ahc);
-static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
-static __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
- struct scb *scb);
-static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
-static __inline struct scsi_sense_data *
- ahc_get_sense_buf(struct ahc_softc *ahc,
- struct scb *scb);
-static __inline uint32_t
- ahc_get_sense_bufaddr(struct ahc_softc *ahc,
- struct scb *scb);
-
-/*
- * Determine whether the sequencer reported a residual
- * for this SCB/transaction.
- */
-static __inline void
-ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
-{
- uint32_t sgptr;
-
- sgptr = ahc_le32toh(scb->hscb->sgptr);
- if ((sgptr & SG_RESID_VALID) != 0)
- ahc_calc_residual(ahc, scb);
-}
-
-/*
- * Return pointers to the transfer negotiation information
- * for the specified our_id/remote_id pair.
- */
-static __inline struct ahc_initiator_tinfo *
-ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
- u_int remote_id, struct ahc_tmode_tstate **tstate)
-{
- /*
- * Transfer data structures are stored from the perspective
- * of the target role. Since the parameters for a connection
- * in the initiator role to a given target are the same as
- * when the roles are reversed, we pretend we are the target.
- */
- if (channel == 'B')
- our_id += 8;
- *tstate = ahc->enabled_targets[our_id];
- return (&(*tstate)->transinfo[remote_id]);
-}
-
-static __inline uint16_t
-ahc_inw(struct ahc_softc *ahc, u_int port)
-{
- uint16_t r = ahc_inb(ahc, port+1) << 8;
- return r | ahc_inb(ahc, port);
-}
-
-static __inline void
-ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
-{
- ahc_outb(ahc, port, value & 0xFF);
- ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
-}
-
-static __inline uint32_t
-ahc_inl(struct ahc_softc *ahc, u_int port)
-{
- return ((ahc_inb(ahc, port))
- | (ahc_inb(ahc, port+1) << 8)
- | (ahc_inb(ahc, port+2) << 16)
- | (ahc_inb(ahc, port+3) << 24));
-}
-
-static __inline void
-ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
-{
- ahc_outb(ahc, port, (value) & 0xFF);
- ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
- ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
- ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
-}
-
-static __inline uint64_t
-ahc_inq(struct ahc_softc *ahc, u_int port)
-{
- return ((ahc_inb(ahc, port))
- | (ahc_inb(ahc, port+1) << 8)
- | (ahc_inb(ahc, port+2) << 16)
- | (ahc_inb(ahc, port+3) << 24)
- | (((uint64_t)ahc_inb(ahc, port+4)) << 32)
- | (((uint64_t)ahc_inb(ahc, port+5)) << 40)
- | (((uint64_t)ahc_inb(ahc, port+6)) << 48)
- | (((uint64_t)ahc_inb(ahc, port+7)) << 56));
-}
-
-static __inline void
-ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
-{
- ahc_outb(ahc, port, value & 0xFF);
- ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
- ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
- ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
- ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
- ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
- ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
- ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
-}
-
-/*
- * Get a free scb. If there are none, see if we can allocate a new SCB.
- */
-static __inline struct scb *
-ahc_get_scb(struct ahc_softc *ahc)
-{
- struct scb *scb;
-
- if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
- ahc_alloc_scbs(ahc);
- scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
- if (scb == NULL)
- return (NULL);
- }
- SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
- return (scb);
-}
-
-/*
- * Return an SCB resource to the free list.
- */
-static __inline void
-ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
-{
- struct hardware_scb *hscb;
-
- hscb = scb->hscb;
- /* Clean up for the next user */
- ahc->scb_data->scbindex[hscb->tag] = NULL;
- scb->flags = SCB_FREE;
- hscb->control = 0;
-
- SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
-
- /* Notify the OSM that a resource is now available. */
- ahc_platform_scb_free(ahc, scb);
-}
-
-static __inline struct scb *
-ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
-{
- struct scb* scb;
-
- scb = ahc->scb_data->scbindex[tag];
- if (scb != NULL)
- ahc_sync_scb(ahc, scb,
- BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- return (scb);
-}
-
-static __inline void
-ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
-{
- struct hardware_scb *q_hscb;
- u_int saved_tag;
-
- /*
- * Our queuing method is a bit tricky. The card
- * knows in advance which HSCB to download, and we
- * can't disappoint it. To achieve this, the next
- * SCB to download is saved off in ahc->next_queued_scb.
- * When we are called to queue "an arbitrary scb",
- * we copy the contents of the incoming HSCB to the one
- * the sequencer knows about, swap HSCB pointers and
- * finally assign the SCB to the tag indexed location
- * in the scb_array. This makes sure that we can still
- * locate the correct SCB by SCB_TAG.
- */
- q_hscb = ahc->next_queued_scb->hscb;
- saved_tag = q_hscb->tag;
- memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
- if ((scb->flags & SCB_CDB32_PTR) != 0) {
- q_hscb->shared_data.cdb_ptr =
- ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
- + offsetof(struct hardware_scb, cdb32));
- }
- q_hscb->tag = saved_tag;
- q_hscb->next = scb->hscb->tag;
-
- /* Now swap HSCB pointers. */
- ahc->next_queued_scb->hscb = scb->hscb;
- scb->hscb = q_hscb;
-
- /* Now define the mapping from tag to SCB in the scbindex */
- ahc->scb_data->scbindex[scb->hscb->tag] = scb;
-}
-
-/*
- * Tell the sequencer about a new transaction to execute.
- */
-static __inline void
-ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
-{
- ahc_swap_with_next_hscb(ahc, scb);
-
- if (scb->hscb->tag == SCB_LIST_NULL
- || scb->hscb->next == SCB_LIST_NULL)
- panic("Attempt to queue invalid SCB tag %x:%x\n",
- scb->hscb->tag, scb->hscb->next);
-
- /*
- * Setup data "oddness".
- */
- scb->hscb->lun &= LID;
- if (ahc_get_transfer_length(scb) & 0x1)
- scb->hscb->lun |= SCB_XFERLEN_ODD;
-
- /*
- * Keep a history of SCBs we've downloaded in the qinfifo.
- */
- ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
-
- /*
- * Make sure our data is consistent from the
- * perspective of the adapter.
- */
- ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
- /* Tell the adapter about the newly queued SCB */
- if ((ahc->features & AHC_QUEUE_REGS) != 0) {
- ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
- } else {
- if ((ahc->features & AHC_AUTOPAUSE) == 0)
- ahc_pause(ahc);
- ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
- if ((ahc->features & AHC_AUTOPAUSE) == 0)
- ahc_unpause(ahc);
- }
-}
-
-static __inline struct scsi_sense_data *
-ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
-{
- int offset;
-
- offset = scb - ahc->scb_data->scbarray;
- return (&ahc->scb_data->sense[offset]);
-}
-
-static __inline uint32_t
-ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
-{
- int offset;
-
- offset = scb - ahc->scb_data->scbarray;
- return (ahc->scb_data->sense_busaddr
- + (offset * sizeof(struct scsi_sense_data)));
-}
+struct ahc_initiator_tinfo *
+ ahc_fetch_transinfo(struct ahc_softc *ahc,
+ char channel, u_int our_id,
+ u_int remote_id,
+ struct ahc_tmode_tstate **tstate);
+uint16_t
+ ahc_inw(struct ahc_softc *ahc, u_int port);
+void ahc_outw(struct ahc_softc *ahc, u_int port,
+ u_int value);
+uint32_t
+ ahc_inl(struct ahc_softc *ahc, u_int port);
+void ahc_outl(struct ahc_softc *ahc, u_int port,
+ uint32_t value);
+uint64_t
+ ahc_inq(struct ahc_softc *ahc, u_int port);
+void ahc_outq(struct ahc_softc *ahc, u_int port,
+ uint64_t value);
+struct scb*
+ ahc_get_scb(struct ahc_softc *ahc);
+void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
+struct scb *
+ ahc_lookup_scb(struct ahc_softc *ahc, u_int tag);
+void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
+struct scsi_sense_data *
+ ahc_get_sense_buf(struct ahc_softc *ahc,
+ struct scb *scb);
/************************** Interrupt Processing ******************************/
-static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
-static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
-static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
-static __inline int ahc_intr(struct ahc_softc *ahc);
-
-static __inline void
-ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
-{
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
- /*offset*/0, /*len*/256, op);
-}
-
-static __inline void
-ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
-{
-#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0) {
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
- ahc->shared_data_dmamap,
- ahc_targetcmd_offset(ahc, 0),
- sizeof(struct target_cmd) * AHC_TMODE_CMDS,
- op);
- }
-#endif
-}
-
-/*
- * See if the firmware has posted any completed commands
- * into our in-core command complete fifos.
- */
-#define AHC_RUN_QOUTFIFO 0x1
-#define AHC_RUN_TQINFIFO 0x2
-static __inline u_int
-ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
-{
- u_int retval;
-
- retval = 0;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
- /*offset*/ahc->qoutfifonext, /*len*/1,
- BUS_DMASYNC_POSTREAD);
- if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
- retval |= AHC_RUN_QOUTFIFO;
-#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0
- && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
- ahc->shared_data_dmamap,
- ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
- /*len*/sizeof(struct target_cmd),
- BUS_DMASYNC_POSTREAD);
- if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
- retval |= AHC_RUN_TQINFIFO;
- }
-#endif
- return (retval);
-}
-
-/*
- * Catch an interrupt from the adapter
- */
-static __inline int
-ahc_intr(struct ahc_softc *ahc)
-{
- u_int intstat;
-
- if ((ahc->pause & INTEN) == 0) {
- /*
- * Our interrupt is not enabled on the chip
- * and may be disabled for re-entrancy reasons,
- * so just return. This is likely just a shared
- * interrupt.
- */
- return (0);
- }
- /*
- * Instead of directly reading the interrupt status register,
- * infer the cause of the interrupt by checking our in-core
- * completion queues. This avoids a costly PCI bus read in
- * most cases.
- */
- if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
- && (ahc_check_cmdcmpltqueues(ahc) != 0))
- intstat = CMDCMPLT;
- else {
- intstat = ahc_inb(ahc, INTSTAT);
- }
-
- if ((intstat & INT_PEND) == 0) {
-#if AHC_PCI_CONFIG > 0
- if (ahc->unsolicited_ints > 500) {
- ahc->unsolicited_ints = 0;
- if ((ahc->chip & AHC_PCI) != 0
- && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
- ahc->bus_intr(ahc);
- }
-#endif
- ahc->unsolicited_ints++;
- return (0);
- }
- ahc->unsolicited_ints = 0;
-
- if (intstat & CMDCMPLT) {
- ahc_outb(ahc, CLRINT, CLRCMDINT);
-
- /*
- * Ensure that the chip sees that we've cleared
- * this interrupt before we walk the output fifo.
- * Otherwise, we may, due to posted bus writes,
- * clear the interrupt after we finish the scan,
- * and after the sequencer has added new entries
- * and asserted the interrupt again.
- */
- ahc_flush_device_writes(ahc);
- ahc_run_qoutfifo(ahc);
-#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0)
- ahc_run_tqinfifo(ahc, /*paused*/FALSE);
-#endif
- }
-
- /*
- * Handle statuses that may invalidate our cached
- * copy of INTSTAT separately.
- */
- if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
- /* Hot eject. Do nothing */
- } else if (intstat & BRKADRINT) {
- ahc_handle_brkadrint(ahc);
- } else if ((intstat & (SEQINT|SCSIINT)) != 0) {
-
- ahc_pause_bug_fix(ahc);
-
- if ((intstat & SEQINT) != 0)
- ahc_handle_seqint(ahc, intstat);
-
- if ((intstat & SCSIINT) != 0)
- ahc_handle_scsiint(ahc, intstat);
- }
- return (1);
-}
+int ahc_intr(struct ahc_softc *ahc);
#endif /* _AIC7XXX_INLINE_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 42ad48e09f02..fd2b9785ff4f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -388,14 +388,83 @@ static int aic7xxx_setup(char *s);
static int ahc_linux_unit;
+/************************** OS Utility Wrappers *******************************/
+void
+ahc_delay(long usec)
+{
+ /*
+ * udelay on Linux can have problems for
+ * multi-millisecond waits. Wait at most
+ * 1024us per call.
+ */
+ while (usec > 0) {
+ udelay(usec % 1024);
+ usec -= 1024;
+ }
+}
+
+/***************************** Low Level I/O **********************************/
+uint8_t
+ahc_inb(struct ahc_softc * ahc, long port)
+{
+ uint8_t x;
+
+ if (ahc->tag == BUS_SPACE_MEMIO) {
+ x = readb(ahc->bsh.maddr + port);
+ } else {
+ x = inb(ahc->bsh.ioport + port);
+ }
+ mb();
+ return (x);
+}
+
+void
+ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
+{
+ if (ahc->tag == BUS_SPACE_MEMIO) {
+ writeb(val, ahc->bsh.maddr + port);
+ } else {
+ outb(val, ahc->bsh.ioport + port);
+ }
+ mb();
+}
+
+void
+ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ ahc_outb(ahc, port, *array++);
+}
+
+void
+ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ *array++ = ahc_inb(ahc, port);
+}
+
/********************************* Inlines ************************************/
-static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
+static void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
-static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
+static int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
struct ahc_dma_seg *sg,
dma_addr_t addr, bus_size_t len);
-static __inline void
+static void
ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
{
struct scsi_cmnd *cmd;
@@ -406,7 +475,7 @@ ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
scsi_dma_unmap(cmd);
}
-static __inline int
+static int
ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
struct ahc_dma_seg *sg, dma_addr_t addr, bus_size_t len)
{
@@ -442,13 +511,11 @@ ahc_linux_info(struct Scsi_Host *host)
bp = &buffer[0];
ahc = *(struct ahc_softc **)host->hostdata;
memset(bp, 0, sizeof(buffer));
- strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
- strcat(bp, AIC7XXX_DRIVER_VERSION);
- strcat(bp, "\n");
- strcat(bp, " <");
+ strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev " AIC7XXX_DRIVER_VERSION "\n"
+ " <");
strcat(bp, ahc->description);
- strcat(bp, ">\n");
- strcat(bp, " ");
+ strcat(bp, ">\n"
+ " ");
ahc_controller_info(ahc, ahc_info);
strcat(bp, ahc_info);
strcat(bp, "\n");
@@ -964,7 +1031,7 @@ aic7xxx_setup(char *s)
char *p;
char *end;
- static struct {
+ static const struct {
const char *name;
uint32_t *flag;
} options[] = {
@@ -2317,7 +2384,7 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period)
unsigned int ppr_options = tinfo->goal.ppr_options;
unsigned long flags;
unsigned long offset = tinfo->goal.offset;
- struct ahc_syncrate *syncrate;
+ const struct ahc_syncrate *syncrate;
if (offset == 0)
offset = MAX_OFFSET;
@@ -2361,7 +2428,7 @@ static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
unsigned int ppr_options = 0;
unsigned int period = 0;
unsigned long flags;
- struct ahc_syncrate *syncrate = NULL;
+ const struct ahc_syncrate *syncrate = NULL;
ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
starget->channel + 'A', ROLE_INITIATOR);
@@ -2391,7 +2458,7 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
unsigned int period = tinfo->goal.period;
unsigned int width = tinfo->goal.width;
unsigned long flags;
- struct ahc_syncrate *syncrate;
+ const struct ahc_syncrate *syncrate;
if (dt && spi_max_width(starget)) {
ppr_options |= MSG_EXT_PPR_DT_REQ;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index b48dab447bde..3f7238db35e5 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -365,7 +365,7 @@ struct ahc_platform_data {
#define AHC_LINUX_NOIRQ ((uint32_t)~0)
uint32_t irq; /* IRQ for this adapter */
uint32_t bios_address;
- uint32_t mem_busaddr; /* Mem Base Addr */
+ resource_size_t mem_busaddr; /* Mem Base Addr */
};
/************************** OS Utility Wrappers *******************************/
@@ -375,82 +375,16 @@ struct ahc_platform_data {
#define malloc(size, type, flags) kmalloc(size, flags)
#define free(ptr, type) kfree(ptr)
-static __inline void ahc_delay(long);
-static __inline void
-ahc_delay(long usec)
-{
- /*
- * udelay on Linux can have problems for
- * multi-millisecond waits. Wait at most
- * 1024us per call.
- */
- while (usec > 0) {
- udelay(usec % 1024);
- usec -= 1024;
- }
-}
+void ahc_delay(long);
/***************************** Low Level I/O **********************************/
-static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port);
-static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
-static __inline void ahc_outsb(struct ahc_softc * ahc, long port,
- uint8_t *, int count);
-static __inline void ahc_insb(struct ahc_softc * ahc, long port,
- uint8_t *, int count);
-
-static __inline uint8_t
-ahc_inb(struct ahc_softc * ahc, long port)
-{
- uint8_t x;
-
- if (ahc->tag == BUS_SPACE_MEMIO) {
- x = readb(ahc->bsh.maddr + port);
- } else {
- x = inb(ahc->bsh.ioport + port);
- }
- mb();
- return (x);
-}
-
-static __inline void
-ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
-{
- if (ahc->tag == BUS_SPACE_MEMIO) {
- writeb(val, ahc->bsh.maddr + port);
- } else {
- outb(val, ahc->bsh.ioport + port);
- }
- mb();
-}
-
-static __inline void
-ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- ahc_outb(ahc, port, *array++);
-}
-
-static __inline void
-ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- *array++ = ahc_inb(ahc, port);
-}
+uint8_t ahc_inb(struct ahc_softc * ahc, long port);
+void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
+void ahc_outsb(struct ahc_softc * ahc, long port,
+ uint8_t *, int count);
+void ahc_insb(struct ahc_softc * ahc, long port,
+ uint8_t *, int count);
/**************************** Initialization **********************************/
int ahc_linux_register_host(struct ahc_softc *,
@@ -464,9 +398,6 @@ struct info_str {
int pos;
};
-void ahc_format_transinfo(struct info_str *info,
- struct ahc_transinfo *tinfo);
-
/******************************** Locking *************************************/
/* Lock protecting internal data structures */
@@ -555,61 +486,12 @@ void ahc_linux_pci_exit(void);
int ahc_pci_map_registers(struct ahc_softc *ahc);
int ahc_pci_map_int(struct ahc_softc *ahc);
-static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
+uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
int reg, int width);
-static __inline uint32_t
-ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
-{
- switch (width) {
- case 1:
- {
- uint8_t retval;
-
- pci_read_config_byte(pci, reg, &retval);
- return (retval);
- }
- case 2:
- {
- uint16_t retval;
- pci_read_config_word(pci, reg, &retval);
- return (retval);
- }
- case 4:
- {
- uint32_t retval;
- pci_read_config_dword(pci, reg, &retval);
- return (retval);
- }
- default:
- panic("ahc_pci_read_config: Read size too big");
- /* NOTREACHED */
- return (0);
- }
-}
-
-static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
- int reg, uint32_t value,
- int width);
-
-static __inline void
-ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
-{
- switch (width) {
- case 1:
- pci_write_config_byte(pci, reg, value);
- break;
- case 2:
- pci_write_config_word(pci, reg, value);
- break;
- case 4:
- pci_write_config_dword(pci, reg, value);
- break;
- default:
- panic("ahc_pci_write_config: Write size too big");
- /* NOTREACHED */
- }
-}
+void ahc_pci_write_config(ahc_dev_softc_t pci,
+ int reg, uint32_t value,
+ int width);
static __inline int ahc_get_pci_function(ahc_dev_softc_t);
static __inline int
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 3d3eaef65fb3..00f5b9868574 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -46,7 +46,7 @@
*/
#define ID(x) ID_C(x, PCI_CLASS_STORAGE_SCSI)
-static struct pci_device_id ahc_linux_pci_id_table[] = {
+static const struct pci_device_id ahc_linux_pci_id_table[] = {
/* aic7850 based controllers */
ID(ID_AHA_2902_04_10_15_20C_30C),
/* aic7860 based controllers */
@@ -206,7 +206,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
const uint64_t mask_39bit = 0x7FFFFFFFFFULL;
struct ahc_softc *ahc;
ahc_dev_softc_t pci;
- struct ahc_pci_identity *entry;
+ const struct ahc_pci_identity *entry;
char *name;
int error;
struct device *dev = &pdev->dev;
@@ -269,6 +269,57 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return (0);
}
+/******************************* PCI Routines *********************************/
+uint32_t
+ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
+{
+ switch (width) {
+ case 1:
+ {
+ uint8_t retval;
+
+ pci_read_config_byte(pci, reg, &retval);
+ return (retval);
+ }
+ case 2:
+ {
+ uint16_t retval;
+ pci_read_config_word(pci, reg, &retval);
+ return (retval);
+ }
+ case 4:
+ {
+ uint32_t retval;
+ pci_read_config_dword(pci, reg, &retval);
+ return (retval);
+ }
+ default:
+ panic("ahc_pci_read_config: Read size too big");
+ /* NOTREACHED */
+ return (0);
+ }
+}
+
+void
+ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
+{
+ switch (width) {
+ case 1:
+ pci_write_config_byte(pci, reg, value);
+ break;
+ case 2:
+ pci_write_config_word(pci, reg, value);
+ break;
+ case 4:
+ pci_write_config_dword(pci, reg, value);
+ break;
+ default:
+ panic("ahc_pci_write_config: Write size too big");
+ /* NOTREACHED */
+ }
+}
+
+
static struct pci_driver aic7xxx_pci_driver = {
.name = "aic7xxx",
.probe = ahc_linux_pci_dev_probe,
@@ -293,7 +344,7 @@ ahc_linux_pci_exit(void)
}
static int
-ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
+ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, resource_size_t *base)
{
if (aic7xxx_allow_memio == 0)
return (ENOMEM);
@@ -301,24 +352,24 @@ ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
*base = pci_resource_start(ahc->dev_softc, 0);
if (*base == 0)
return (ENOMEM);
- if (request_region(*base, 256, "aic7xxx") == 0)
+ if (!request_region(*base, 256, "aic7xxx"))
return (ENOMEM);
return (0);
}
static int
ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
- u_long *bus_addr,
+ resource_size_t *bus_addr,
uint8_t __iomem **maddr)
{
- u_long start;
+ resource_size_t start;
int error;
error = 0;
start = pci_resource_start(ahc->dev_softc, 1);
if (start != 0) {
*bus_addr = start;
- if (request_mem_region(start, 0x1000, "aic7xxx") == 0)
+ if (!request_mem_region(start, 0x1000, "aic7xxx"))
error = ENOMEM;
if (error == 0) {
*maddr = ioremap_nocache(start, 256);
@@ -336,7 +387,7 @@ int
ahc_pci_map_registers(struct ahc_softc *ahc)
{
uint32_t command;
- u_long base;
+ resource_size_t base;
uint8_t __iomem *maddr;
int error;
@@ -374,12 +425,12 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
} else
command |= PCIM_CMD_MEMEN;
} else {
- printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
+ printf("aic7xxx: PCI%d:%d:%d MEM region 0x%llx "
"unavailable. Cannot memory map device.\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
ahc_get_pci_function(ahc->dev_softc),
- base);
+ (unsigned long long)base);
}
/*
@@ -390,15 +441,15 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
error = ahc_linux_pci_reserve_io_region(ahc, &base);
if (error == 0) {
ahc->tag = BUS_SPACE_PIO;
- ahc->bsh.ioport = base;
+ ahc->bsh.ioport = (u_long)base;
command |= PCIM_CMD_PORTEN;
} else {
- printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
+ printf("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] "
"unavailable. Cannot map device.\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
ahc_get_pci_function(ahc->dev_softc),
- base);
+ (unsigned long long)base);
}
}
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 56848f41e4f9..c07cb6eebb02 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -168,8 +168,7 @@ static ahc_device_setup_t ahc_aha394XX_setup;
static ahc_device_setup_t ahc_aha494XX_setup;
static ahc_device_setup_t ahc_aha398XX_setup;
-static struct ahc_pci_identity ahc_pci_ident_table [] =
-{
+static const struct ahc_pci_identity ahc_pci_ident_table[] = {
/* aic7850 based controllers */
{
ID_AHA_2902_04_10_15_20C_30C,
@@ -668,7 +667,7 @@ ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
return (result);
}
-struct ahc_pci_identity *
+const struct ahc_pci_identity *
ahc_find_pci_device(ahc_dev_softc_t pci)
{
uint64_t full_id;
@@ -676,7 +675,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
uint16_t vendor;
uint16_t subdevice;
uint16_t subvendor;
- struct ahc_pci_identity *entry;
+ const struct ahc_pci_identity *entry;
u_int i;
vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
@@ -710,7 +709,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
}
int
-ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
+ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry)
{
u_int command;
u_int our_id;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index 99e5443e7535..e92991a7c485 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -58,7 +58,7 @@ static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
* Table of syncrates that don't follow the "divisible by 4"
* rule. This table will be expanded in future SCSI specs.
*/
-static struct {
+static const struct {
u_int period_factor;
u_int period; /* in 100ths of ns */
} scsi_syncrates[] = {
@@ -137,7 +137,7 @@ copy_info(struct info_str *info, char *fmt, ...)
return (len);
}
-void
+static void
ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
{
u_int speed;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
index 88bfd767c51c..309a562b009e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
@@ -8,7 +8,7 @@
#include "aic7xxx_osm.h"
-static ahc_reg_parse_entry_t SCSISEQ_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSISEQ_parse_table[] = {
{ "SCSIRSTO", 0x01, 0x01 },
{ "ENAUTOATNP", 0x02, 0x02 },
{ "ENAUTOATNI", 0x04, 0x04 },
@@ -26,7 +26,7 @@ ahc_scsiseq_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x00, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SXFRCTL0_parse_table[] = {
+static const ahc_reg_parse_entry_t SXFRCTL0_parse_table[] = {
{ "CLRCHN", 0x02, 0x02 },
{ "SCAMEN", 0x04, 0x04 },
{ "SPIOEN", 0x08, 0x08 },
@@ -43,7 +43,7 @@ ahc_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x01, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SXFRCTL1_parse_table[] = {
+static const ahc_reg_parse_entry_t SXFRCTL1_parse_table[] = {
{ "STPWEN", 0x01, 0x01 },
{ "ACTNEGEN", 0x02, 0x02 },
{ "ENSTIMER", 0x04, 0x04 },
@@ -60,7 +60,7 @@ ahc_sxfrctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x02, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSISIGO_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSISIGO_parse_table[] = {
{ "ACKO", 0x01, 0x01 },
{ "REQO", 0x02, 0x02 },
{ "BSYO", 0x04, 0x04 },
@@ -85,7 +85,7 @@ ahc_scsisigo_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x03, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSISIGI_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSISIGI_parse_table[] = {
{ "ACKI", 0x01, 0x01 },
{ "REQI", 0x02, 0x02 },
{ "BSYI", 0x04, 0x04 },
@@ -112,7 +112,7 @@ ahc_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x03, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSIRATE_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSIRATE_parse_table[] = {
{ "SINGLE_EDGE", 0x10, 0x10 },
{ "ENABLE_CRC", 0x40, 0x40 },
{ "WIDEXFER", 0x80, 0x80 },
@@ -128,7 +128,7 @@ ahc_scsirate_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x04, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSIID_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSIID_parse_table[] = {
{ "TWIN_CHNLB", 0x80, 0x80 },
{ "OID", 0x0f, 0x0f },
{ "TWIN_TID", 0x70, 0x70 },
@@ -151,20 +151,13 @@ ahc_scsidatl_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_scsidath_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "SCSIDATH",
- 0x07, regvalue, cur_col, wrap));
-}
-
-int
ahc_stcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "STCNT",
0x08, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t OPTIONMODE_parse_table[] = {
+static const ahc_reg_parse_entry_t OPTIONMODE_parse_table[] = {
{ "DIS_MSGIN_DUALEDGE", 0x01, 0x01 },
{ "AUTO_MSGOUT_DE", 0x02, 0x02 },
{ "SCSIDATL_IMGEN", 0x04, 0x04 },
@@ -190,7 +183,7 @@ ahc_targcrccnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0a, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t CLRSINT0_parse_table[] = {
+static const ahc_reg_parse_entry_t CLRSINT0_parse_table[] = {
{ "CLRSPIORDY", 0x02, 0x02 },
{ "CLRSWRAP", 0x08, 0x08 },
{ "CLRIOERR", 0x08, 0x08 },
@@ -206,7 +199,7 @@ ahc_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0b, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SSTAT0_parse_table[] = {
+static const ahc_reg_parse_entry_t SSTAT0_parse_table[] = {
{ "DMADONE", 0x01, 0x01 },
{ "SPIORDY", 0x02, 0x02 },
{ "SDONE", 0x04, 0x04 },
@@ -225,7 +218,7 @@ ahc_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0b, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t CLRSINT1_parse_table[] = {
+static const ahc_reg_parse_entry_t CLRSINT1_parse_table[] = {
{ "CLRREQINIT", 0x01, 0x01 },
{ "CLRPHASECHG", 0x02, 0x02 },
{ "CLRSCSIPERR", 0x04, 0x04 },
@@ -242,7 +235,7 @@ ahc_clrsint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0c, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SSTAT1_parse_table[] = {
+static const ahc_reg_parse_entry_t SSTAT1_parse_table[] = {
{ "REQINIT", 0x01, 0x01 },
{ "PHASECHG", 0x02, 0x02 },
{ "SCSIPERR", 0x04, 0x04 },
@@ -260,7 +253,7 @@ ahc_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0c, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SSTAT2_parse_table[] = {
+static const ahc_reg_parse_entry_t SSTAT2_parse_table[] = {
{ "DUAL_EDGE_ERR", 0x01, 0x01 },
{ "CRCREQERR", 0x02, 0x02 },
{ "CRCENDERR", 0x04, 0x04 },
@@ -278,7 +271,7 @@ ahc_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0d, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SSTAT3_parse_table[] = {
+static const ahc_reg_parse_entry_t SSTAT3_parse_table[] = {
{ "OFFCNT", 0x0f, 0x0f },
{ "U2OFFCNT", 0x7f, 0x7f },
{ "SCSICNT", 0xf0, 0xf0 }
@@ -291,7 +284,7 @@ ahc_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0e, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSIID_ULTRA2_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSIID_ULTRA2_parse_table[] = {
{ "OID", 0x0f, 0x0f },
{ "TID", 0xf0, 0xf0 }
};
@@ -303,7 +296,7 @@ ahc_scsiid_ultra2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x0f, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SIMODE0_parse_table[] = {
+static const ahc_reg_parse_entry_t SIMODE0_parse_table[] = {
{ "ENDMADONE", 0x01, 0x01 },
{ "ENSPIORDY", 0x02, 0x02 },
{ "ENSDONE", 0x04, 0x04 },
@@ -321,7 +314,7 @@ ahc_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x10, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SIMODE1_parse_table[] = {
+static const ahc_reg_parse_entry_t SIMODE1_parse_table[] = {
{ "ENREQINIT", 0x01, 0x01 },
{ "ENPHASECHG", 0x02, 0x02 },
{ "ENSCSIPERR", 0x04, 0x04 },
@@ -347,33 +340,13 @@ ahc_scsibusl_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_scsibush_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "SCSIBUSH",
- 0x13, regvalue, cur_col, wrap));
-}
-
-static ahc_reg_parse_entry_t SXFRCTL2_parse_table[] = {
- { "CMDDMAEN", 0x08, 0x08 },
- { "AUTORSTDIS", 0x10, 0x10 },
- { "ASYNC_SETUP", 0x07, 0x07 }
-};
-
-int
-ahc_sxfrctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(SXFRCTL2_parse_table, 3, "SXFRCTL2",
- 0x13, regvalue, cur_col, wrap));
-}
-
-int
ahc_shaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "SHADDR",
0x14, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SELTIMER_parse_table[] = {
+static const ahc_reg_parse_entry_t SELTIMER_parse_table[] = {
{ "STAGE1", 0x01, 0x01 },
{ "STAGE2", 0x02, 0x02 },
{ "STAGE3", 0x04, 0x04 },
@@ -389,7 +362,7 @@ ahc_seltimer_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x18, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SELID_parse_table[] = {
+static const ahc_reg_parse_entry_t SELID_parse_table[] = {
{ "ONEBIT", 0x08, 0x08 },
{ "SELID_MASK", 0xf0, 0xf0 }
};
@@ -401,21 +374,6 @@ ahc_selid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x19, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCAMCTL_parse_table[] = {
- { "DFLTTID", 0x10, 0x10 },
- { "ALTSTIM", 0x20, 0x20 },
- { "CLRSCAMSELID", 0x40, 0x40 },
- { "ENSCAMSELO", 0x80, 0x80 },
- { "SCAMLVL", 0x03, 0x03 }
-};
-
-int
-ahc_scamctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(SCAMCTL_parse_table, 5, "SCAMCTL",
- 0x1a, regvalue, cur_col, wrap));
-}
-
int
ahc_targid_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
@@ -423,7 +381,7 @@ ahc_targid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1b, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SPIOCAP_parse_table[] = {
+static const ahc_reg_parse_entry_t SPIOCAP_parse_table[] = {
{ "SSPIOCPS", 0x01, 0x01 },
{ "ROM", 0x02, 0x02 },
{ "EEPROM", 0x04, 0x04 },
@@ -441,7 +399,7 @@ ahc_spiocap_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1b, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t BRDCTL_parse_table[] = {
+static const ahc_reg_parse_entry_t BRDCTL_parse_table[] = {
{ "BRDCTL0", 0x01, 0x01 },
{ "BRDSTB_ULTRA2", 0x01, 0x01 },
{ "BRDCTL1", 0x02, 0x02 },
@@ -464,7 +422,7 @@ ahc_brdctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1d, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SEECTL_parse_table[] = {
+static const ahc_reg_parse_entry_t SEECTL_parse_table[] = {
{ "SEEDI", 0x01, 0x01 },
{ "SEEDO", 0x02, 0x02 },
{ "SEECK", 0x04, 0x04 },
@@ -482,7 +440,7 @@ ahc_seectl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x1e, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SBLKCTL_parse_table[] = {
+static const ahc_reg_parse_entry_t SBLKCTL_parse_table[] = {
{ "XCVR", 0x01, 0x01 },
{ "SELWIDE", 0x02, 0x02 },
{ "ENAB20", 0x04, 0x04 },
@@ -522,13 +480,6 @@ ahc_disc_dsb_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_cmdsize_table_tail_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "CMDSIZE_TABLE_TAIL",
- 0x34, regvalue, cur_col, wrap));
-}
-
-int
ahc_mwi_residual_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "MWI_RESIDUAL",
@@ -549,7 +500,7 @@ ahc_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3a, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t DMAPARAMS_parse_table[] = {
+static const ahc_reg_parse_entry_t DMAPARAMS_parse_table[] = {
{ "FIFORESET", 0x01, 0x01 },
{ "FIFOFLUSH", 0x02, 0x02 },
{ "DIRECTION", 0x04, 0x04 },
@@ -569,7 +520,7 @@ ahc_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3b, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
+static const ahc_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
{ "NO_DISCONNECT", 0x01, 0x01 },
{ "SPHASE_PENDING", 0x02, 0x02 },
{ "DPHASE_PENDING", 0x04, 0x04 },
@@ -602,7 +553,7 @@ ahc_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x3e, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t LASTPHASE_parse_table[] = {
+static const ahc_reg_parse_entry_t LASTPHASE_parse_table[] = {
{ "MSGI", 0x20, 0x20 },
{ "IOI", 0x40, 0x40 },
{ "CDI", 0x80, 0x80 },
@@ -645,13 +596,6 @@ ahc_free_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_complete_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "COMPLETE_SCBH",
- 0x43, regvalue, cur_col, wrap));
-}
-
-int
ahc_hscb_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "HSCB_ADDR",
@@ -700,7 +644,7 @@ ahc_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x50, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t ARG_1_parse_table[] = {
+static const ahc_reg_parse_entry_t ARG_1_parse_table[] = {
{ "CONT_TARG_SESSION", 0x02, 0x02 },
{ "CONT_MSG_LOOP", 0x04, 0x04 },
{ "EXIT_MSG_LOOP", 0x08, 0x08 },
@@ -731,7 +675,7 @@ ahc_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x53, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
{ "ENAUTOATNP", 0x02, 0x02 },
{ "ENAUTOATNI", 0x04, 0x04 },
{ "ENAUTOATNO", 0x08, 0x08 },
@@ -747,7 +691,7 @@ ahc_scsiseq_template_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x54, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = {
+static const ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = {
{ "HA_274_EXTENDED_TRANS",0x01, 0x01 }
};
@@ -758,7 +702,7 @@ ahc_ha_274_biosglobal_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x56, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
+static const ahc_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
{ "SCB_DMA", 0x01, 0x01 },
{ "TARGET_MSG_PENDING", 0x02, 0x02 }
};
@@ -770,7 +714,7 @@ ahc_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x57, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCSICONF_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSICONF_parse_table[] = {
{ "ENSPCHK", 0x20, 0x20 },
{ "RESET_SCSI", 0x40, 0x40 },
{ "TERM_ENB", 0x80, 0x80 },
@@ -785,7 +729,7 @@ ahc_scsiconf_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5a, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t INTDEF_parse_table[] = {
+static const ahc_reg_parse_entry_t INTDEF_parse_table[] = {
{ "EDGE_TRIG", 0x80, 0x80 },
{ "VECTOR", 0x0f, 0x0f }
};
@@ -804,7 +748,7 @@ ahc_hostconf_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5d, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t HA_274_BIOSCTRL_parse_table[] = {
+static const ahc_reg_parse_entry_t HA_274_BIOSCTRL_parse_table[] = {
{ "CHANNEL_B_PRIMARY", 0x08, 0x08 },
{ "BIOSMODE", 0x30, 0x30 },
{ "BIOSDISABLED", 0x30, 0x30 }
@@ -817,7 +761,7 @@ ahc_ha_274_biosctrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x5f, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SEQCTL_parse_table[] = {
+static const ahc_reg_parse_entry_t SEQCTL_parse_table[] = {
{ "LOADRAM", 0x01, 0x01 },
{ "SEQRESET", 0x02, 0x02 },
{ "STEP", 0x04, 0x04 },
@@ -849,7 +793,7 @@ ahc_seqaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x62, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SEQADDR1_parse_table[] = {
+static const ahc_reg_parse_entry_t SEQADDR1_parse_table[] = {
{ "SEQADDR1_MASK", 0x01, 0x01 }
};
@@ -902,7 +846,7 @@ ahc_none_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x6a, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t FLAGS_parse_table[] = {
+static const ahc_reg_parse_entry_t FLAGS_parse_table[] = {
{ "CARRY", 0x01, 0x01 },
{ "ZERO", 0x02, 0x02 }
};
@@ -929,13 +873,6 @@ ahc_dindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_function1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "FUNCTION1",
- 0x6e, regvalue, cur_col, wrap));
-}
-
-int
ahc_stack_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "STACK",
@@ -956,19 +893,7 @@ ahc_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x70, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t BCTL_parse_table[] = {
- { "ENABLE", 0x01, 0x01 },
- { "ACE", 0x08, 0x08 }
-};
-
-int
-ahc_bctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(BCTL_parse_table, 2, "BCTL",
- 0x84, regvalue, cur_col, wrap));
-}
-
-static ahc_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
+static const ahc_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
{ "CIOPARCKEN", 0x01, 0x01 },
{ "USCBSIZE32", 0x02, 0x02 },
{ "RAMPS", 0x04, 0x04 },
@@ -986,7 +911,7 @@ ahc_dscommand0_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x84, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t BUSTIME_parse_table[] = {
+static const ahc_reg_parse_entry_t BUSTIME_parse_table[] = {
{ "BON", 0x0f, 0x0f },
{ "BOFF", 0xf0, 0xf0 }
};
@@ -998,7 +923,7 @@ ahc_bustime_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x85, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t DSCOMMAND1_parse_table[] = {
+static const ahc_reg_parse_entry_t DSCOMMAND1_parse_table[] = {
{ "HADDLDSEL0", 0x01, 0x01 },
{ "HADDLDSEL1", 0x02, 0x02 },
{ "DSLATT", 0xfc, 0xfc }
@@ -1011,7 +936,7 @@ ahc_dscommand1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x85, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t BUSSPD_parse_table[] = {
+static const ahc_reg_parse_entry_t BUSSPD_parse_table[] = {
{ "STBON", 0x07, 0x07 },
{ "STBOFF", 0x38, 0x38 },
{ "DFTHRSH_75", 0x80, 0x80 },
@@ -1026,7 +951,7 @@ ahc_busspd_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x86, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
+static const ahc_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
{ "SEQ_MAILBOX", 0x0f, 0x0f },
{ "HOST_TQINPOS", 0x80, 0x80 },
{ "HOST_MAILBOX", 0xf0, 0xf0 }
@@ -1039,7 +964,7 @@ ahc_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x86, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t DSPCISTATUS_parse_table[] = {
+static const ahc_reg_parse_entry_t DSPCISTATUS_parse_table[] = {
{ "DFTHRSH_100", 0xc0, 0xc0 }
};
@@ -1050,7 +975,7 @@ ahc_dspcistatus_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x86, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t HCNTRL_parse_table[] = {
+static const ahc_reg_parse_entry_t HCNTRL_parse_table[] = {
{ "CHIPRST", 0x01, 0x01 },
{ "CHIPRSTACK", 0x01, 0x01 },
{ "INTEN", 0x02, 0x02 },
@@ -1088,7 +1013,7 @@ ahc_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x90, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t INTSTAT_parse_table[] = {
+static const ahc_reg_parse_entry_t INTSTAT_parse_table[] = {
{ "SEQINT", 0x01, 0x01 },
{ "CMDCMPLT", 0x02, 0x02 },
{ "SCSIINT", 0x04, 0x04 },
@@ -1119,7 +1044,7 @@ ahc_intstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x91, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t CLRINT_parse_table[] = {
+static const ahc_reg_parse_entry_t CLRINT_parse_table[] = {
{ "CLRSEQINT", 0x01, 0x01 },
{ "CLRCMDINT", 0x02, 0x02 },
{ "CLRSCSIINT", 0x04, 0x04 },
@@ -1134,7 +1059,7 @@ ahc_clrint_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x92, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t ERROR_parse_table[] = {
+static const ahc_reg_parse_entry_t ERROR_parse_table[] = {
{ "ILLHADDR", 0x01, 0x01 },
{ "ILLSADDR", 0x02, 0x02 },
{ "ILLOPCODE", 0x04, 0x04 },
@@ -1152,7 +1077,7 @@ ahc_error_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x92, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t DFCNTRL_parse_table[] = {
+static const ahc_reg_parse_entry_t DFCNTRL_parse_table[] = {
{ "FIFORESET", 0x01, 0x01 },
{ "FIFOFLUSH", 0x02, 0x02 },
{ "DIRECTION", 0x04, 0x04 },
@@ -1172,7 +1097,7 @@ ahc_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x93, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t DFSTATUS_parse_table[] = {
+static const ahc_reg_parse_entry_t DFSTATUS_parse_table[] = {
{ "FIFOEMP", 0x01, 0x01 },
{ "FIFOFULL", 0x02, 0x02 },
{ "DFTHRESH", 0x04, 0x04 },
@@ -1198,20 +1123,13 @@ ahc_dfwaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_dfraddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "DFRADDR",
- 0x97, regvalue, cur_col, wrap));
-}
-
-int
ahc_dfdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "DFDAT",
0x99, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCBCNT_parse_table[] = {
+static const ahc_reg_parse_entry_t SCBCNT_parse_table[] = {
{ "SCBAUTO", 0x80, 0x80 },
{ "SCBCNT_MASK", 0x1f, 0x1f }
};
@@ -1231,20 +1149,13 @@ ahc_qinfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
}
int
-ahc_qincnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "QINCNT",
- 0x9c, regvalue, cur_col, wrap));
-}
-
-int
ahc_qoutfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahc_print_register(NULL, 0, "QOUTFIFO",
0x9d, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t CRCCONTROL1_parse_table[] = {
+static const ahc_reg_parse_entry_t CRCCONTROL1_parse_table[] = {
{ "TARGCRCCNTEN", 0x04, 0x04 },
{ "TARGCRCENDEN", 0x08, 0x08 },
{ "CRCREQCHKEN", 0x10, 0x10 },
@@ -1260,14 +1171,7 @@ ahc_crccontrol1_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x9d, regvalue, cur_col, wrap));
}
-int
-ahc_qoutcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "QOUTCNT",
- 0x9e, regvalue, cur_col, wrap));
-}
-
-static ahc_reg_parse_entry_t SCSIPHASE_parse_table[] = {
+static const ahc_reg_parse_entry_t SCSIPHASE_parse_table[] = {
{ "DATA_OUT_PHASE", 0x01, 0x01 },
{ "DATA_IN_PHASE", 0x02, 0x02 },
{ "MSG_OUT_PHASE", 0x04, 0x04 },
@@ -1284,7 +1188,7 @@ ahc_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
0x9e, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SFUNCT_parse_table[] = {
+static const ahc_reg_parse_entry_t SFUNCT_parse_table[] = {
{ "ALT_MODE", 0x80, 0x80 }
};
@@ -1351,7 +1255,7 @@ ahc_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xac, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
+static const ahc_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
{ "SG_LAST_SEG", 0x80, 0x80 },
{ "SG_HIGH_ADDR_BITS", 0x7f, 0x7f }
};
@@ -1363,7 +1267,7 @@ ahc_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xb0, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
+static const ahc_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
{ "SG_LIST_NULL", 0x01, 0x01 },
{ "SG_FULL_RESID", 0x02, 0x02 },
{ "SG_RESID_VALID", 0x04, 0x04 }
@@ -1376,7 +1280,7 @@ ahc_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xb4, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
+static const ahc_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
{ "DISCONNECTED", 0x04, 0x04 },
{ "ULTRAENB", 0x08, 0x08 },
{ "MK_MESSAGE", 0x10, 0x10 },
@@ -1394,7 +1298,7 @@ ahc_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xb8, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
+static const ahc_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
{ "TWIN_CHNLB", 0x80, 0x80 },
{ "OID", 0x0f, 0x0f },
{ "TWIN_TID", 0x70, 0x70 },
@@ -1408,7 +1312,7 @@ ahc_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xb9, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SCB_LUN_parse_table[] = {
+static const ahc_reg_parse_entry_t SCB_LUN_parse_table[] = {
{ "SCB_XFERLEN_ODD", 0x80, 0x80 },
{ "LID", 0x3f, 0x3f }
};
@@ -1455,14 +1359,7 @@ ahc_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xbf, regvalue, cur_col, wrap));
}
-int
-ahc_scb_64_spare_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
- return (ahc_print_register(NULL, 0, "SCB_64_SPARE",
- 0xc0, regvalue, cur_col, wrap));
-}
-
-static ahc_reg_parse_entry_t SEECTL_2840_parse_table[] = {
+static const ahc_reg_parse_entry_t SEECTL_2840_parse_table[] = {
{ "DO_2840", 0x01, 0x01 },
{ "CK_2840", 0x02, 0x02 },
{ "CS_2840", 0x04, 0x04 }
@@ -1475,7 +1372,7 @@ ahc_seectl_2840_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xc0, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t STATUS_2840_parse_table[] = {
+static const ahc_reg_parse_entry_t STATUS_2840_parse_table[] = {
{ "DI_2840", 0x01, 0x01 },
{ "EEPROM_TF", 0x80, 0x80 },
{ "ADSEL", 0x1e, 0x1e },
@@ -1524,7 +1421,7 @@ ahc_ccsgaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xea, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t CCSGCTL_parse_table[] = {
+static const ahc_reg_parse_entry_t CCSGCTL_parse_table[] = {
{ "CCSGRESET", 0x01, 0x01 },
{ "SG_FETCH_NEEDED", 0x02, 0x02 },
{ "CCSGEN", 0x08, 0x08 },
@@ -1552,7 +1449,7 @@ ahc_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xed, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t CCSCBCTL_parse_table[] = {
+static const ahc_reg_parse_entry_t CCSCBCTL_parse_table[] = {
{ "CCSCBRESET", 0x01, 0x01 },
{ "CCSCBDIR", 0x04, 0x04 },
{ "CCSCBEN", 0x08, 0x08 },
@@ -1610,7 +1507,7 @@ ahc_sdscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xf8, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
+static const ahc_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
{ "SDSCB_ROLLOVER", 0x10, 0x10 },
{ "SNSCB_ROLLOVER", 0x20, 0x20 },
{ "SCB_AVAIL", 0x40, 0x40 },
@@ -1625,7 +1522,7 @@ ahc_qoff_ctlsta_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xfa, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t DFF_THRSH_parse_table[] = {
+static const ahc_reg_parse_entry_t DFF_THRSH_parse_table[] = {
{ "RD_DFTHRSH_MIN", 0x00, 0x00 },
{ "WR_DFTHRSH_MIN", 0x00, 0x00 },
{ "RD_DFTHRSH_25", 0x01, 0x01 },
@@ -1653,7 +1550,7 @@ ahc_dff_thrsh_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xfb, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
+static const ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
{ "LAST_SEG_DONE", 0x01, 0x01 },
{ "LAST_SEG", 0x02, 0x02 },
{ "SG_ADDR_MASK", 0xf8, 0xf8 }
@@ -1666,7 +1563,7 @@ ahc_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap)
0xfc, regvalue, cur_col, wrap));
}
-static ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
+static const ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
{ "LAST_SEG_DONE", 0x01, 0x01 },
{ "LAST_SEG", 0x02, 0x02 },
{ "SG_ADDR_MASK", 0xf8, 0xf8 }
diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
index 4cee08521e75..07e93fbae706 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
@@ -5,7 +5,7 @@
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
*/
-static uint8_t seqprog[] = {
+static const uint8_t seqprog[] = {
0xb2, 0x00, 0x00, 0x08,
0xf7, 0x11, 0x22, 0x08,
0x00, 0x65, 0xee, 0x59,
@@ -1081,7 +1081,7 @@ ahc_patch0_func(struct ahc_softc *ahc)
return (0);
}
-static struct patch {
+static const struct patch {
ahc_patch_func_t *patch_func;
uint32_t begin :10,
skip_instr :10,
@@ -1291,7 +1291,7 @@ static struct patch {
{ ahc_patch4_func, 865, 12, 1 }
};
-static struct cs {
+static const struct cs {
uint16_t begin;
uint16_t end;
} critical_sections[] = {
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c
index 924102720b14..e4a778720301 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm.c
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c
@@ -362,7 +362,7 @@ output_code()
" *\n"
"%s */\n", versions);
- fprintf(ofile, "static uint8_t seqprog[] = {\n");
+ fprintf(ofile, "static const uint8_t seqprog[] = {\n");
for (cur_instr = STAILQ_FIRST(&seq_program);
cur_instr != NULL;
cur_instr = STAILQ_NEXT(cur_instr, links)) {
@@ -415,7 +415,7 @@ output_code()
}
fprintf(ofile,
-"static struct patch {\n"
+"static const struct patch {\n"
" %spatch_func_t *patch_func;\n"
" uint32_t begin :10,\n"
" skip_instr :10,\n"
@@ -435,7 +435,7 @@ output_code()
fprintf(ofile, "\n};\n\n");
fprintf(ofile,
-"static struct cs {\n"
+"static const struct cs {\n"
" uint16_t begin;\n"
" uint16_t end;\n"
"} critical_sections[] = {\n");
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
index 702e2dbd11fb..81be6a261cc8 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
@@ -101,11 +101,12 @@ static void format_3_instr(int opcode, symbol_ref_t *src,
expression_t *immed, symbol_ref_t *address);
static void test_readable_symbol(symbol_t *symbol);
static void test_writable_symbol(symbol_t *symbol);
-static void type_check(symbol_t *symbol, expression_t *expression, int and_op);
+static void type_check(symbol_ref_t *sym, expression_t *expression, int and_op);
static void make_expression(expression_t *immed, int value);
static void add_conditional(symbol_t *symbol);
static void add_version(const char *verstring);
static int is_download_const(expression_t *immed);
+static int is_location_address(symbol_t *symbol);
void yyerror(const char *string);
#define SRAM_SYMNAME "SRAM_BASE"
@@ -142,6 +143,8 @@ void yyerror(const char *string);
%token <value> T_ADDRESS
+%token T_COUNT
+
%token T_ACCESS_MODE
%token T_MODES
@@ -192,10 +195,10 @@ void yyerror(const char *string);
%token <value> T_OR
-/* 16 bit extensions */
-%token <value> T_OR16 T_AND16 T_XOR16 T_ADD16
-%token <value> T_ADC16 T_MVI16 T_TEST16 T_CMP16 T_CMPXCHG
-
+/* 16 bit extensions, not implemented
+ * %token <value> T_OR16 T_AND16 T_XOR16 T_ADD16
+ * %token <value> T_ADC16 T_MVI16 T_TEST16 T_CMP16 T_CMPXCHG
+ */
%token T_RET
%token T_NOP
@@ -214,7 +217,7 @@ void yyerror(const char *string);
%type <expression> expression immediate immediate_or_a
-%type <value> export ret f1_opcode f2_opcode f4_opcode jmp_jc_jnc_call jz_jnz je_jne
+%type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
%type <value> mode_value mode_list macro_arglist
@@ -313,13 +316,13 @@ reg_definition:
stop("Register multiply defined", EX_DATAERR);
/* NOTREACHED */
}
- cur_symbol = $1;
+ cur_symbol = $1;
cur_symbol->type = cur_symtype;
initialize_symbol(cur_symbol);
}
reg_attribute_list
'}'
- {
+ {
/*
* Default to allowing everything in for registers
* with no bit or mask definitions.
@@ -349,9 +352,10 @@ reg_attribute_list:
| reg_attribute_list reg_attribute
;
-reg_attribute:
+reg_attribute:
reg_address
| size
+| count
| access_mode
| modes
| field_defn
@@ -392,6 +396,13 @@ size:
}
;
+count:
+ T_COUNT T_NUMBER
+ {
+ cur_symbol->count += $2;
+ }
+;
+
access_mode:
T_ACCESS_MODE T_MODE
{
@@ -641,14 +652,14 @@ expression:
&($1.referenced_syms),
&($3.referenced_syms));
}
-| expression T_EXPR_LSHIFT expression
+| expression T_EXPR_LSHIFT expression
{
$$.value = $1.value << $3.value;
symlist_merge(&$$.referenced_syms,
&$1.referenced_syms,
&$3.referenced_syms);
}
-| expression T_EXPR_RSHIFT expression
+| expression T_EXPR_RSHIFT expression
{
$$.value = $1.value >> $3.value;
symlist_merge(&$$.referenced_syms,
@@ -714,7 +725,7 @@ expression:
;
constant:
- T_CONST T_SYMBOL expression
+ T_CONST T_SYMBOL expression
{
if ($2->type != UNINITIALIZED) {
stop("Re-definition of symbol as a constant",
@@ -800,6 +811,7 @@ scratch_ram:
cur_symtype = SRAMLOC;
cur_symbol->type = SRAMLOC;
initialize_symbol(cur_symbol);
+ cur_symbol->count += 1;
}
reg_address
{
@@ -831,6 +843,7 @@ scb:
initialize_symbol(cur_symbol);
/* 64 bytes of SCB space */
cur_symbol->info.rinfo->size = 64;
+ cur_symbol->count += 1;
}
reg_address
{
@@ -1311,14 +1324,18 @@ f2_opcode:
| T_ROR { $$ = AIC_OP_ROR; }
;
-f4_opcode:
- T_OR16 { $$ = AIC_OP_OR16; }
-| T_AND16 { $$ = AIC_OP_AND16; }
-| T_XOR16 { $$ = AIC_OP_XOR16; }
-| T_ADD16 { $$ = AIC_OP_ADD16; }
-| T_ADC16 { $$ = AIC_OP_ADC16; }
-| T_MVI16 { $$ = AIC_OP_MVI16; }
-;
+/*
+ * 16bit opcodes, not used
+ *
+ *f4_opcode:
+ * T_OR16 { $$ = AIC_OP_OR16; }
+ *| T_AND16 { $$ = AIC_OP_AND16; }
+ *| T_XOR16 { $$ = AIC_OP_XOR16; }
+ *| T_ADD16 { $$ = AIC_OP_ADD16; }
+ *| T_ADC16 { $$ = AIC_OP_ADC16; }
+ *| T_MVI16 { $$ = AIC_OP_MVI16; }
+ *;
+ */
code:
f2_opcode destination ',' expression opt_source ret ';'
@@ -1357,6 +1374,7 @@ code:
code:
T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
{
+ type_check(&$2, &$4, AIC_OP_OR);
format_3_instr($5, &$2, &$4, &$6);
}
;
@@ -1528,7 +1546,7 @@ initialize_symbol(symbol_t *symbol)
sizeof(struct cond_info));
break;
case MACRO:
- symbol->info.macroinfo =
+ symbol->info.macroinfo =
(struct macro_info *)malloc(sizeof(struct macro_info));
if (symbol->info.macroinfo == NULL) {
stop("Can't create macro info", EX_SOFTWARE);
@@ -1552,7 +1570,6 @@ add_macro_arg(const char *argtext, int argnum)
struct macro_arg *marg;
int i;
int retval;
-
if (cur_symbol == NULL || cur_symbol->type != MACRO) {
stop("Invalid current symbol for adding macro arg",
@@ -1633,8 +1650,10 @@ format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed,
test_writable_symbol(dest->symbol);
test_readable_symbol(src->symbol);
- /* Ensure that immediate makes sense for this destination */
- type_check(dest->symbol, immed, opcode);
+ if (!is_location_address(dest->symbol)) {
+ /* Ensure that immediate makes sense for this destination */
+ type_check(dest, immed, opcode);
+ }
/* Allocate sequencer space for the instruction and fill it out */
instr = seq_alloc();
@@ -1766,9 +1785,6 @@ format_3_instr(int opcode, symbol_ref_t *src,
/* Test register permissions */
test_readable_symbol(src->symbol);
- /* Ensure that immediate makes sense for this source */
- type_check(src->symbol, immed, opcode);
-
/* Allocate sequencer space for the instruction and fill it out */
instr = seq_alloc();
f3_instr = &instr->format.format3;
@@ -1797,7 +1813,6 @@ format_3_instr(int opcode, symbol_ref_t *src,
static void
test_readable_symbol(symbol_t *symbol)
{
-
if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) {
snprintf(errbuf, sizeof(errbuf),
"Register %s unavailable in source reg mode %d",
@@ -1815,7 +1830,6 @@ test_readable_symbol(symbol_t *symbol)
static void
test_writable_symbol(symbol_t *symbol)
{
-
if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) {
snprintf(errbuf, sizeof(errbuf),
"Register %s unavailable in destination reg mode %d",
@@ -1831,25 +1845,34 @@ test_writable_symbol(symbol_t *symbol)
}
static void
-type_check(symbol_t *symbol, expression_t *expression, int opcode)
+type_check(symbol_ref_t *sym, expression_t *expression, int opcode)
{
+ symbol_t *symbol = sym->symbol;
symbol_node_t *node;
int and_op;
+ int8_t value, mask;
and_op = FALSE;
- if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || opcode == AIC_OP_JZ)
- and_op = TRUE;
-
/*
* Make sure that we aren't attempting to write something
* that hasn't been defined. If this is an and operation,
* this is a mask, so "undefined" bits are okay.
*/
- if (and_op == FALSE
- && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
+ if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ ||
+ opcode == AIC_OP_JZ || opcode == AIC_OP_JNE ||
+ opcode == AIC_OP_BMOV)
+ and_op = TRUE;
+
+ /*
+ * Defaulting to 8 bit logic
+ */
+ mask = (int8_t)~symbol->info.rinfo->valid_bitmask;
+ value = (int8_t)expression->value;
+
+ if (and_op == FALSE && (mask & value) != 0 ) {
snprintf(errbuf, sizeof(errbuf),
"Invalid bit(s) 0x%x in immediate written to %s",
- expression->value & ~symbol->info.rinfo->valid_bitmask,
+ (mask & value),
symbol->name);
stop(errbuf, EX_DATAERR);
/* NOTREACHED */
@@ -1959,3 +1982,13 @@ is_download_const(expression_t *immed)
return (FALSE);
}
+
+static int
+is_location_address(symbol_t *sym)
+{
+ if (sym->type == SCBLOC ||
+ sym->type == SRAMLOC)
+ return (TRUE);
+ return (FALSE);
+}
+
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
index 7c3983f868a9..2c7f02daf88d 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
@@ -162,6 +162,7 @@ register { return T_REGISTER; }
const { yylval.value = FALSE; return T_CONST; }
download { return T_DOWNLOAD; }
address { return T_ADDRESS; }
+count { return T_COUNT; }
access_mode { return T_ACCESS_MODE; }
modes { return T_MODES; }
RW|RO|WO {
@@ -228,15 +229,15 @@ ret { return T_RET; }
nop { return T_NOP; }
/* ARP2 16bit extensions */
-or16 { return T_OR16; }
-and16 { return T_AND16; }
-xor16 { return T_XOR16; }
-add16 { return T_ADD16; }
-adc16 { return T_ADC16; }
-mvi16 { return T_MVI16; }
-test16 { return T_TEST16; }
-cmp16 { return T_CMP16; }
-cmpxchg { return T_CMPXCHG; }
+ /* or16 { return T_OR16; } */
+ /* and16 { return T_AND16; }*/
+ /* xor16 { return T_XOR16; }*/
+ /* add16 { return T_ADD16; }*/
+ /* adc16 { return T_ADC16; }*/
+ /* mvi16 { return T_MVI16; }*/
+ /* test16 { return T_TEST16; }*/
+ /* cmp16 { return T_CMP16; }*/
+ /* cmpxchg { return T_CMPXCHG; }*/
/* Allowed Symbols */
\<\< { return T_EXPR_LSHIFT; }
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
index f1f448dff569..fcd357872b43 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
@@ -77,6 +77,7 @@ symbol_create(char *name)
if (new_symbol->name == NULL)
stop("Unable to strdup symbol name", EX_SOFTWARE);
new_symbol->type = UNINITIALIZED;
+ new_symbol->count = 1;
return (new_symbol);
}
@@ -198,6 +199,12 @@ symtable_get(char *name)
}
}
memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
+ stored_ptr->count++;
+ data.data = &stored_ptr;
+ if (symtable->put(symtable, &key, &data, /*flags*/0) !=0) {
+ perror("Symtable put failed");
+ exit(EX_SOFTWARE);
+ }
return (stored_ptr);
}
@@ -256,7 +263,7 @@ symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
&& (curnode->symbol->info.finfo->value >
newnode->symbol->info.finfo->value))))
|| (!field && (curnode->symbol->info.rinfo->address >
- newnode->symbol->info.rinfo->address))) {
+ newnode->symbol->info.rinfo->address))) {
SLIST_INSERT_HEAD(symlist, newnode, links);
return;
}
@@ -271,7 +278,7 @@ symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
cursymbol = SLIST_NEXT(curnode, links)->symbol;
if ((field
- && (cursymbol->type > symbol->type
+ && (cursymbol->type > symbol->type
|| (cursymbol->type == symbol->type
&& (cursymbol->info.finfo->value >
symbol->info.finfo->value))))
@@ -351,7 +358,7 @@ aic_print_reg_dump_types(FILE *ofile)
{
if (ofile == NULL)
return;
-
+
fprintf(ofile,
"typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n"
"typedef struct %sreg_parse_entry {\n"
@@ -370,7 +377,7 @@ aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode)
return;
fprintf(dfile,
-"static %sreg_parse_entry_t %s_parse_table[] = {\n",
+"static const %sreg_parse_entry_t %s_parse_table[] = {\n",
prefix,
regnode->symbol->name);
}
@@ -385,7 +392,7 @@ aic_print_reg_dump_end(FILE *ofile, FILE *dfile,
lower_name = strdup(regnode->symbol->name);
if (lower_name == NULL)
stop("Unable to strdup symbol name", EX_SOFTWARE);
-
+
for (letter = lower_name; *letter != '\0'; letter++)
*letter = tolower(*letter);
@@ -472,6 +479,7 @@ symtable_dump(FILE *ofile, FILE *dfile)
DBT key;
DBT data;
int flag;
+ int reg_count = 0, reg_used = 0;
u_int i;
if (symtable == NULL)
@@ -541,6 +549,9 @@ symtable_dump(FILE *ofile, FILE *dfile)
int num_entries;
num_entries = 0;
+ reg_count++;
+ if (curnode->symbol->count == 1)
+ break;
fields = &curnode->symbol->info.rinfo->fields;
SLIST_FOREACH(fieldnode, fields, links) {
if (num_entries == 0)
@@ -553,11 +564,14 @@ symtable_dump(FILE *ofile, FILE *dfile)
}
aic_print_reg_dump_end(ofile, dfile,
curnode, num_entries);
+ reg_used++;
}
default:
break;
}
}
+ fprintf(stderr, "%s: %d of %d register definitions used\n", appname,
+ reg_used, reg_count);
/* Fold in the masks and bits */
while (SLIST_FIRST(&masks) != NULL) {
@@ -646,7 +660,6 @@ symtable_dump(FILE *ofile, FILE *dfile)
free(curnode);
}
-
fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
index afc22e8b4903..05190c1a2fb7 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
@@ -128,6 +128,7 @@ typedef struct expression_info {
typedef struct symbol {
char *name;
symtype type;
+ int count;
union {
struct reg_info *rinfo;
struct field_info *finfo;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index c9dd8392aab2..ac92ac143b46 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(adpt_post_wait_lock);
static u8 adpt_read_blink_led(adpt_hba* host)
{
- if(host->FwDebugBLEDflag_P != 0) {
+ if (host->FwDebugBLEDflag_P) {
if( readb(host->FwDebugBLEDflag_P) == 0xbc ){
return readb(host->FwDebugBLEDvalue_P);
}
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 8be3d76656fa..a73a6bbb1b2b 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -2286,17 +2286,14 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec,
}
}
-static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
+static irqreturn_t ihdlr(struct Scsi_Host *shost)
{
struct scsi_cmnd *SCpnt;
unsigned int i, k, c, status, tstatus, reg;
struct mssp *spp;
struct mscp *cpp;
struct hostdata *ha = (struct hostdata *)shost->hostdata;
-
- if (shost->irq != irq)
- panic("%s: ihdlr, irq %d, shost->irq %d.\n", ha->board_name, irq,
- shost->irq);
+ int irq = shost->irq;
/* Check if this board need to be serviced */
if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED))
@@ -2535,7 +2532,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
return IRQ_NONE;
}
-static irqreturn_t do_interrupt_handler(int irq, void *shap)
+static irqreturn_t do_interrupt_handler(int dummy, void *shap)
{
struct Scsi_Host *shost;
unsigned int j;
@@ -2548,7 +2545,7 @@ static irqreturn_t do_interrupt_handler(int irq, void *shap)
shost = sh[j];
spin_lock_irqsave(shost->host_lock, spin_flags);
- ret = ihdlr(irq, shost);
+ ret = ihdlr(shost);
spin_unlock_irqrestore(shost->host_lock, spin_flags);
return ret;
}
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index bfdee5968892..a0b6d414953d 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -978,7 +978,7 @@ static int esp_check_spur_intr(struct esp *esp)
*/
if (!esp->ops->dma_error(esp)) {
printk(KERN_ERR PFX "esp%d: Spurious irq, "
- "sreg=%x.\n",
+ "sreg=%02x.\n",
esp->host->unique_id, esp->sreg);
return -1;
}
@@ -1447,6 +1447,9 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
if (offset > 15)
goto do_reject;
+ if (esp->flags & ESP_FLAG_DISABLE_SYNC)
+ offset = 0;
+
if (offset) {
int rounded_up, one_clock;
@@ -1697,7 +1700,12 @@ again:
else
ent->flags &= ~ESP_CMD_FLAG_WRITE;
- dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
+ if (esp->ops->dma_length_limit)
+ dma_len = esp->ops->dma_length_limit(esp, dma_addr,
+ dma_len);
+ else
+ dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
+
esp->data_dma_len = dma_len;
if (!dma_len) {
@@ -1761,7 +1769,6 @@ again:
esp_advance_dma(esp, ent, cmd, bytes_sent);
esp_event(esp, ESP_EVENT_CHECK_PHASE);
goto again;
- break;
}
case ESP_EVENT_STATUS: {
@@ -2235,7 +2242,7 @@ static void esp_bootup_reset(struct esp *esp)
static void esp_set_clock_params(struct esp *esp)
{
- int fmhz;
+ int fhz;
u8 ccf;
/* This is getting messy but it has to be done correctly or else
@@ -2270,9 +2277,9 @@ static void esp_set_clock_params(struct esp *esp)
* This entails the smallest and largest sync period we could ever
* handle on this ESP.
*/
- fmhz = esp->cfreq;
+ fhz = esp->cfreq;
- ccf = ((fmhz / 1000000) + 4) / 5;
+ ccf = ((fhz / 1000000) + 4) / 5;
if (ccf == 1)
ccf = 2;
@@ -2281,16 +2288,16 @@ static void esp_set_clock_params(struct esp *esp)
* been unable to find the clock-frequency PROM property. All
* other machines provide useful values it seems.
*/
- if (fmhz <= 5000000 || ccf < 1 || ccf > 8) {
- fmhz = 20000000;
+ if (fhz <= 5000000 || ccf < 1 || ccf > 8) {
+ fhz = 20000000;
ccf = 4;
}
esp->cfact = (ccf == 8 ? 0 : ccf);
- esp->cfreq = fmhz;
- esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+ esp->cfreq = fhz;
+ esp->ccycle = ESP_HZ_TO_CYCLE(fhz);
esp->ctick = ESP_TICK(ccf, esp->ccycle);
- esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+ esp->neg_defp = ESP_NEG_DEFP(fhz, ccf);
esp->sync_defp = SYNC_DEFP_SLOW;
}
@@ -2382,6 +2389,12 @@ static int esp_slave_configure(struct scsi_device *dev)
struct esp_target_data *tp = &esp->target[dev->id];
int goal_tags, queue_depth;
+ if (esp->flags & ESP_FLAG_DISABLE_SYNC) {
+ /* Bypass async domain validation */
+ dev->ppr = 0;
+ dev->sdtr = 0;
+ }
+
goal_tags = 0;
if (dev->tagged_supported) {
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index d5576d54ce76..bb43a1388188 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -224,7 +224,7 @@
#define ESP_TIMEO_CONST 8192
#define ESP_NEG_DEFP(mhz, cfact) \
((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
-#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
+#define ESP_HZ_TO_CYCLE(hertz) ((1000000000) / ((hertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high
@@ -240,9 +240,9 @@ struct esp_cmd_priv {
int num_sg;
} u;
- unsigned int cur_residue;
+ int cur_residue;
struct scatterlist *cur_sg;
- unsigned int tot_residue;
+ int tot_residue;
};
#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp))
@@ -368,6 +368,12 @@ struct esp_driver_ops {
*/
int (*irq_pending)(struct esp *esp);
+ /* Return the maximum allowable size of a DMA transfer for a
+ * given buffer.
+ */
+ u32 (*dma_length_limit)(struct esp *esp, u32 dma_addr,
+ u32 dma_len);
+
/* Reset the DMA engine entirely. On return, ESP interrupts
* should be enabled. Often the interrupt enabling is
* controlled in the DMA engine.
@@ -471,6 +477,7 @@ struct esp {
#define ESP_FLAG_DOING_SLOWCMD 0x00000004
#define ESP_FLAG_WIDE_CAPABLE 0x00000008
#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
+#define ESP_FLAG_DISABLE_SYNC 0x00000020
u8 select_state;
#define ESP_SELECT_NONE 0x00 /* Not selecting */
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 2cd6b4959eb2..c33bcb284df7 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1443,7 +1443,7 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
} else {
- current_SC->SCp.ptr = 0;
+ current_SC->SCp.ptr = NULL;
current_SC->SCp.this_residual = 0;
current_SC->SCp.buffer = NULL;
current_SC->SCp.buffers_residual = 0;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index c264a8c5f01e..3690360d7a79 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -199,9 +199,13 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
if (!shost->can_queue) {
printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
sht->name);
- goto out;
+ goto fail;
}
+ error = scsi_setup_command_freelist(shost);
+ if (error)
+ goto fail;
+
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &platform_bus;
@@ -255,6 +259,8 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
out_del_gendev:
device_del(&shost->shost_gendev);
out:
+ scsi_destroy_command_freelist(shost);
+ fail:
return error;
}
EXPORT_SYMBOL(scsi_add_host);
@@ -284,6 +290,11 @@ static void scsi_host_dev_release(struct device *dev)
kfree(shost);
}
+struct device_type scsi_host_type = {
+ .name = "scsi_host",
+ .release = scsi_host_dev_release,
+};
+
/**
* scsi_host_alloc - register a scsi host adapter instance.
* @sht: pointer to scsi host template
@@ -376,33 +387,31 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
else
shost->dma_boundary = 0xffffffff;
- rval = scsi_setup_command_freelist(shost);
- if (rval)
- goto fail_kfree;
-
device_initialize(&shost->shost_gendev);
snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
- shost->shost_gendev.release = scsi_host_dev_release;
+#ifndef CONFIG_SYSFS_DEPRECATED
+ shost->shost_gendev.bus = &scsi_bus_type;
+#endif
+ shost->shost_gendev.type = &scsi_host_type;
device_initialize(&shost->shost_dev);
shost->shost_dev.parent = &shost->shost_gendev;
shost->shost_dev.class = &shost_class;
snprintf(shost->shost_dev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
+ shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
shost->ehandler = kthread_run(scsi_error_handler, shost,
"scsi_eh_%d", shost->host_no);
if (IS_ERR(shost->ehandler)) {
rval = PTR_ERR(shost->ehandler);
- goto fail_destroy_freelist;
+ goto fail_kfree;
}
scsi_proc_hostdir_add(shost->hostt);
return shost;
- fail_destroy_freelist:
- scsi_destroy_command_freelist(shost);
fail_kfree:
kfree(shost);
return NULL;
@@ -496,7 +505,7 @@ void scsi_exit_hosts(void)
int scsi_is_host_device(const struct device *dev)
{
- return dev->release == scsi_host_dev_release;
+ return dev->type == &scsi_host_type;
}
EXPORT_SYMBOL(scsi_is_host_device);
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 93c3fc20aa59..44d8d5163a1a 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -134,6 +134,7 @@ static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive)
static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
unsigned int bcount)
{
+ ide_hwif_t *hwif = drive->hwif;
int count;
char *buf;
@@ -145,14 +146,12 @@ static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
local_irq_save(flags);
buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
pc->sg->offset;
- drive->hwif->atapi_input_bytes(drive,
- buf + pc->b_count, count);
+ hwif->input_data(drive, NULL, buf + pc->b_count, count);
kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = sg_virt(pc->sg);
- drive->hwif->atapi_input_bytes(drive,
- buf + pc->b_count, count);
+ hwif->input_data(drive, NULL, buf + pc->b_count, count);
}
bcount -= count; pc->b_count += count;
if (pc->b_count == pc->sg->length) {
@@ -165,13 +164,14 @@ static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
if (bcount) {
printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
- ide_atapi_discard_data(drive, bcount);
+ ide_pad_transfer(drive, 0, bcount);
}
}
static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
unsigned int bcount)
{
+ ide_hwif_t *hwif = drive->hwif;
int count;
char *buf;
@@ -183,14 +183,12 @@ static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
local_irq_save(flags);
buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
pc->sg->offset;
- drive->hwif->atapi_output_bytes(drive,
- buf + pc->b_count, count);
+ hwif->output_data(drive, NULL, buf + pc->b_count, count);
kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = sg_virt(pc->sg);
- drive->hwif->atapi_output_bytes(drive,
- buf + pc->b_count, count);
+ hwif->output_data(drive, NULL, buf + pc->b_count, count);
}
bcount -= count; pc->b_count += count;
if (pc->b_count == pc->sg->length) {
@@ -203,7 +201,7 @@ static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
if (bcount) {
printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
- ide_atapi_write_zeros(drive, bcount);
+ ide_pad_transfer(drive, 1, bcount);
}
}
@@ -258,8 +256,8 @@ idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
/* force an abort */
- hwif->OUTB(WIN_IDLEIMMEDIATE,
- hwif->io_ports[IDE_COMMAND_OFFSET]);
+ hwif->OUTBSYNC(drive, WIN_IDLEIMMEDIATE,
+ hwif->io_ports.command_addr);
rq->errors++;
@@ -393,7 +391,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
printk ("ide-scsi: %s: DMA complete\n", drive->name);
#endif /* IDESCSI_DEBUG_LOG */
pc->xferred = pc->req_xfer;
- (void) HWIF(drive)->ide_dma_end(drive);
+ (void)hwif->dma_ops->dma_end(drive);
}
/* Clear the interrupt */
@@ -410,9 +408,9 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
idescsi_end_request (drive, 1, 0);
return ide_stopped;
}
- bcount = (hwif->INB(hwif->io_ports[IDE_BCOUNTH_OFFSET]) << 8) |
- hwif->INB(hwif->io_ports[IDE_BCOUNTL_OFFSET]);
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) |
+ hwif->INB(hwif->io_ports.lbam_addr);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if (ireason & CD) {
printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
@@ -432,14 +430,15 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
idescsi_input_buffers(drive, pc,
temp);
else
- drive->hwif->atapi_input_bytes(drive, pc->cur_pos, temp);
+ hwif->input_data(drive, NULL,
+ pc->cur_pos, temp);
printk(KERN_ERR "ide-scsi: transferred"
" %d of %d bytes\n",
temp, bcount);
}
pc->xferred += temp;
pc->cur_pos += temp;
- ide_atapi_discard_data(drive, bcount - temp);
+ ide_pad_transfer(drive, 0, bcount - temp);
ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
return ide_started;
}
@@ -453,15 +452,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
if (pc->sg)
idescsi_input_buffers(drive, pc, bcount);
else
- hwif->atapi_input_bytes(drive, pc->cur_pos,
- bcount);
+ hwif->input_data(drive, NULL, pc->cur_pos, bcount);
} else {
pc->flags |= PC_FLAG_WRITING;
if (pc->sg)
idescsi_output_buffers(drive, pc, bcount);
else
- hwif->atapi_output_bytes(drive, pc->cur_pos,
- bcount);
+ hwif->output_data(drive, NULL, pc->cur_pos, bcount);
}
/* Update the current position */
pc->xferred += bcount;
@@ -485,7 +482,7 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
"initiated yet DRQ isn't asserted\n");
return startstop;
}
- ireason = hwif->INB(hwif->io_ports[IDE_IREASON_OFFSET]);
+ ireason = hwif->INB(hwif->io_ports.nsect_addr);
if ((ireason & CD) == 0 || (ireason & IO)) {
printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
"issuing a packet command\n");
@@ -494,11 +491,13 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
BUG_ON(HWGROUP(drive)->handler != NULL);
/* Set the interrupt routine */
ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
+
/* Send the actual packet */
- drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12);
+ hwif->output_data(drive, NULL, scsi->pc->c, 12);
+
if (pc->flags & PC_FLAG_DMA_OK) {
pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
- hwif->dma_start(drive);
+ hwif->dma_ops->dma_start(drive);
}
return ide_started;
}
@@ -560,7 +559,7 @@ static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive,
if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
hwif->sg_mapped = 1;
- dma = !hwif->dma_setup(drive);
+ dma = !hwif->dma_ops->dma_setup(drive);
hwif->sg_mapped = 0;
}
@@ -575,7 +574,7 @@ static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive,
return ide_started;
} else {
/* Issue the packet command */
- hwif->OUTB(WIN_PACKETCMD, hwif->io_ports[IDE_COMMAND_OFFSET]);
+ ide_execute_pkt_cmd(drive);
return idescsi_transfer_pc(drive);
}
}
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 5d231015bb20..b2d481dd3750 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -217,11 +217,15 @@ static int __devexit esp_jazz_remove(struct platform_device *dev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:jazz_esp");
+
static struct platform_driver esp_jazz_driver = {
.probe = esp_jazz_probe,
.remove = __devexit_p(esp_jazz_remove),
.driver = {
.name = "jazz_esp",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index a9fbb3f88659..960baaf11fb1 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -182,8 +182,8 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
}
static ssize_t
-lpfc_state_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
@@ -936,7 +936,7 @@ static DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);
static DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL);
static DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
static DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
-static DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL);
+static DEVICE_ATTR(link_state, S_IRUGO, lpfc_link_state_show, NULL);
static DEVICE_ATTR(option_rom_version, S_IRUGO,
lpfc_option_rom_version_show, NULL);
static DEVICE_ATTR(num_discovered_ports, S_IRUGO,
@@ -1666,7 +1666,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_fwrev,
&dev_attr_hdw,
&dev_attr_option_rom_version,
- &dev_attr_state,
+ &dev_attr_link_state,
&dev_attr_num_discovered_ports,
&dev_attr_lpfc_drvr_version,
&dev_attr_lpfc_temp_sensor,
@@ -1714,7 +1714,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_info,
- &dev_attr_state,
+ &dev_attr_link_state,
&dev_attr_num_discovered_ports,
&dev_attr_lpfc_drvr_version,
&dev_attr_lpfc_log_verbose,
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
new file mode 100644
index 000000000000..cd37bd69a115
--- /dev/null
+++ b/drivers/scsi/mac_esp.c
@@ -0,0 +1,657 @@
+/* mac_esp.c: ESP front-end for Macintosh Quadra systems.
+ *
+ * Adapted from jazz_esp.c and the old mac_esp.c.
+ *
+ * The pseudo DMA algorithm is based on the one used in NetBSD.
+ * See sys/arch/mac68k/obio/esp.c for some background information.
+ *
+ * Copyright (C) 2007-2008 Finn Thain
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/nubus.h>
+
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include <asm/macints.h>
+#include <asm/macintosh.h>
+
+#include <scsi/scsi_host.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME "mac_esp"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_VERSION "1.000"
+#define DRV_MODULE_RELDATE "Sept 15, 2007"
+
+#define MAC_ESP_IO_BASE 0x50F00000
+#define MAC_ESP_REGS_QUADRA (MAC_ESP_IO_BASE + 0x10000)
+#define MAC_ESP_REGS_QUADRA2 (MAC_ESP_IO_BASE + 0xF000)
+#define MAC_ESP_REGS_QUADRA3 (MAC_ESP_IO_BASE + 0x18000)
+#define MAC_ESP_REGS_SPACING 0x402
+#define MAC_ESP_PDMA_REG 0xF9800024
+#define MAC_ESP_PDMA_REG_SPACING 0x4
+#define MAC_ESP_PDMA_IO_OFFSET 0x100
+
+#define esp_read8(REG) mac_esp_read8(esp, REG)
+#define esp_write8(VAL, REG) mac_esp_write8(esp, VAL, REG)
+
+struct mac_esp_priv {
+ struct esp *esp;
+ void __iomem *pdma_regs;
+ void __iomem *pdma_io;
+ int error;
+};
+static struct platform_device *internal_esp, *external_esp;
+
+#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
+ platform_get_drvdata((struct platform_device *) \
+ (esp->dev)))
+
+static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg)
+{
+ nubus_writeb(val, esp->regs + reg * 16);
+}
+
+static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg)
+{
+ return nubus_readb(esp->regs + reg * 16);
+}
+
+/* For pseudo DMA and PIO we need the virtual address
+ * so this address mapping is the identity mapping.
+ */
+
+static dma_addr_t mac_esp_map_single(struct esp *esp, void *buf,
+ size_t sz, int dir)
+{
+ return (dma_addr_t)buf;
+}
+
+static int mac_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ int i;
+
+ for (i = 0; i < num_sg; i++)
+ sg[i].dma_address = (u32)sg_virt(&sg[i]);
+ return num_sg;
+}
+
+static void mac_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir)
+{
+ /* Nothing to do. */
+}
+
+static void mac_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ /* Nothing to do. */
+}
+
+static void mac_esp_reset_dma(struct esp *esp)
+{
+ /* Nothing to do. */
+}
+
+static void mac_esp_dma_drain(struct esp *esp)
+{
+ /* Nothing to do. */
+}
+
+static void mac_esp_dma_invalidate(struct esp *esp)
+{
+ /* Nothing to do. */
+}
+
+static int mac_esp_dma_error(struct esp *esp)
+{
+ return MAC_ESP_GET_PRIV(esp)->error;
+}
+
+static inline int mac_esp_wait_for_empty_fifo(struct esp *esp)
+{
+ struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
+ int i = 500000;
+
+ do {
+ if (!(esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES))
+ return 0;
+
+ if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
+ return 1;
+
+ udelay(2);
+ } while (--i);
+
+ printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n",
+ esp_read8(ESP_STATUS));
+ mep->error = 1;
+ return 1;
+}
+
+static inline int mac_esp_wait_for_dreq(struct esp *esp)
+{
+ struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
+ int i = 500000;
+
+ do {
+ if (mep->pdma_regs == NULL) {
+ if (mac_irq_pending(IRQ_MAC_SCSIDRQ))
+ return 0;
+ } else {
+ if (nubus_readl(mep->pdma_regs) & 0x200)
+ return 0;
+ }
+
+ if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
+ return 1;
+
+ udelay(2);
+ } while (--i);
+
+ printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n",
+ esp_read8(ESP_STATUS));
+ mep->error = 1;
+ return 1;
+}
+
+#define MAC_ESP_PDMA_LOOP(operands) \
+ asm volatile ( \
+ " tstw %2 \n" \
+ " jbeq 20f \n" \
+ "1: movew " operands " \n" \
+ "2: movew " operands " \n" \
+ "3: movew " operands " \n" \
+ "4: movew " operands " \n" \
+ "5: movew " operands " \n" \
+ "6: movew " operands " \n" \
+ "7: movew " operands " \n" \
+ "8: movew " operands " \n" \
+ "9: movew " operands " \n" \
+ "10: movew " operands " \n" \
+ "11: movew " operands " \n" \
+ "12: movew " operands " \n" \
+ "13: movew " operands " \n" \
+ "14: movew " operands " \n" \
+ "15: movew " operands " \n" \
+ "16: movew " operands " \n" \
+ " subqw #1,%2 \n" \
+ " jbne 1b \n" \
+ "20: tstw %3 \n" \
+ " jbeq 30f \n" \
+ "21: movew " operands " \n" \
+ " subqw #1,%3 \n" \
+ " jbne 21b \n" \
+ "30: tstw %4 \n" \
+ " jbeq 40f \n" \
+ "31: moveb " operands " \n" \
+ "32: nop \n" \
+ "40: \n" \
+ " \n" \
+ " .section __ex_table,\"a\" \n" \
+ " .align 4 \n" \
+ " .long 1b,40b \n" \
+ " .long 2b,40b \n" \
+ " .long 3b,40b \n" \
+ " .long 4b,40b \n" \
+ " .long 5b,40b \n" \
+ " .long 6b,40b \n" \
+ " .long 7b,40b \n" \
+ " .long 8b,40b \n" \
+ " .long 9b,40b \n" \
+ " .long 10b,40b \n" \
+ " .long 11b,40b \n" \
+ " .long 12b,40b \n" \
+ " .long 13b,40b \n" \
+ " .long 14b,40b \n" \
+ " .long 15b,40b \n" \
+ " .long 16b,40b \n" \
+ " .long 21b,40b \n" \
+ " .long 31b,40b \n" \
+ " .long 32b,40b \n" \
+ " .previous \n" \
+ : "+a" (addr) \
+ : "a" (mep->pdma_io), "r" (count32), "r" (count2), "g" (esp_count))
+
+static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
+{
+ struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ mep->error = 0;
+
+ if (!write)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ esp_write8((esp_count >> 0) & 0xFF, ESP_TCLOW);
+ esp_write8((esp_count >> 8) & 0xFF, ESP_TCMED);
+
+ scsi_esp_cmd(esp, cmd);
+
+ do {
+ unsigned int count32 = esp_count >> 5;
+ unsigned int count2 = (esp_count & 0x1F) >> 1;
+ unsigned int start_addr = addr;
+
+ if (mac_esp_wait_for_dreq(esp))
+ break;
+
+ if (write) {
+ MAC_ESP_PDMA_LOOP("%1@,%0@+");
+
+ esp_count -= addr - start_addr;
+ } else {
+ unsigned int n;
+
+ MAC_ESP_PDMA_LOOP("%0@+,%1@");
+
+ if (mac_esp_wait_for_empty_fifo(esp))
+ break;
+
+ n = (esp_read8(ESP_TCMED) << 8) + esp_read8(ESP_TCLOW);
+ addr = start_addr + esp_count - n;
+ esp_count = n;
+ }
+ } while (esp_count);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * Programmed IO routines follow.
+ */
+
+static inline int mac_esp_wait_for_fifo(struct esp *esp)
+{
+ int i = 500000;
+
+ do {
+ if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES)
+ return 0;
+
+ udelay(2);
+ } while (--i);
+
+ printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n",
+ esp_read8(ESP_STATUS));
+ return 1;
+}
+
+static inline int mac_esp_wait_for_intr(struct esp *esp)
+{
+ int i = 500000;
+
+ do {
+ esp->sreg = esp_read8(ESP_STATUS);
+ if (esp->sreg & ESP_STAT_INTR)
+ return 0;
+
+ udelay(2);
+ } while (--i);
+
+ printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg);
+ return 1;
+}
+
+#define MAC_ESP_PIO_LOOP(operands, reg1) \
+ asm volatile ( \
+ "1: moveb " operands " \n" \
+ " subqw #1,%1 \n" \
+ " jbne 1b \n" \
+ : "+a" (addr), "+r" (reg1) \
+ : "a" (fifo))
+
+#define MAC_ESP_PIO_FILL(operands, reg1) \
+ asm volatile ( \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " moveb " operands " \n" \
+ " subqw #8,%1 \n" \
+ " subqw #8,%1 \n" \
+ : "+a" (addr), "+r" (reg1) \
+ : "a" (fifo))
+
+#define MAC_ESP_FIFO_SIZE 16
+
+static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
+{
+ unsigned long flags;
+ struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
+ u8 *fifo = esp->regs + ESP_FDATA * 16;
+
+ local_irq_save(flags);
+
+ cmd &= ~ESP_CMD_DMA;
+ mep->error = 0;
+
+ if (write) {
+ scsi_esp_cmd(esp, cmd);
+
+ if (!mac_esp_wait_for_intr(esp)) {
+ if (mac_esp_wait_for_fifo(esp))
+ esp_count = 0;
+ } else {
+ esp_count = 0;
+ }
+ } else {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ if (esp_count >= MAC_ESP_FIFO_SIZE)
+ MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
+ else
+ MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);
+
+ scsi_esp_cmd(esp, cmd);
+ }
+
+ while (esp_count) {
+ unsigned int n;
+
+ if (mac_esp_wait_for_intr(esp)) {
+ mep->error = 1;
+ break;
+ }
+
+ if (esp->sreg & ESP_STAT_SPAM) {
+ printk(KERN_ERR PFX "gross error\n");
+ mep->error = 1;
+ break;
+ }
+
+ n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+
+ if (write) {
+ if (n > esp_count)
+ n = esp_count;
+ esp_count -= n;
+
+ MAC_ESP_PIO_LOOP("%2@,%0@+", n);
+
+ if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP)
+ break;
+
+ if (esp_count) {
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ESP_INTR_DC)
+ break;
+
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ }
+ } else {
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ESP_INTR_DC)
+ break;
+
+ n = MAC_ESP_FIFO_SIZE - n;
+ if (n > esp_count)
+ n = esp_count;
+
+ if (n == MAC_ESP_FIFO_SIZE) {
+ MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
+ } else {
+ esp_count -= n;
+ MAC_ESP_PIO_LOOP("%0@+,%2@", n);
+ }
+
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ }
+ }
+
+ local_irq_restore(flags);
+}
+
+static int mac_esp_irq_pending(struct esp *esp)
+{
+ if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
+ return 1;
+ return 0;
+}
+
+static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
+{
+ return dma_len > 0xFFFF ? 0xFFFF : dma_len;
+}
+
+static struct esp_driver_ops mac_esp_ops = {
+ .esp_write8 = mac_esp_write8,
+ .esp_read8 = mac_esp_read8,
+ .map_single = mac_esp_map_single,
+ .map_sg = mac_esp_map_sg,
+ .unmap_single = mac_esp_unmap_single,
+ .unmap_sg = mac_esp_unmap_sg,
+ .irq_pending = mac_esp_irq_pending,
+ .dma_length_limit = mac_esp_dma_length_limit,
+ .reset_dma = mac_esp_reset_dma,
+ .dma_drain = mac_esp_dma_drain,
+ .dma_invalidate = mac_esp_dma_invalidate,
+ .send_dma_cmd = mac_esp_send_pdma_cmd,
+ .dma_error = mac_esp_dma_error,
+};
+
+static int __devinit esp_mac_probe(struct platform_device *dev)
+{
+ struct scsi_host_template *tpnt = &scsi_esp_template;
+ struct Scsi_Host *host;
+ struct esp *esp;
+ int err;
+ int chips_present;
+ struct mac_esp_priv *mep;
+
+ if (!MACH_IS_MAC)
+ return -ENODEV;
+
+ switch (macintosh_config->scsi_type) {
+ case MAC_SCSI_QUADRA:
+ case MAC_SCSI_QUADRA3:
+ chips_present = 1;
+ break;
+ case MAC_SCSI_QUADRA2:
+ if ((macintosh_config->ident == MAC_MODEL_Q900) ||
+ (macintosh_config->ident == MAC_MODEL_Q950))
+ chips_present = 2;
+ else
+ chips_present = 1;
+ break;
+ default:
+ chips_present = 0;
+ }
+
+ if (dev->id + 1 > chips_present)
+ return -ENODEV;
+
+ host = scsi_host_alloc(tpnt, sizeof(struct esp));
+
+ err = -ENOMEM;
+ if (!host)
+ goto fail;
+
+ host->max_id = 8;
+ host->use_clustering = DISABLE_CLUSTERING;
+ esp = shost_priv(host);
+
+ esp->host = host;
+ esp->dev = dev;
+
+ esp->command_block = kzalloc(16, GFP_KERNEL);
+ if (!esp->command_block)
+ goto fail_unlink;
+ esp->command_block_dma = (dma_addr_t)esp->command_block;
+
+ esp->scsi_id = 7;
+ host->this_id = esp->scsi_id;
+ esp->scsi_id_mask = 1 << esp->scsi_id;
+
+ mep = kzalloc(sizeof(struct mac_esp_priv), GFP_KERNEL);
+ if (!mep)
+ goto fail_free_command_block;
+ mep->esp = esp;
+ platform_set_drvdata(dev, mep);
+
+ switch (macintosh_config->scsi_type) {
+ case MAC_SCSI_QUADRA:
+ esp->cfreq = 16500000;
+ esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA;
+ mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET;
+ mep->pdma_regs = NULL;
+ break;
+ case MAC_SCSI_QUADRA2:
+ esp->cfreq = 25000000;
+ esp->regs = (void __iomem *)(MAC_ESP_REGS_QUADRA2 +
+ dev->id * MAC_ESP_REGS_SPACING);
+ mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET;
+ mep->pdma_regs = (void __iomem *)(MAC_ESP_PDMA_REG +
+ dev->id * MAC_ESP_PDMA_REG_SPACING);
+ nubus_writel(0x1d1, mep->pdma_regs);
+ break;
+ case MAC_SCSI_QUADRA3:
+ /* These quadras have a real DMA controller (the PSC) but we
+ * don't know how to drive it so we must use PIO instead.
+ */
+ esp->cfreq = 25000000;
+ esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA3;
+ mep->pdma_io = NULL;
+ mep->pdma_regs = NULL;
+ break;
+ }
+
+ esp->ops = &mac_esp_ops;
+ if (mep->pdma_io == NULL) {
+ printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id);
+ esp_write8(0, ESP_TCLOW);
+ esp_write8(0, ESP_TCMED);
+ esp->flags = ESP_FLAG_DISABLE_SYNC;
+ mac_esp_ops.send_dma_cmd = mac_esp_send_pio_cmd;
+ } else {
+ printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id);
+ }
+
+ host->irq = IRQ_MAC_SCSI;
+ err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP",
+ esp);
+ if (err < 0)
+ goto fail_free_priv;
+
+ err = scsi_esp_register(esp, &dev->dev);
+ if (err)
+ goto fail_free_irq;
+
+ return 0;
+
+fail_free_irq:
+ free_irq(host->irq, esp);
+fail_free_priv:
+ kfree(mep);
+fail_free_command_block:
+ kfree(esp->command_block);
+fail_unlink:
+ scsi_host_put(host);
+fail:
+ return err;
+}
+
+static int __devexit esp_mac_remove(struct platform_device *dev)
+{
+ struct mac_esp_priv *mep = platform_get_drvdata(dev);
+ struct esp *esp = mep->esp;
+ unsigned int irq = esp->host->irq;
+
+ scsi_esp_unregister(esp);
+
+ free_irq(irq, esp);
+
+ kfree(mep);
+
+ kfree(esp->command_block);
+
+ scsi_host_put(esp->host);
+
+ return 0;
+}
+
+static struct platform_driver esp_mac_driver = {
+ .probe = esp_mac_probe,
+ .remove = __devexit_p(esp_mac_remove),
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ },
+};
+
+static int __init mac_esp_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&esp_mac_driver);
+ if (err)
+ return err;
+
+ internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0);
+ if (internal_esp && platform_device_add(internal_esp)) {
+ platform_device_put(internal_esp);
+ internal_esp = NULL;
+ }
+
+ external_esp = platform_device_alloc(DRV_MODULE_NAME, 1);
+ if (external_esp && platform_device_add(external_esp)) {
+ platform_device_put(external_esp);
+ external_esp = NULL;
+ }
+
+ if (internal_esp || external_esp) {
+ return 0;
+ } else {
+ platform_driver_unregister(&esp_mac_driver);
+ return -ENOMEM;
+ }
+}
+
+static void __exit mac_esp_exit(void)
+{
+ platform_driver_unregister(&esp_mac_driver);
+
+ if (internal_esp) {
+ platform_device_unregister(internal_esp);
+ internal_esp = NULL;
+ }
+ if (external_esp) {
+ platform_device_unregister(external_esp);
+ external_esp = NULL;
+ }
+}
+
+MODULE_DESCRIPTION("Mac ESP SCSI driver");
+MODULE_AUTHOR("Finn Thain <fthain@telegraphics.com.au>");
+MODULE_LICENSE("GPLv2");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(mac_esp_init);
+module_exit(mac_esp_exit);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index d89289400425..ceab4f73caf1 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8186,7 +8186,7 @@ static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd)
cmd->next_wcmd = NULL;
if (!(wcmd = np->waiting_list)) np->waiting_list = cmd;
else {
- while ((wcmd->next_wcmd) != 0)
+ while (wcmd->next_wcmd)
wcmd = (struct scsi_cmnd *) wcmd->next_wcmd;
wcmd->next_wcmd = (char *) cmd;
}
@@ -8222,7 +8222,7 @@ static void process_waiting_list(struct ncb *np, int sts)
#ifdef DEBUG_WAITING_LIST
if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
#endif
- while ((wcmd = waiting_list) != 0) {
+ while (wcmd = waiting_list) {
waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd;
wcmd->next_wcmd = NULL;
if (sts == DID_OK) {
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index d61df036910c..287690853caf 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -609,8 +609,8 @@ qla2x00_pci_info_show(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-qla2x00_state_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+qla2x00_link_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
int len = 0;
@@ -814,7 +814,7 @@ static DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
static DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
static DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
static DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
-static DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
+static DEVICE_ATTR(link_state, S_IRUGO, qla2x00_link_state_show, NULL);
static DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show, qla2x00_zio_store);
static DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
qla2x00_zio_timer_store);
@@ -838,7 +838,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_model_name,
&dev_attr_model_desc,
&dev_attr_pci_info,
- &dev_attr_state,
+ &dev_attr_link_state,
&dev_attr_zio,
&dev_attr_zio_timer,
&dev_attr_beacon,
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 9d12d9f26209..cbef785765cf 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -38,78 +38,38 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
}
static int
-qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
- uint32_t cram_size, uint32_t *ext_mem, void **nxt)
+qla24xx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint32_t *ram,
+ uint32_t ram_dwords, void **nxt)
{
int rval;
- uint32_t cnt, stat, timer, risc_address, ext_mem_cnt;
- uint16_t mb[4];
+ uint32_t cnt, stat, timer, dwords, idx;
+ uint16_t mb0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ dma_addr_t dump_dma = ha->gid_list_dma;
+ uint32_t *dump = (uint32_t *)ha->gid_list;
rval = QLA_SUCCESS;
- risc_address = ext_mem_cnt = 0;
- memset(mb, 0, sizeof(mb));
+ mb0 = 0;
- /* Code RAM. */
- risc_address = 0x20000;
- WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
+ WRT_REG_WORD(&reg->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- for (cnt = 0; cnt < cram_size / 4 && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
- WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
- RD_REG_WORD(&reg->mailbox8);
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
-
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->host_status);
- if (stat & HSRX_RISC_INT) {
- stat &= 0xff;
+ dwords = GID_LIST_SIZE / 4;
+ for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
+ cnt += dwords, addr += dwords) {
+ if (cnt + dwords > ram_dwords)
+ dwords = ram_dwords - cnt;
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
+ WRT_REG_WORD(&reg->mailbox1, LSW(addr));
+ WRT_REG_WORD(&reg->mailbox8, MSW(addr));
- mb[0] = RD_REG_WORD(&reg->mailbox0);
- mb[2] = RD_REG_WORD(&reg->mailbox2);
- mb[3] = RD_REG_WORD(&reg->mailbox3);
+ WRT_REG_WORD(&reg->mailbox2, MSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox3, LSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox6, MSW(MSD(dump_dma)));
+ WRT_REG_WORD(&reg->mailbox7, LSW(MSD(dump_dma)));
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
-
- /* Clear this intr; it wasn't a mailbox intr */
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- }
- udelay(5);
- }
-
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb[0] & MBS_MASK;
- code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
- } else {
- rval = QLA_FUNCTION_FAILED;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* External Memory. */
- risc_address = 0x100000;
- ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
- WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- }
- for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
- WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
- RD_REG_WORD(&reg->mailbox8);
+ WRT_REG_WORD(&reg->mailbox4, MSW(dwords));
+ WRT_REG_WORD(&reg->mailbox5, LSW(dwords));
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
for (timer = 6000000; timer; timer--) {
@@ -123,9 +83,7 @@ qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
set_bit(MBX_INTERRUPT,
&ha->mbx_cmd_flags);
- mb[0] = RD_REG_WORD(&reg->mailbox0);
- mb[2] = RD_REG_WORD(&reg->mailbox2);
- mb[3] = RD_REG_WORD(&reg->mailbox3);
+ mb0 = RD_REG_WORD(&reg->mailbox0);
WRT_REG_DWORD(&reg->hccr,
HCCRX_CLR_RISC_INT);
@@ -141,17 +99,34 @@ qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
}
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb[0] & MBS_MASK;
- ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
+ rval = mb0 & MBS_MASK;
+ for (idx = 0; idx < dwords; idx++)
+ ram[cnt + idx] = swab32(dump[idx]);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
- *nxt = rval == QLA_SUCCESS ? &ext_mem[cnt]: NULL;
+ *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
return rval;
}
+static int
+qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+ uint32_t cram_size, void **nxt)
+{
+ int rval;
+
+ /* Code RAM. */
+ rval = qla24xx_dump_ram(ha, 0x20000, code_ram, cram_size / 4, nxt);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ /* External Memory. */
+ return qla24xx_dump_ram(ha, 0x100000, *nxt,
+ ha->fw_memory_size - 0x100000 + 1, nxt);
+}
+
static uint32_t *
qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
uint32_t count, uint32_t *buf)
@@ -239,6 +214,90 @@ qla24xx_soft_reset(scsi_qla_host_t *ha)
return rval;
}
+static int
+qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
+ uint16_t ram_words, void **nxt)
+{
+ int rval;
+ uint32_t cnt, stat, timer, words, idx;
+ uint16_t mb0;
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ dma_addr_t dump_dma = ha->gid_list_dma;
+ uint16_t *dump = (uint16_t *)ha->gid_list;
+
+ rval = QLA_SUCCESS;
+ mb0 = 0;
+
+ WRT_MAILBOX_REG(ha, reg, 0, MBC_DUMP_RISC_RAM_EXTENDED);
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ words = GID_LIST_SIZE / 2;
+ for (cnt = 0; cnt < ram_words && rval == QLA_SUCCESS;
+ cnt += words, addr += words) {
+ if (cnt + words > ram_words)
+ words = ram_words - cnt;
+
+ WRT_MAILBOX_REG(ha, reg, 1, LSW(addr));
+ WRT_MAILBOX_REG(ha, reg, 8, MSW(addr));
+
+ WRT_MAILBOX_REG(ha, reg, 2, MSW(dump_dma));
+ WRT_MAILBOX_REG(ha, reg, 3, LSW(dump_dma));
+ WRT_MAILBOX_REG(ha, reg, 6, MSW(MSD(dump_dma)));
+ WRT_MAILBOX_REG(ha, reg, 7, LSW(MSD(dump_dma)));
+
+ WRT_MAILBOX_REG(ha, reg, 4, words);
+ WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+
+ for (timer = 6000000; timer; timer--) {
+ /* Check for pending interrupts. */
+ stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+ if (stat & HSR_RISC_INT) {
+ stat &= 0xff;
+
+ if (stat == 0x1 || stat == 0x2) {
+ set_bit(MBX_INTERRUPT,
+ &ha->mbx_cmd_flags);
+
+ mb0 = RD_MAILBOX_REG(ha, reg, 0);
+
+ /* Release mailbox registers. */
+ WRT_REG_WORD(&reg->semaphore, 0);
+ WRT_REG_WORD(&reg->hccr,
+ HCCR_CLR_RISC_INT);
+ RD_REG_WORD(&reg->hccr);
+ break;
+ } else if (stat == 0x10 || stat == 0x11) {
+ set_bit(MBX_INTERRUPT,
+ &ha->mbx_cmd_flags);
+
+ mb0 = RD_MAILBOX_REG(ha, reg, 0);
+
+ WRT_REG_WORD(&reg->hccr,
+ HCCR_CLR_RISC_INT);
+ RD_REG_WORD(&reg->hccr);
+ break;
+ }
+
+ /* clear this intr; it wasn't a mailbox intr */
+ WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+ RD_REG_WORD(&reg->hccr);
+ }
+ udelay(5);
+ }
+
+ if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ rval = mb0 & MBS_MASK;
+ for (idx = 0; idx < words; idx++)
+ ram[cnt + idx] = swab16(dump[idx]);
+ } else {
+ rval = QLA_FUNCTION_FAILED;
+ }
+ }
+
+ *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
+ return rval;
+}
+
static inline void
qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
uint16_t *buf)
@@ -258,19 +317,14 @@ void
qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
{
int rval;
- uint32_t cnt, timer;
- uint32_t risc_address;
- uint16_t mb0, mb2;
+ uint32_t cnt;
- uint32_t stat;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
uint16_t __iomem *dmp_reg;
unsigned long flags;
struct qla2300_fw_dump *fw;
- uint32_t data_ram_cnt;
+ void *nxt;
- risc_address = data_ram_cnt = 0;
- mb0 = mb2 = 0;
flags = 0;
if (!hardware_locked)
@@ -388,185 +442,23 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
}
}
- if (rval == QLA_SUCCESS) {
- /* Get RISC SRAM. */
- risc_address = 0x800;
- WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- }
- for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_MAILBOX_REG(ha, reg, 1, (uint16_t)risc_address);
- WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
-
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
- if (stat & HSR_RISC_INT) {
- stat &= 0xff;
-
- if (stat == 0x1 || stat == 0x2) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_MAILBOX_REG(ha, reg, 0);
- mb2 = RD_MAILBOX_REG(ha, reg, 2);
-
- /* Release mailbox registers. */
- WRT_REG_WORD(&reg->semaphore, 0);
- WRT_REG_WORD(&reg->hccr,
- HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- break;
- } else if (stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_MAILBOX_REG(ha, reg, 0);
- mb2 = RD_MAILBOX_REG(ha, reg, 2);
-
- WRT_REG_WORD(&reg->hccr,
- HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- break;
- }
-
- /* clear this intr; it wasn't a mailbox intr */
- WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- }
- udelay(5);
- }
-
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb0 & MBS_MASK;
- fw->risc_ram[cnt] = htons(mb2);
- } else {
- rval = QLA_FUNCTION_FAILED;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* Get stack SRAM. */
- risc_address = 0x10000;
- WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- }
- for (cnt = 0; cnt < sizeof(fw->stack_ram) / 2 && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address));
- WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address));
- WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
-
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
- if (stat & HSR_RISC_INT) {
- stat &= 0xff;
-
- if (stat == 0x1 || stat == 0x2) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_MAILBOX_REG(ha, reg, 0);
- mb2 = RD_MAILBOX_REG(ha, reg, 2);
-
- /* Release mailbox registers. */
- WRT_REG_WORD(&reg->semaphore, 0);
- WRT_REG_WORD(&reg->hccr,
- HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- break;
- } else if (stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_MAILBOX_REG(ha, reg, 0);
- mb2 = RD_MAILBOX_REG(ha, reg, 2);
-
- WRT_REG_WORD(&reg->hccr,
- HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- break;
- }
-
- /* clear this intr; it wasn't a mailbox intr */
- WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- }
- udelay(5);
- }
-
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb0 & MBS_MASK;
- fw->stack_ram[cnt] = htons(mb2);
- } else {
- rval = QLA_FUNCTION_FAILED;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* Get data SRAM. */
- risc_address = 0x11000;
- data_ram_cnt = ha->fw_memory_size - risc_address + 1;
- WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- }
- for (cnt = 0; cnt < data_ram_cnt && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address));
- WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address));
- WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
-
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
- if (stat & HSR_RISC_INT) {
- stat &= 0xff;
-
- if (stat == 0x1 || stat == 0x2) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_MAILBOX_REG(ha, reg, 0);
- mb2 = RD_MAILBOX_REG(ha, reg, 2);
-
- /* Release mailbox registers. */
- WRT_REG_WORD(&reg->semaphore, 0);
- WRT_REG_WORD(&reg->hccr,
- HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- break;
- } else if (stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_MAILBOX_REG(ha, reg, 0);
- mb2 = RD_MAILBOX_REG(ha, reg, 2);
-
- WRT_REG_WORD(&reg->hccr,
- HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- break;
- }
+ /* Get RISC SRAM. */
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_ram(ha, 0x800, fw->risc_ram,
+ sizeof(fw->risc_ram) / 2, &nxt);
- /* clear this intr; it wasn't a mailbox intr */
- WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
- RD_REG_WORD(&reg->hccr);
- }
- udelay(5);
- }
+ /* Get stack SRAM. */
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_ram(ha, 0x10000, fw->stack_ram,
+ sizeof(fw->stack_ram) / 2, &nxt);
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb0 & MBS_MASK;
- fw->data_ram[cnt] = htons(mb2);
- } else {
- rval = QLA_FUNCTION_FAILED;
- }
- }
+ /* Get data SRAM. */
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_ram(ha, 0x11000, fw->data_ram,
+ ha->fw_memory_size - 0x11000 + 1, &nxt);
if (rval == QLA_SUCCESS)
- qla2xxx_copy_queues(ha, &fw->data_ram[cnt]);
+ qla2xxx_copy_queues(ha, nxt);
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
@@ -1010,7 +902,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
goto qla24xx_fw_dump_failed_0;
rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
- fw->ext_mem, &nxt);
+ &nxt);
if (rval != QLA_SUCCESS)
goto qla24xx_fw_dump_failed_0;
@@ -1318,7 +1210,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
goto qla25xx_fw_dump_failed_0;
rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
- fw->ext_mem, &nxt);
+ &nxt);
if (rval != QLA_SUCCESS)
goto qla25xx_fw_dump_failed_0;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 078f2a15f40b..cf194517400d 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1036,22 +1036,6 @@ struct mid_db_entry_24xx {
uint8_t reserved_1;
};
- /*
- * Virtual Fabric ID type definition.
- */
-typedef struct vf_id {
- uint16_t id : 12;
- uint16_t priority : 4;
-} vf_id_t;
-
-/*
- * Virtual Fabric HopCt type definition.
- */
-typedef struct vf_hopct {
- uint16_t reserved : 8;
- uint16_t hopct : 8;
-} vf_hopct_t;
-
/*
* Virtual Port Control IOCB
*/
@@ -1082,10 +1066,10 @@ struct vp_ctrl_entry_24xx {
uint8_t vp_idx_map[16];
uint16_t flags;
- struct vf_id id;
+ uint16_t id;
uint16_t reserved_4;
- struct vf_hopct hopct;
- uint8_t reserved_5[8];
+ uint16_t hopct;
+ uint8_t reserved_5[24];
};
/*
@@ -1132,9 +1116,9 @@ struct vp_config_entry_24xx {
uint16_t reserved_vp2;
uint8_t port_name_idx2[WWN_SIZE];
uint8_t node_name_idx2[WWN_SIZE];
- struct vf_id id;
+ uint16_t id;
uint16_t reserved_4;
- struct vf_hopct hopct;
+ uint16_t hopct;
uint8_t reserved_5;
};
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 76eb4fecce65..f8827068d30f 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -152,10 +152,6 @@ extern int
qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
extern int
-qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t,
- uint32_t);
-
-extern int
qla2x00_abort_command(scsi_qla_host_t *, srb_t *);
extern int
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 750d7ef83aae..4cb80b476c85 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1583,8 +1583,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
eiter->len = __constant_cpu_to_be16(4 + 4);
max_frame_size = IS_FWI2_CAPABLE(ha) ?
- (uint32_t) icb24->frame_payload_size:
- (uint32_t) ha->init_cb->frame_payload_size;
+ le16_to_cpu(icb24->frame_payload_size):
+ le16_to_cpu(ha->init_cb->frame_payload_size);
eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
size += 4 + 4;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 01e26087c1dd..bbbc5a632a1d 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3645,7 +3645,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = __constant_cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
- icb->login_timeout = cpu_to_le16(nv->login_timeout);
+ icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 285479b62d8f..5d9a64a7879b 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -409,6 +409,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
}
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
ha->flags.management_server_logged_in = 0;
qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]);
@@ -454,8 +455,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->flags.management_server_logged_in = 0;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
- if (ql2xfdmienable)
- set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0);
break;
@@ -511,6 +510,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
}
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
ha->flags.gpsc_supported = 1;
ha->flags.management_server_logged_in = 0;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 7d0a8a4c7719..210060420809 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -681,7 +681,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
* Context:
* Kernel context.
*/
-int
+static int
qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer,
dma_addr_t phys_addr, size_t size, uint32_t tov)
{
@@ -784,7 +784,6 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
ha->host_no, rval));
} else {
- sp->flags |= SRB_ABORT_PENDING;
DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
ha->host_no));
}
@@ -1469,7 +1468,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
- lg->vp_index = cpu_to_le16(ha->vp_idx);
+ lg->vp_index = ha->vp_idx;
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
@@ -1724,7 +1723,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
- lg->vp_index = cpu_to_le16(ha->vp_idx);
+ lg->vp_index = ha->vp_idx;
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
@@ -2210,7 +2209,6 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
rval = QLA_FUNCTION_FAILED;
} else {
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
- sp->flags |= SRB_ABORT_PENDING;
}
dma_pool_free(ha->s_dma_pool, abt, abt_dma);
@@ -2644,12 +2642,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
struct vp_rpt_id_entry_24xx *rptid_entry)
{
uint8_t vp_idx;
+ uint16_t stat = le16_to_cpu(rptid_entry->vp_idx);
scsi_qla_host_t *vha;
if (rptid_entry->entry_status != 0)
return;
- if (rptid_entry->entry_status != __constant_cpu_to_le16(CS_COMPLETE))
- return;
if (rptid_entry->format == 0) {
DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
@@ -2659,17 +2656,17 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]));
} else if (rptid_entry->format == 1) {
- vp_idx = LSB(rptid_entry->vp_idx);
+ vp_idx = LSB(stat);
DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
"- status %d - "
"with port id %02x%02x%02x\n",__func__,ha->host_no,
- vp_idx, MSB(rptid_entry->vp_idx),
+ vp_idx, MSB(stat),
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]));
if (vp_idx == 0)
return;
- if (MSB(rptid_entry->vp_idx) == 1)
+ if (MSB(stat) == 1)
return;
list_for_each_entry(vha, &ha->vp_list, vp_list)
@@ -2982,8 +2979,8 @@ qla84xx_verify_chip(struct scsi_qla_host *ha, uint16_t *status)
/* We update the firmware with only one data sequence. */
options |= VCO_END_OF_DATA;
- retry = 0;
do {
+ retry = 0;
memset(mn, 0, sizeof(*mn));
mn->p.req.entry_type = VERIFY_CHIP_IOCB_TYPE;
mn->p.req.entry_count = 1;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 8b33b163b1d4..3223fd16bcfe 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -67,7 +67,7 @@ static void qla2x00_free_device(scsi_qla_host_t *);
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
-int ql2xfdmienable;
+int ql2xfdmienable=1;
module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registratons "
@@ -2135,7 +2135,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
kfree(ha->nvram);
}
-struct qla_work_evt *
+static struct qla_work_evt *
qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
int locked)
{
@@ -2152,7 +2152,7 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
return e;
}
-int
+static int
qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
{
unsigned long flags;
@@ -2373,7 +2373,7 @@ qla2x00_do_dpc(void *data)
} else {
fcport->login_retry = 0;
}
- if (fcport->login_retry == 0)
+ if (fcport->login_retry == 0 && status != QLA_SUCCESS)
fcport->loop_id = FC_NO_LOOP_ID;
}
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
@@ -2599,6 +2599,10 @@ qla2x00_timer(scsi_qla_host_t *ha)
start_dpc++;
}
+ /* Process any deferred work. */
+ if (!list_empty(&ha->work_list))
+ start_dpc++;
+
/* Schedule the DPC routine if needed */
if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index f42f17acf2cf..afeae2bfe7eb 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.01-k1"
+#define QLA2XXX_VERSION "8.02.01-k2"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 3f34e9376b0a..b33e72516ef8 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -121,6 +121,7 @@ extern struct scsi_transport_template blank_transport_template;
extern void __scsi_remove_device(struct scsi_device *);
extern struct bus_type scsi_bus_type;
+extern struct attribute_group *scsi_sysfs_shost_attr_groups[];
/* scsi_netlink.c */
#ifdef CONFIG_SCSI_NETLINK
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index ed395154a5b1..3a1c99d5c775 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -190,10 +190,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
*/
static int proc_print_scsidevice(struct device *dev, void *data)
{
- struct scsi_device *sdev = to_scsi_device(dev);
+ struct scsi_device *sdev;
struct seq_file *s = data;
int i;
+ if (!scsi_is_sdev_device(dev))
+ goto out;
+
+ sdev = to_scsi_device(dev);
seq_printf(s,
"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
@@ -230,6 +234,7 @@ static int proc_print_scsidevice(struct device *dev, void *data)
else
seq_printf(s, "\n");
+out:
return 0;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index e67c14e31bab..fcd7455ffc39 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -322,6 +322,21 @@ out:
return NULL;
}
+static void scsi_target_destroy(struct scsi_target *starget)
+{
+ struct device *dev = &starget->dev;
+ struct Scsi_Host *shost = dev_to_shost(dev->parent);
+ unsigned long flags;
+
+ transport_destroy_device(dev);
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (shost->hostt->target_destroy)
+ shost->hostt->target_destroy(starget);
+ list_del_init(&starget->siblings);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ put_device(dev);
+}
+
static void scsi_target_dev_release(struct device *dev)
{
struct device *parent = dev->parent;
@@ -331,9 +346,14 @@ static void scsi_target_dev_release(struct device *dev)
put_device(parent);
}
+struct device_type scsi_target_type = {
+ .name = "scsi_target",
+ .release = scsi_target_dev_release,
+};
+
int scsi_is_target_device(const struct device *dev)
{
- return dev->release == scsi_target_dev_release;
+ return dev->type == &scsi_target_type;
}
EXPORT_SYMBOL(scsi_is_target_device);
@@ -391,14 +411,17 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
device_initialize(dev);
starget->reap_ref = 1;
dev->parent = get_device(parent);
- dev->release = scsi_target_dev_release;
sprintf(dev->bus_id, "target%d:%d:%d",
shost->host_no, channel, id);
+#ifndef CONFIG_SYSFS_DEPRECATED
+ dev->bus = &scsi_bus_type;
+#endif
+ dev->type = &scsi_target_type;
starget->id = id;
starget->channel = channel;
INIT_LIST_HEAD(&starget->siblings);
INIT_LIST_HEAD(&starget->devices);
- starget->state = STARGET_RUNNING;
+ starget->state = STARGET_CREATED;
starget->scsi_level = SCSI_2;
retry:
spin_lock_irqsave(shost->host_lock, flags);
@@ -411,18 +434,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
spin_unlock_irqrestore(shost->host_lock, flags);
/* allocate and add */
transport_setup_device(dev);
- error = device_add(dev);
- if (error) {
- dev_err(dev, "target device_add failed, error %d\n", error);
- spin_lock_irqsave(shost->host_lock, flags);
- list_del_init(&starget->siblings);
- spin_unlock_irqrestore(shost->host_lock, flags);
- transport_destroy_device(dev);
- put_device(parent);
- kfree(starget);
- return NULL;
- }
- transport_add_device(dev);
if (shost->hostt->target_alloc) {
error = shost->hostt->target_alloc(starget);
@@ -430,9 +441,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);
/* don't want scsi_target_reap to do the final
* put because it will be under the host lock */
- get_device(dev);
- scsi_target_reap(starget);
- put_device(dev);
+ scsi_target_destroy(starget);
return NULL;
}
}
@@ -459,18 +468,10 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
{
struct scsi_target *starget =
container_of(work, struct scsi_target, ew.work);
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- unsigned long flags;
transport_remove_device(&starget->dev);
device_del(&starget->dev);
- transport_destroy_device(&starget->dev);
- spin_lock_irqsave(shost->host_lock, flags);
- if (shost->hostt->target_destroy)
- shost->hostt->target_destroy(starget);
- list_del_init(&starget->siblings);
- spin_unlock_irqrestore(shost->host_lock, flags);
- put_device(&starget->dev);
+ scsi_target_destroy(starget);
}
/**
@@ -485,21 +486,25 @@ void scsi_target_reap(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
+ enum scsi_target_state state;
+ int empty;
spin_lock_irqsave(shost->host_lock, flags);
+ state = starget->state;
+ empty = --starget->reap_ref == 0 &&
+ list_empty(&starget->devices) ? 1 : 0;
+ spin_unlock_irqrestore(shost->host_lock, flags);
- if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
- BUG_ON(starget->state == STARGET_DEL);
- starget->state = STARGET_DEL;
- spin_unlock_irqrestore(shost->host_lock, flags);
- execute_in_process_context(scsi_target_reap_usercontext,
- &starget->ew);
+ if (!empty)
return;
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
-
- return;
+ BUG_ON(state == STARGET_DEL);
+ starget->state = STARGET_DEL;
+ if (state == STARGET_CREATED)
+ scsi_target_destroy(starget);
+ else
+ execute_in_process_context(scsi_target_reap_usercontext,
+ &starget->ew);
}
/**
@@ -1048,8 +1053,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
scsi_inq_str(vend, result, 8, 16),
scsi_inq_str(mod, result, 16, 32));
});
+
}
-
+
res = SCSI_SCAN_TARGET_PRESENT;
goto out_free_result;
}
@@ -1489,7 +1495,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (scsi_host_scan_allowed(shost))
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
mutex_unlock(&shost->scan_mutex);
- transport_configure_device(&starget->dev);
scsi_target_reap(starget);
put_device(&starget->dev);
@@ -1570,7 +1575,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
out_reap:
/* now determine if the target has any children at all
* and if not, nuke it */
- transport_configure_device(&starget->dev);
scsi_target_reap(starget);
put_device(&starget->dev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 67bb20ed45d2..049103f1d16f 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -21,6 +21,8 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+static struct device_type scsi_dev_type;
+
static const struct {
enum scsi_device_state value;
char *name;
@@ -249,18 +251,27 @@ shost_rd_attr(sg_tablesize, "%hu\n");
shost_rd_attr(unchecked_isa_dma, "%d\n");
shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
-static struct device_attribute *scsi_sysfs_shost_attrs[] = {
- &dev_attr_unique_id,
- &dev_attr_host_busy,
- &dev_attr_cmd_per_lun,
- &dev_attr_can_queue,
- &dev_attr_sg_tablesize,
- &dev_attr_unchecked_isa_dma,
- &dev_attr_proc_name,
- &dev_attr_scan,
- &dev_attr_hstate,
- &dev_attr_supported_mode,
- &dev_attr_active_mode,
+static struct attribute *scsi_sysfs_shost_attrs[] = {
+ &dev_attr_unique_id.attr,
+ &dev_attr_host_busy.attr,
+ &dev_attr_cmd_per_lun.attr,
+ &dev_attr_can_queue.attr,
+ &dev_attr_sg_tablesize.attr,
+ &dev_attr_unchecked_isa_dma.attr,
+ &dev_attr_proc_name.attr,
+ &dev_attr_scan.attr,
+ &dev_attr_hstate.attr,
+ &dev_attr_supported_mode.attr,
+ &dev_attr_active_mode.attr,
+ NULL
+};
+
+struct attribute_group scsi_shost_attr_group = {
+ .attrs = scsi_sysfs_shost_attrs,
+};
+
+struct attribute_group *scsi_sysfs_shost_attr_groups[] = {
+ &scsi_shost_attr_group,
NULL
};
@@ -335,7 +346,12 @@ static struct class sdev_class = {
/* all probing is done in the individual ->probe routines */
static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
{
- struct scsi_device *sdp = to_scsi_device(dev);
+ struct scsi_device *sdp;
+
+ if (dev->type != &scsi_dev_type)
+ return 0;
+
+ sdp = to_scsi_device(dev);
if (sdp->no_uld_attach)
return 0;
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
@@ -351,10 +367,16 @@ static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
static int scsi_bus_suspend(struct device * dev, pm_message_t state)
{
- struct device_driver *drv = dev->driver;
- struct scsi_device *sdev = to_scsi_device(dev);
+ struct device_driver *drv;
+ struct scsi_device *sdev;
int err;
+ if (dev->type != &scsi_dev_type)
+ return 0;
+
+ drv = dev->driver;
+ sdev = to_scsi_device(dev);
+
err = scsi_device_quiesce(sdev);
if (err)
return err;
@@ -370,10 +392,16 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state)
static int scsi_bus_resume(struct device * dev)
{
- struct device_driver *drv = dev->driver;
- struct scsi_device *sdev = to_scsi_device(dev);
+ struct device_driver *drv;
+ struct scsi_device *sdev;
int err = 0;
+ if (dev->type != &scsi_dev_type)
+ return 0;
+
+ drv = dev->driver;
+ sdev = to_scsi_device(dev);
+
if (drv && drv->resume)
err = drv->resume(dev);
@@ -781,6 +809,27 @@ sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
return count;
}
+static int scsi_target_add(struct scsi_target *starget)
+{
+ int error;
+
+ if (starget->state != STARGET_CREATED)
+ return 0;
+
+ error = device_add(&starget->dev);
+ if (error) {
+ dev_err(&starget->dev, "target device_add failed, error %d\n", error);
+ get_device(&starget->dev);
+ scsi_target_reap(starget);
+ put_device(&starget->dev);
+ return error;
+ }
+ transport_add_device(&starget->dev);
+ starget->state = STARGET_RUNNING;
+
+ return 0;
+}
+
static struct device_attribute sdev_attr_queue_type_rw =
__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
sdev_store_queue_type_rw);
@@ -796,10 +845,16 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{
int error, i;
struct request_queue *rq = sdev->request_queue;
+ struct scsi_target *starget = sdev->sdev_target;
if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
return error;
+ error = scsi_target_add(starget);
+ if (error)
+ return error;
+
+ transport_configure_device(&starget->dev);
error = device_add(&sdev->sdev_gendev);
if (error) {
put_device(sdev->sdev_gendev.parent);
@@ -834,7 +889,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
goto out;
}
- error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
+ error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
if (error)
sdev_printk(KERN_INFO, sdev,
@@ -971,44 +1026,6 @@ int scsi_register_interface(struct class_interface *intf)
}
EXPORT_SYMBOL(scsi_register_interface);
-
-static struct device_attribute *class_attr_overridden(
- struct device_attribute **attrs,
- struct device_attribute *attr)
-{
- int i;
-
- if (!attrs)
- return NULL;
- for (i = 0; attrs[i]; i++)
- if (!strcmp(attrs[i]->attr.name, attr->attr.name))
- return attrs[i];
- return NULL;
-}
-
-static int class_attr_add(struct device *classdev,
- struct device_attribute *attr)
-{
- struct device_attribute *base_attr;
-
- /*
- * Spare the caller from having to copy things it's not interested in.
- */
- base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr);
- if (base_attr) {
- /* extend permissions */
- attr->attr.mode |= base_attr->attr.mode;
-
- /* override null show/store with default */
- if (!attr->show)
- attr->show = base_attr->show;
- if (!attr->store)
- attr->store = base_attr->store;
- }
-
- return device_create_file(classdev, attr);
-}
-
/**
* scsi_sysfs_add_host - add scsi host to subsystem
* @shost: scsi host struct to add to subsystem
@@ -1018,20 +1035,11 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
{
int error, i;
+ /* add host specific attributes */
if (shost->hostt->shost_attrs) {
for (i = 0; shost->hostt->shost_attrs[i]; i++) {
- error = class_attr_add(&shost->shost_dev,
- shost->hostt->shost_attrs[i]);
- if (error)
- return error;
- }
- }
-
- for (i = 0; scsi_sysfs_shost_attrs[i]; i++) {
- if (!class_attr_overridden(shost->hostt->shost_attrs,
- scsi_sysfs_shost_attrs[i])) {
error = device_create_file(&shost->shost_dev,
- scsi_sysfs_shost_attrs[i]);
+ shost->hostt->shost_attrs[i]);
if (error)
return error;
}
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 6b092a6c295d..5fd64e70029d 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1961,12 +1961,17 @@ fc_timed_out(struct scsi_cmnd *scmd)
}
/*
- * Must be called with shost->host_lock held
+ * Called by fc_user_scan to locate an rport on the shost that
+ * matches the channel and target id, and invoke scsi_scan_target()
+ * on the rport.
*/
-static int fc_user_scan(struct Scsi_Host *shost, uint channel,
- uint id, uint lun)
+static void
+fc_user_scan_tgt(struct Scsi_Host *shost, uint channel, uint id, uint lun)
{
struct fc_rport *rport;
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(rport, &fc_host_rports(shost), peers) {
if (rport->scsi_target_id == -1)
@@ -1975,13 +1980,54 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
if (rport->port_state != FC_PORTSTATE_ONLINE)
continue;
- if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
- (id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
- scsi_scan_target(&rport->dev, rport->channel,
- rport->scsi_target_id, lun, 1);
+ if ((channel == rport->channel) &&
+ (id == rport->scsi_target_id)) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_scan_target(&rport->dev, channel, id, lun, 1);
+ return;
}
}
+ spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/*
+ * Called via sysfs scan routines. Necessary, as the FC transport
+ * wants to place all target objects below the rport object. So this
+ * routine must invoke the scsi_scan_target() routine with the rport
+ * object as the parent.
+ */
+static int
+fc_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun)
+{
+ uint chlo, chhi;
+ uint tgtlo, tgthi;
+
+ if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
+ ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
+ ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
+ return -EINVAL;
+
+ if (channel == SCAN_WILD_CARD) {
+ chlo = 0;
+ chhi = shost->max_channel + 1;
+ } else {
+ chlo = channel;
+ chhi = channel + 1;
+ }
+
+ if (id == SCAN_WILD_CARD) {
+ tgtlo = 0;
+ tgthi = shost->max_id;
+ } else {
+ tgtlo = id;
+ tgthi = id + 1;
+ }
+
+ for ( ; chlo < chhi; chlo++)
+ for ( ; tgtlo < tgthi; tgtlo++)
+ fc_user_scan_tgt(shost, chlo, tgtlo, lun);
+
return 0;
}
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 27ec625ab771..7899e3dda9bf 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -192,6 +192,16 @@ static void sas_non_host_smp_request(struct request_queue *q)
sas_smp_request(q, rphy_to_shost(rphy), rphy);
}
+static void sas_host_release(struct device *dev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+ struct request_queue *q = sas_host->q;
+
+ if (q)
+ blk_cleanup_queue(q);
+}
+
static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
{
struct request_queue *q;
@@ -199,6 +209,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
struct device *dev;
char namebuf[BUS_ID_SIZE];
const char *name;
+ void (*release)(struct device *);
if (!to_sas_internal(shost->transportt)->f->smp_handler) {
printk("%s can't handle SMP requests\n", shost->hostt->name);
@@ -209,17 +220,19 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
q = blk_init_queue(sas_non_host_smp_request, NULL);
dev = &rphy->dev;
name = dev->bus_id;
+ release = NULL;
} else {
q = blk_init_queue(sas_host_smp_request, NULL);
dev = &shost->shost_gendev;
snprintf(namebuf, sizeof(namebuf),
"sas_host%d", shost->host_no);
name = namebuf;
+ release = sas_host_release;
}
if (!q)
return -ENOMEM;
- error = bsg_register_queue(q, dev, name);
+ error = bsg_register_queue(q, dev, name, release);
if (error) {
blk_cleanup_queue(q);
return -ENOMEM;
@@ -253,7 +266,6 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
return;
bsg_unregister_queue(q);
- blk_cleanup_queue(q);
}
/*
@@ -1301,6 +1313,9 @@ static void sas_expander_release(struct device *dev)
struct sas_rphy *rphy = dev_to_rphy(dev);
struct sas_expander_device *edev = rphy_to_expander_device(rphy);
+ if (rphy->q)
+ blk_cleanup_queue(rphy->q);
+
put_device(dev->parent);
kfree(edev);
}
@@ -1310,6 +1325,9 @@ static void sas_end_device_release(struct device *dev)
struct sas_rphy *rphy = dev_to_rphy(dev);
struct sas_end_device *edev = rphy_to_end_device(rphy);
+ if (rphy->q)
+ blk_cleanup_queue(rphy->q);
+
put_device(dev->parent);
kfree(edev);
}
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index bc12b5d5d676..75a64a6cae8c 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -24,6 +24,7 @@
#include <linux/workqueue.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <scsi/scsi.h>
#include "scsi_priv.h"
#include <scsi/scsi_device.h>
@@ -1374,11 +1375,11 @@ static int spi_host_configure(struct transport_container *tc,
* overloads the return by setting 1<<1 if the attribute should
* be writeable */
#define TARGET_ATTRIBUTE_HELPER(name) \
- (si->f->show_##name ? 1 : 0) + \
- (si->f->set_##name ? 2 : 0)
+ (si->f->show_##name ? S_IRUGO : 0) | \
+ (si->f->set_##name ? S_IWUSR : 0)
-static int target_attribute_is_visible(struct kobject *kobj,
- struct attribute *attr, int i)
+static mode_t target_attribute_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
{
struct device *cdev = container_of(kobj, struct device, kobj);
struct scsi_target *starget = transport_class_to_starget(cdev);
@@ -1428,7 +1429,7 @@ static int target_attribute_is_visible(struct kobject *kobj,
spi_support_ius(starget))
return TARGET_ATTRIBUTE_HELPER(hold_mcs);
else if (attr == &dev_attr_revalidate.attr)
- return 1;
+ return S_IWUSR;
return 0;
}
@@ -1462,25 +1463,9 @@ static int spi_target_configure(struct transport_container *tc,
struct device *cdev)
{
struct kobject *kobj = &cdev->kobj;
- int i;
- struct attribute *attr;
- int rc;
-
- for (i = 0; (attr = target_attributes[i]) != NULL; i++) {
- int j = target_attribute_group.is_visible(kobj, attr, i);
-
- /* FIXME: as well as returning -EEXIST, which we'd like
- * to ignore, sysfs also does a WARN_ON and dumps a trace,
- * which is bad, so temporarily, skip attributes that are
- * already visible (the revalidate one) */
- if (j && attr != &dev_attr_revalidate.attr)
- rc = sysfs_add_file_to_group(kobj, attr,
- target_attribute_group.name);
- /* and make the attribute writeable if we have a set
- * function */
- if ((j & 1))
- rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
- }
+
+ /* force an update based on parameters read from the device */
+ sysfs_update_group(kobj, &target_attribute_group);
return 0;
}
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 03e359670506..31fe6051c799 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -313,7 +313,8 @@ static struct platform_driver sgiwd93_driver = {
.probe = sgiwd93_probe,
.remove = __devexit_p(sgiwd93_remove),
.driver = {
- .name = "sgiwd93"
+ .name = "sgiwd93",
+ .owner = THIS_MODULE,
}
};
@@ -333,3 +334,4 @@ module_exit(sgiwd93_module_exit);
MODULE_DESCRIPTION("SGI WD33C93 driver");
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sgiwd93");
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index 0a6b45b1b003..2bbef4c45a0d 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -53,6 +53,7 @@
MODULE_AUTHOR("Thomas Bogendörfer");
MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:snirm_53c710");
#define SNIRM710_CLOCK 32
@@ -136,6 +137,7 @@ static struct platform_driver snirm710_driver = {
.remove = __devexit_p(snirm710_driver_remove),
.driver = {
.name = "snirm_53c710",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a860c3a9ae99..e8db66ad0bde 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4322,7 +4322,7 @@ static void do_remove_sysfs_files(void)
static ssize_t
st_defined_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
+ struct st_modedef *STm = dev_get_drvdata(dev);
ssize_t l = 0;
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
@@ -4334,7 +4334,7 @@ DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL);
static ssize_t
st_defblk_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
+ struct st_modedef *STm = dev_get_drvdata(dev);
ssize_t l = 0;
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
@@ -4346,7 +4346,7 @@ DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL);
static ssize_t
st_defdensity_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
+ struct st_modedef *STm = dev_get_drvdata(dev);
ssize_t l = 0;
char *fmt;
@@ -4361,7 +4361,7 @@ static ssize_t
st_defcompression_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
+ struct st_modedef *STm = dev_get_drvdata(dev);
ssize_t l = 0;
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
@@ -4373,7 +4373,7 @@ DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
static ssize_t
st_options_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
+ struct st_modedef *STm = dev_get_drvdata(dev);
struct scsi_tape *STp;
int i, j, options;
ssize_t l = 0;
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 06152c7fa689..7514b3a0390e 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -294,6 +294,7 @@ static struct platform_driver esp_sun3x_driver = {
.remove = __devexit_p(esp_sun3x_remove),
.driver = {
.name = "sun3x_esp",
+ .owner = THIS_MODULE,
},
};
@@ -314,3 +315,4 @@ MODULE_VERSION(DRV_VERSION);
module_init(sun3x_esp_init);
module_exit(sun3x_esp_exit);
+MODULE_ALIAS("platform:sun3x_esp");
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 35142b5341b5..22a6aae78699 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -1647,7 +1647,7 @@ static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status)
SYM_QUEHEAD *qp;
struct sym_ccb *cp;
- while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) {
+ while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) {
struct scsi_cmnd *cmd;
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
@@ -3168,7 +3168,7 @@ int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int
* the COMP queue and put back other ones into
* the BUSY queue.
*/
- while ((qp = sym_remque_head(&qtmp)) != 0) {
+ while ((qp = sym_remque_head(&qtmp)) != NULL) {
struct scsi_cmnd *cmd;
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
cmd = cp->cmd;
@@ -5729,7 +5729,7 @@ void sym_hcb_free(struct sym_hcb *np)
sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE");
if (np->actccbs) {
- while ((qp = sym_remque_head(&np->free_ccbq)) != 0) {
+ while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) {
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
sym_mfree_dma(cp, sizeof(*cp), "CCB");
}
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 58d7eee4fe81..640333b1e75c 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1715,13 +1715,12 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in
}
-static irqreturn_t ihdlr(int irq, unsigned int j) {
+static irqreturn_t ihdlr(unsigned int j)
+{
struct scsi_cmnd *SCpnt;
unsigned int i, k, c, status, tstatus, reg, ret;
struct mscp *spp, *cpp;
-
- if (sh[j]->irq != irq)
- panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
+ int irq = sh[j]->irq;
/* Check if this board need to be serviced */
if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none;
@@ -1935,7 +1934,7 @@ static irqreturn_t do_interrupt_handler(int irq, void *shap) {
if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE;
spin_lock_irqsave(sh[j]->host_lock, spin_flags);
- ret = ihdlr(irq, j);
+ ret = ihdlr(j);
spin_unlock_irqrestore(sh[j]->host_lock, spin_flags);
return ret;
}
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index f385dce8dfbe..27aa40f3980e 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -951,7 +951,7 @@ static int ultrastor_abort(struct scsi_cmnd *SCpnt)
printk("abort: command mismatch, %p != %p\n",
config.mscp[mscp_index].SCint, SCpnt);
#endif
- if (config.mscp[mscp_index].SCint == 0)
+ if (config.mscp[mscp_index].SCint == NULL)
return FAILED;
if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
@@ -1101,7 +1101,7 @@ static void ultrastor_interrupt(void *dev_id)
SCtmp = mscp->SCint;
mscp->SCint = NULL;
- if (SCtmp == 0)
+ if (!SCtmp)
{
#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index 2aa6bfe8fdb3..f59463601874 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -51,6 +51,7 @@ extern int kgdb_output_string (const char* s, unsigned int count);
/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
#include <linux/console.h>
+#include <linux/jiffies.h>
/* this defines the index into rs_table for the port to use
*/
@@ -1729,7 +1730,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
break;
/* The 'tx_cur' is really the next buffer to send. We
* have to back up to the previous BD and wait for it
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 96a585e1cee8..ea41f2626458 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1868,6 +1868,7 @@ static int serial8250_startup(struct uart_port *port)
}
if (is_real_interrupt(up->port.irq)) {
+ unsigned char iir1;
/*
* Test for UARTs that do not reassert THRE when the
* transmitter is idle and the interrupt has already
@@ -1881,7 +1882,7 @@ static int serial8250_startup(struct uart_port *port)
wait_for_xmitr(up, UART_LSR_THRE);
serial_out_sync(up, UART_IER, UART_IER_THRI);
udelay(1); /* allow THRE to set */
- serial_in(up, UART_IIR);
+ iir1 = serial_in(up, UART_IIR);
serial_out(up, UART_IER, 0);
serial_out_sync(up, UART_IER, UART_IER_THRI);
udelay(1); /* allow a working UART time to re-assert THRE */
@@ -1894,7 +1895,7 @@ static int serial8250_startup(struct uart_port *port)
* If the interrupt is not reasserted, setup a timer to
* kick the UART on a regular basis.
*/
- if (iir & UART_IIR_NO_INT) {
+ if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
pr_debug("ttyS%d - using backup timer\n", port->line);
up->timer.function = serial8250_backup_timeout;
up->timer.data = (unsigned long)up;
@@ -2228,7 +2229,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
}
serial8250_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
- tty_termios_encode_baud_rate(termios, baud, baud);
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
}
static void
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c
deleted file mode 100644
index 58015fd14be9..000000000000
--- a/drivers/serial/8250_au1x00.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Serial Device Initialisation for Au1x00
- *
- * (C) Copyright Embedded Alley Solutions, Inc 2005
- * Author: Pantelis Antoniou <pantelis@embeddedalley.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/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/serial_core.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <linux/serial_8250.h>
-
-#include <asm/mach-au1x00/au1000.h>
-
-#include "8250.h"
-
-#define PORT(_base, _irq) \
- { \
- .iobase = _base, \
- .membase = (void __iomem *)_base,\
- .mapbase = CPHYSADDR(_base), \
- .irq = _irq, \
- .uartclk = 0, /* filled */ \
- .regshift = 2, \
- .iotype = UPIO_AU, \
- .flags = UPF_SKIP_TEST \
- }
-
-static struct plat_serial8250_port au1x00_data[] = {
-#if defined(CONFIG_SOC_AU1000)
- PORT(UART0_ADDR, AU1000_UART0_INT),
- PORT(UART1_ADDR, AU1000_UART1_INT),
- PORT(UART2_ADDR, AU1000_UART2_INT),
- PORT(UART3_ADDR, AU1000_UART3_INT),
-#elif defined(CONFIG_SOC_AU1500)
- PORT(UART0_ADDR, AU1500_UART0_INT),
- PORT(UART3_ADDR, AU1500_UART3_INT),
-#elif defined(CONFIG_SOC_AU1100)
- PORT(UART0_ADDR, AU1100_UART0_INT),
- PORT(UART1_ADDR, AU1100_UART1_INT),
- /* The internal UART2 does not exist on the AU1100 processor. */
- PORT(UART3_ADDR, AU1100_UART3_INT),
-#elif defined(CONFIG_SOC_AU1550)
- PORT(UART0_ADDR, AU1550_UART0_INT),
- PORT(UART1_ADDR, AU1550_UART1_INT),
- PORT(UART3_ADDR, AU1550_UART3_INT),
-#elif defined(CONFIG_SOC_AU1200)
- PORT(UART0_ADDR, AU1200_UART0_INT),
- PORT(UART1_ADDR, AU1200_UART1_INT),
-#endif
- { },
-};
-
-static struct platform_device au1x00_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_AU1X00,
- .dev = {
- .platform_data = au1x00_data,
- },
-};
-
-static int __init au1x00_init(void)
-{
- int i;
- unsigned int uartclk;
-
- /* get uart clock */
- uartclk = get_au1x00_uart_baud_base() * 16;
-
- /* fill up uartclk */
- for (i = 0; au1x00_data[i].flags ; i++)
- au1x00_data[i].uartclk = uartclk;
-
- return platform_device_register(&au1x00_device);
-}
-
-/* XXX: Yes, I know this doesn't yet work. */
-static void __exit au1x00_exit(void)
-{
- platform_device_unregister(&au1x00_device);
-}
-
-module_init(au1x00_init);
-module_exit(au1x00_exit);
-
-MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>");
-MODULE_DESCRIPTION("8250 serial probe module for Au1x000 cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index f97224ce59da..6e57382b9137 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -775,7 +775,7 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
* This list is ordered alphabetically by vendor then device.
* Specific entries must come before more generic entries.
*/
-static struct pci_serial_quirk pci_serial_quirks[] = {
+static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
/*
* ADDI-DATA GmbH communication cards <info@addi-data.com>
*/
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index f7cd9504d811..34b809e3b596 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -262,12 +262,12 @@ config SERIAL_8250_ACORN
cards. If unsure, say N.
config SERIAL_8250_AU1X00
- bool "AU1X00 serial port support"
+ bool "Au1x00 serial port support"
depends on SERIAL_8250 != n && SOC_AU1X00
help
- If you have an Au1x00 board and want to use the serial port, say Y
- to this option. The driver can handle 1 or 2 serial ports.
- If unsure, say N.
+ If you have an Au1x00 SOC based board and want to use the serial port,
+ say Y to this option. The driver can handle up to 4 serial ports,
+ depending on the SOC. If unsure, say N.
config SERIAL_8250_RM9K
bool "Support for MIPS RM9xxx integrated serial port"
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 3cbea5494724..f02ff9fad017 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
-obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 55492fa095a2..c065a704a93a 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -96,7 +96,6 @@
/* PDC registers */
#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
-#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR)
#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR)
#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 383c4e660cd5..88e7c1d5b919 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -3582,6 +3582,8 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ lock_kernel();
+
if (clear & TIOCM_RTS)
e100_rts(info, 0);
if (clear & TIOCM_DTR)
@@ -3601,6 +3603,8 @@ rs_tiocmset(struct tty_struct *tty, struct file *file,
e100_ri_out(info, 1);
if (set & TIOCM_CD)
e100_cd_out(info, 1);
+
+ unlock_kernel();
return 0;
}
@@ -3610,6 +3614,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned int result;
+ lock_kernel();
result =
(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
@@ -3618,6 +3623,8 @@ rs_tiocmget(struct tty_struct *tty, struct file *file)
| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
+ unlock_kernel();
+
#ifdef SERIAL_DEBUG_IO
printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
info->line, result, result);
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index 116211fcd36f..0dddd68b20d2 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -819,7 +819,7 @@ static void dz_console_putchar(struct uart_port *uport, int ch)
dz_out(dport, DZ_TCR, mask);
iob();
udelay(2);
- } while (loops--);
+ } while (--loops);
if (loops) /* Cannot send otherwise. */
dz_out(dport, DZ_TDR, ch);
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 8aacfb78deab..25029c7570b6 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -31,7 +31,8 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
struct resource resource;
struct device_node *np = ofdev->node;
const unsigned int *clk, *spd;
- int ret;
+ const u32 *prop;
+ int ret, prop_size;
memset(port, 0, sizeof *port);
spd = of_get_property(np, "current-speed", NULL);
@@ -49,6 +50,17 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
spin_lock_init(&port->lock);
port->mapbase = resource.start;
+
+ /* Check for shifted address mapping */
+ prop = of_get_property(np, "reg-offset", &prop_size);
+ if (prop && (prop_size == sizeof(u32)))
+ port->mapbase += *prop;
+
+ /* Check for registers offset within the devices address range */
+ prop = of_get_property(np, "reg-shift", &prop_size);
+ if (prop && (prop_size == sizeof(u32)))
+ port->regshift = *prop;
+
port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
port->type = type;
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index a9ca03ead3e5..977ce820ce30 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -329,13 +329,15 @@ EXPORT_SYMBOL(uart_update_timeout);
* If it's still invalid, we try 9600 baud.
*
* Update the @termios structure to reflect the baud rate
- * we're actually going to be using.
+ * we're actually going to be using. Don't do this for the case
+ * where B0 is requested ("hang up").
*/
unsigned int
uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
struct ktermios *old, unsigned int min, unsigned int max)
{
unsigned int try, baud, altbaud = 38400;
+ int hung_up = 0;
upf_t flags = port->flags & UPF_SPD_MASK;
if (flags == UPF_SPD_HI)
@@ -360,8 +362,10 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
/*
* Special case: B0 rate.
*/
- if (baud == 0)
+ if (baud == 0) {
+ hung_up = 1;
baud = 9600;
+ }
if (baud >= min && baud <= max)
return baud;
@@ -373,7 +377,9 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
termios->c_cflag &= ~CBAUD;
if (old) {
baud = tty_termios_baud_rate(old);
- tty_termios_encode_baud_rate(termios, baud, baud);
+ if (!hung_up)
+ tty_termios_encode_baud_rate(termios,
+ baud, baud);
old = NULL;
continue;
}
@@ -382,7 +388,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
* As a last resort, if the quotient is zero,
* default to 9600 bps
*/
- tty_termios_encode_baud_rate(termios, 9600, 9600);
+ if (!hung_up)
+ tty_termios_encode_baud_rate(termios, 9600, 9600);
}
return 0;
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 3271379a36db..90a20a152ebf 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1231,7 +1231,7 @@ static inline struct console *SUNZILOG_CONSOLE(void)
#define SUNZILOG_CONSOLE() (NULL)
#endif
-static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel)
+static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
{
int baud, brg;
@@ -1305,7 +1305,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
up->curregs[R7] = 0x7E; /* SDLC Flag */
up->curregs[R9] = NV;
up->curregs[R7p] = 0x00;
- sunzilog_init_kbdms(up, up->port.line);
+ sunzilog_init_kbdms(up);
/* Only enable interrupts if an ISR handler available */
if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
up->curregs[R9] |= MIE;
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 98ab649c1ff9..bb6ce6bba32f 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -1,7 +1,7 @@
/*
* Driver for NEC VR4100 series Serial Interface Unit.
*
- * Copyright (C) 2004-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2004-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* Based on drivers/serial/8250.c, by Russell King.
*
@@ -840,6 +840,19 @@ static int __devinit siu_console_init(void)
console_initcall(siu_console_init);
+void __init vr41xx_siu_early_setup(struct uart_port *port)
+{
+ if (port->type == PORT_UNKNOWN)
+ return;
+
+ siu_uart_ports[port->line].line = port->line;
+ siu_uart_ports[port->line].type = port->type;
+ siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
+ siu_uart_ports[port->line].mapbase = port->mapbase;
+ siu_uart_ports[port->line].mapbase = port->mapbase;
+ siu_uart_ports[port->line].ops = &siu_uart_ops;
+}
+
#define SERIAL_VR41XX_CONSOLE &siu_console
#else
#define SERIAL_VR41XX_CONSOLE NULL
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index d8107890db15..fae9e8f3d092 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -5,11 +5,9 @@
# nobody's needed a slave side API yet. The master-role API is not
# fully appropriate there, so it'd need some thought to do well.
#
-menu "SPI support"
- depends on HAS_IOMEM
-
-config SPI
+menuconfig SPI
bool "SPI support"
+ depends on HAS_IOMEM
help
The "Serial Peripheral Interface" is a low level synchronous
protocol. Chips that support SPI can have data transfer rates
@@ -28,9 +26,11 @@ config SPI
(half duplex), SSP, SSI, and PSP. This driver framework should
work with most such devices and controllers.
+if SPI
+
config SPI_DEBUG
boolean "Debug support for SPI drivers"
- depends on SPI && DEBUG_KERNEL
+ depends on DEBUG_KERNEL
help
Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
sysfs, and debugfs support in SPI controller and protocol drivers.
@@ -245,5 +245,4 @@ config SPI_TLE62X0
# (slave support would go here)
-endmenu # "SPI support"
-
+endif # SPI
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 1749a27be066..02c8e305b14f 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -616,7 +616,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
return -ESHUTDOWN;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (!(xfer->tx_buf || xfer->rx_buf)) {
+ if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
dev_dbg(&spi->dev, "missing rx or tx buf\n");
return -EINVAL;
}
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
index 5f00bd6500ef..d9ae111c27ae 100644
--- a/drivers/spi/omap_uwire.c
+++ b/drivers/spi/omap_uwire.c
@@ -151,7 +151,7 @@ static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
if (time_after(jiffies, max_jiffies)) {
printk(KERN_ERR "%s: timeout. reg=%#06x "
"mask=%#06x val=%#06x\n",
- __FUNCTION__, w, mask, val);
+ __func__, w, mask, val);
return -1;
}
c++;
@@ -437,7 +437,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
}
omap_uwire_configure_mode(spi->chip_select, flags);
pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n",
- __FUNCTION__, flags,
+ __func__, flags,
clk_get_rate(uwire->ck) / 1000,
rate / 1000);
status = 0;
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 147e26a78d64..654bb58be630 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -67,8 +67,11 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
#define DEFINE_SSP_REG(reg, off) \
-static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
-static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
+static inline u32 read_##reg(void const __iomem *p) \
+{ return __raw_readl(p + (off)); } \
+\
+static inline void write_##reg(u32 v, void __iomem *p) \
+{ __raw_writel(v, p + (off)); }
DEFINE_SSP_REG(SSCR0, 0x00)
DEFINE_SSP_REG(SSCR1, 0x04)
@@ -106,7 +109,7 @@ struct driver_data {
u32 *null_dma_buf;
/* SSP register addresses */
- void *ioaddr;
+ void __iomem *ioaddr;
u32 ssdr_physical;
/* SSP masks*/
@@ -173,7 +176,7 @@ static int flush(struct driver_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
do {
while (read_SSSR(reg) & SSSR_RNE) {
@@ -191,7 +194,7 @@ static void null_cs_control(u32 command)
static int null_writer(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
@@ -206,7 +209,7 @@ static int null_writer(struct driver_data *drv_data)
static int null_reader(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
while ((read_SSSR(reg) & SSSR_RNE)
@@ -220,7 +223,7 @@ static int null_reader(struct driver_data *drv_data)
static int u8_writer(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|| (drv_data->tx == drv_data->tx_end))
@@ -234,7 +237,7 @@ static int u8_writer(struct driver_data *drv_data)
static int u8_reader(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
while ((read_SSSR(reg) & SSSR_RNE)
&& (drv_data->rx < drv_data->rx_end)) {
@@ -247,7 +250,7 @@ static int u8_reader(struct driver_data *drv_data)
static int u16_writer(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|| (drv_data->tx == drv_data->tx_end))
@@ -261,7 +264,7 @@ static int u16_writer(struct driver_data *drv_data)
static int u16_reader(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
while ((read_SSSR(reg) & SSSR_RNE)
&& (drv_data->rx < drv_data->rx_end)) {
@@ -274,7 +277,7 @@ static int u16_reader(struct driver_data *drv_data)
static int u32_writer(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|| (drv_data->tx == drv_data->tx_end))
@@ -288,7 +291,7 @@ static int u32_writer(struct driver_data *drv_data)
static int u32_reader(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
while ((read_SSSR(reg) & SSSR_RNE)
&& (drv_data->rx < drv_data->rx_end)) {
@@ -412,7 +415,7 @@ static void giveback(struct driver_data *drv_data)
msg->complete(msg->context);
}
-static int wait_ssp_rx_stall(void *ioaddr)
+static int wait_ssp_rx_stall(void const __iomem *ioaddr)
{
unsigned long limit = loops_per_jiffy << 1;
@@ -432,9 +435,9 @@ static int wait_dma_channel_stop(int channel)
return limit;
}
-void dma_error_stop(struct driver_data *drv_data, const char *msg)
+static void dma_error_stop(struct driver_data *drv_data, const char *msg)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
/* Stop and reset */
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
@@ -456,7 +459,7 @@ void dma_error_stop(struct driver_data *drv_data, const char *msg)
static void dma_transfer_complete(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
struct spi_message *msg = drv_data->cur_msg;
/* Clear and disable interrupts on SSP and DMA channels*/
@@ -536,7 +539,7 @@ static void dma_handler(int channel, void *data)
static irqreturn_t dma_transfer(struct driver_data *drv_data)
{
u32 irq_status;
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
irq_status = read_SSSR(reg) & drv_data->mask_sr;
if (irq_status & SSSR_ROR) {
@@ -570,7 +573,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
static void int_error_stop(struct driver_data *drv_data, const char* msg)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
/* Stop and reset SSP */
write_SSSR(drv_data->clear_sr, reg);
@@ -588,7 +591,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
static void int_transfer_complete(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
/* Stop SSP */
write_SSSR(drv_data->clear_sr, reg);
@@ -614,7 +617,7 @@ static void int_transfer_complete(struct driver_data *drv_data)
static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
{
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
@@ -675,7 +678,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
static irqreturn_t ssp_int(int irq, void *dev_id)
{
struct driver_data *drv_data = dev_id;
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
if (!drv_data->cur_msg) {
@@ -695,7 +698,8 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
return drv_data->transfer_handler(drv_data);
}
-int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi,
+static int set_dma_burst_and_threshold(struct chip_data *chip,
+ struct spi_device *spi,
u8 bits_per_word, u32 *burst_code,
u32 *threshold)
{
@@ -809,7 +813,7 @@ static void pump_transfers(unsigned long data)
struct spi_transfer *previous = NULL;
struct chip_data *chip = NULL;
struct ssp_device *ssp = drv_data->ssp;
- void *reg = drv_data->ioaddr;
+ void __iomem *reg = drv_data->ioaddr;
u32 clk_div = 0;
u8 bits = 0;
u32 speed = 0;
@@ -1338,7 +1342,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info;
struct spi_master *master;
- struct driver_data *drv_data = 0;
+ struct driver_data *drv_data = NULL;
struct ssp_device *ssp;
int status = 0;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 71e881419cdd..96cc39ecb6e2 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -214,7 +214,7 @@ int spi_bitbang_setup(struct spi_device *spi)
return retval;
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
- __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
+ __func__, spi->mode & (SPI_CPOL | SPI_CPHA),
spi->bits_per_word, 2 * cs->nsecs);
/* NOTE we _need_ to call chipselect() early, ideally with adapter
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index d4ba640366b6..c730d05bfeb6 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -270,19 +270,26 @@ struct chip_data {
static void pump_messages(struct work_struct *work);
-static int flush(struct driver_data *drv_data)
+static void flush(struct driver_data *drv_data)
{
- unsigned long limit = loops_per_jiffy << 1;
void __iomem *regs = drv_data->regs;
- volatile u32 d;
+ u32 control;
dev_dbg(&drv_data->pdev->dev, "flush\n");
+
+ /* Wait for end of transaction */
do {
- while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR)
- d = readl(regs + SPI_RXDATA);
- } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--);
+ control = readl(regs + SPI_CONTROL);
+ } while (control & SPI_CONTROL_XCH);
+
+ /* Release chip select if requested, transfer delays are
+ handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(SPI_CS_DEASSERT);
- return limit;
+ /* Disable SPI to flush FIFOs */
+ writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL);
+ writel(control, regs + SPI_CONTROL);
}
static void restore_state(struct driver_data *drv_data)
@@ -570,6 +577,7 @@ static void giveback(struct spi_message *message, struct driver_data *drv_data)
writel(0, regs + SPI_INT_STATUS);
writel(0, regs + SPI_DMA);
+ /* Unconditioned deselct */
drv_data->cs_control(SPI_CS_DEASSERT);
message->state = NULL;
@@ -592,13 +600,10 @@ static void dma_err_handler(int channel, void *data, int errcode)
/* Disable both rx and tx dma channels */
imx_dma_disable(drv_data->rx_channel);
imx_dma_disable(drv_data->tx_channel);
-
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_err_handler - flush failed\n");
-
unmap_dma_buffers(drv_data);
+ flush(drv_data);
+
msg->state = ERROR_STATE;
tasklet_schedule(&drv_data->pump_transfers);
}
@@ -612,8 +617,7 @@ static void dma_tx_handler(int channel, void *data)
imx_dma_disable(channel);
/* Now waits for TX FIFO empty */
- writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE,
- drv_data->regs + SPI_INT_STATUS);
+ writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS);
}
static irqreturn_t dma_transfer(struct driver_data *drv_data)
@@ -621,19 +625,18 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
u32 status;
struct spi_message *msg = drv_data->cur_msg;
void __iomem *regs = drv_data->regs;
- unsigned long limit;
status = readl(regs + SPI_INT_STATUS);
- if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) {
+ if ((status & (SPI_INTEN_RO | SPI_STATUS_RO))
+ == (SPI_INTEN_RO | SPI_STATUS_RO)) {
writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+ imx_dma_disable(drv_data->tx_channel);
imx_dma_disable(drv_data->rx_channel);
unmap_dma_buffers(drv_data);
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer - flush failed\n");
+ flush(drv_data);
dev_warn(&drv_data->pdev->dev,
"dma_transfer - fifo overun\n");
@@ -649,20 +652,17 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
if (drv_data->rx) {
/* Wait end of transfer before read trailing data */
- limit = loops_per_jiffy << 1;
- while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) &&
- limit--);
-
- if (limit == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer - end of tx failed\n");
- else
- dev_dbg(&drv_data->pdev->dev,
- "dma_transfer - end of tx\n");
+ while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH)
+ cpu_relax();
imx_dma_disable(drv_data->rx_channel);
unmap_dma_buffers(drv_data);
+ /* Release chip select if requested, transfer delays are
+ handled in pump_transfers() */
+ if (drv_data->cs_change)
+ drv_data->cs_control(SPI_CS_DEASSERT);
+
/* Calculate number of trailing data and read them */
dev_dbg(&drv_data->pdev->dev,
"dma_transfer - test = 0x%08X\n",
@@ -676,19 +676,12 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
/* Write only transfer */
unmap_dma_buffers(drv_data);
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "dma_transfer - flush failed\n");
+ flush(drv_data);
}
/* End of transfer, update total byte transfered */
msg->actual_length += drv_data->len;
- /* Release chip select if requested, transfer delays are
- handled in pump_transfers() */
- if (drv_data->cs_change)
- drv_data->cs_control(SPI_CS_DEASSERT);
-
/* Move to next transfer */
msg->state = next_transfer(drv_data);
@@ -711,44 +704,43 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
status = readl(regs + SPI_INT_STATUS);
- while (status & SPI_STATUS_TH) {
+ if (status & SPI_INTEN_TE) {
+ /* TXFIFO Empty Interrupt on the last transfered word */
+ writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
dev_dbg(&drv_data->pdev->dev,
- "interrupt_wronly_transfer - status = 0x%08X\n", status);
+ "interrupt_wronly_transfer - end of tx\n");
- /* Pump data */
- if (write(drv_data)) {
- writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
- regs + SPI_INT_STATUS);
+ flush(drv_data);
- dev_dbg(&drv_data->pdev->dev,
- "interrupt_wronly_transfer - end of tx\n");
+ /* Update total byte transfered */
+ msg->actual_length += drv_data->len;
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "interrupt_wronly_transfer - "
- "flush failed\n");
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
- /* End of transfer, update total byte transfered */
- msg->actual_length += drv_data->len;
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
- /* Release chip select if requested, transfer delays are
- handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(SPI_CS_DEASSERT);
+ return IRQ_HANDLED;
+ } else {
+ while (status & SPI_STATUS_TH) {
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_wronly_transfer - status = 0x%08X\n",
+ status);
- /* Move to next transfer */
- msg->state = next_transfer(drv_data);
+ /* Pump data */
+ if (write(drv_data)) {
+ /* End of TXFIFO writes,
+ now wait until TXFIFO is empty */
+ writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+ return IRQ_HANDLED;
+ }
- /* Schedule transfer tasklet */
- tasklet_schedule(&drv_data->pump_transfers);
+ status = readl(regs + SPI_INT_STATUS);
- return IRQ_HANDLED;
+ /* We did something */
+ handled = IRQ_HANDLED;
}
-
- status = readl(regs + SPI_INT_STATUS);
-
- /* We did something */
- handled = IRQ_HANDLED;
}
return handled;
@@ -758,45 +750,31 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
{
struct spi_message *msg = drv_data->cur_msg;
void __iomem *regs = drv_data->regs;
- u32 status;
+ u32 status, control;
irqreturn_t handled = IRQ_NONE;
unsigned long limit;
status = readl(regs + SPI_INT_STATUS);
- while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+ if (status & SPI_INTEN_TE) {
+ /* TXFIFO Empty Interrupt on the last transfered word */
+ writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
dev_dbg(&drv_data->pdev->dev,
- "interrupt_transfer - status = 0x%08X\n", status);
-
- if (status & SPI_STATUS_RO) {
- writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
- regs + SPI_INT_STATUS);
-
- dev_warn(&drv_data->pdev->dev,
- "interrupt_transfer - fifo overun\n"
- " data not yet written = %d\n"
- " data not yet read = %d\n",
- data_to_write(drv_data),
- data_to_read(drv_data));
-
- if (flush(drv_data) == 0)
- dev_err(&drv_data->pdev->dev,
- "interrupt_transfer - flush failed\n");
-
- msg->state = ERROR_STATE;
- tasklet_schedule(&drv_data->pump_transfers);
+ "interrupt_transfer - end of tx\n");
- return IRQ_HANDLED;
- }
-
- /* Pump data */
- read(drv_data);
- if (write(drv_data)) {
- writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
- regs + SPI_INT_STATUS);
+ if (msg->state == ERROR_STATE) {
+ /* RXFIFO overrun was detected and message aborted */
+ flush(drv_data);
+ } else {
+ /* Wait for end of transaction */
+ do {
+ control = readl(regs + SPI_CONTROL);
+ } while (control & SPI_CONTROL_XCH);
- dev_dbg(&drv_data->pdev->dev,
- "interrupt_transfer - end of tx\n");
+ /* Release chip select if requested, transfer delays are
+ handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(SPI_CS_DEASSERT);
/* Read trailing bytes */
limit = loops_per_jiffy << 1;
@@ -810,27 +788,54 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"interrupt_transfer - end of rx\n");
- /* End of transfer, update total byte transfered */
+ /* Update total byte transfered */
msg->actual_length += drv_data->len;
- /* Release chip select if requested, transfer delays are
- handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(SPI_CS_DEASSERT);
-
/* Move to next transfer */
msg->state = next_transfer(drv_data);
+ }
- /* Schedule transfer tasklet */
- tasklet_schedule(&drv_data->pump_transfers);
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
- return IRQ_HANDLED;
- }
+ return IRQ_HANDLED;
+ } else {
+ while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_transfer - status = 0x%08X\n",
+ status);
+
+ if (status & SPI_STATUS_RO) {
+ /* RXFIFO overrun, abort message end wait
+ until TXFIFO is empty */
+ writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+
+ dev_warn(&drv_data->pdev->dev,
+ "interrupt_transfer - fifo overun\n"
+ " data not yet written = %d\n"
+ " data not yet read = %d\n",
+ data_to_write(drv_data),
+ data_to_read(drv_data));
+
+ msg->state = ERROR_STATE;
+
+ return IRQ_HANDLED;
+ }
- status = readl(regs + SPI_INT_STATUS);
+ /* Pump data */
+ read(drv_data);
+ if (write(drv_data)) {
+ /* End of TXFIFO writes,
+ now wait until TXFIFO is empty */
+ writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+ return IRQ_HANDLED;
+ }
- /* We did something */
- handled = IRQ_HANDLED;
+ status = readl(regs + SPI_INT_STATUS);
+
+ /* We did something */
+ handled = IRQ_HANDLED;
+ }
}
return handled;
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index be15a6213205..189f706b9e4b 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -310,7 +310,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
return retval;
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
- __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
+ __func__, spi->mode & (SPI_CPOL | SPI_CPHA),
spi->bits_per_word, 2 * mpc83xx_spi->nsecs);
/* NOTE we _need_ to call chipselect() early, ideally with adapter
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index b7476b888197..34bfb7dd7764 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -169,7 +169,7 @@ static int s3c24xx_spi_setup(struct spi_device *spi)
}
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
- __FUNCTION__, spi->mode, spi->bits_per_word,
+ __func__, spi->mode, spi->bits_per_word,
spi->max_speed_hz);
return 0;
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index cf6aef34fe25..113a0468ffcb 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -151,13 +151,13 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
hz = (t) ? t->speed_hz : spi->max_speed_hz;
if (bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __FUNCTION__, bits_per_word);
+ __func__, bits_per_word);
return -EINVAL;
}
if (hz && xspi->speed_hz > hz) {
dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
- __FUNCTION__, hz);
+ __func__, hz);
return -EINVAL;
}
@@ -181,7 +181,7 @@ static int xilinx_spi_setup(struct spi_device *spi)
if (spi->mode & ~MODEBITS) {
dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
- __FUNCTION__, spi->mode & ~MODEBITS);
+ __func__, spi->mode & ~MODEBITS);
return -EINVAL;
}
@@ -190,7 +190,7 @@ static int xilinx_spi_setup(struct spi_device *spi)
return retval;
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
- __FUNCTION__, spi->mode & MODEBITS, spi->bits_per_word, 0);
+ __func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
return 0;
}
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 17e71d56f31e..4b628526df09 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig THERMAL
- bool "Generic Thermal sysfs driver"
+ tristate "Generic Thermal sysfs driver"
help
Generic Thermal Sysfs driver offers a generic mechanism for
thermal management. Usually it's made up of one or more thermal
@@ -11,4 +11,4 @@ menuconfig THERMAL
Each thermal zone contains its own temperature, trip points,
cooling devices.
All platforms with ACPI thermal support can use this driver.
- If you want this support, you should say Y here.
+ If you want this support, you should say Y or M here.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 8ef1232de376..31108a01c22e 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -2,4 +2,4 @@
# Makefile for sensor chip drivers.
#
-obj-$(CONFIG_THERMAL) += thermal.o
+obj-$(CONFIG_THERMAL) += thermal_sys.o
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal_sys.c
index 7f79bbf652d7..6098787341f3 100644
--- a/drivers/thermal/thermal.c
+++ b/drivers/thermal/thermal_sys.c
@@ -31,7 +31,7 @@
#include <linux/thermal.h>
#include <linux/spinlock.h>
-MODULE_AUTHOR("Zhang Rui")
+MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL");
@@ -295,6 +295,164 @@ thermal_cooling_device_trip_point_show(struct device *dev,
/* Device management */
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* hwmon sys I/F */
+#include <linux/hwmon.h>
+static LIST_HEAD(thermal_hwmon_list);
+
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_hwmon_device *hwmon = dev->driver_data;
+ return sprintf(buf, "%s\n", hwmon->type);
+}
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+ struct thermal_zone_device *tz
+ = container_of(hwmon_attr, struct thermal_zone_device,
+ temp_input);
+
+ return tz->ops->get_temp(tz, buf);
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+ struct thermal_zone_device *tz
+ = container_of(hwmon_attr, struct thermal_zone_device,
+ temp_crit);
+
+ return tz->ops->get_trip_temp(tz, 0, buf);
+}
+
+
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ struct thermal_hwmon_device *hwmon;
+ int new_hwmon_device = 1;
+ int result;
+
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(hwmon, &thermal_hwmon_list, node)
+ if (!strcmp(hwmon->type, tz->type)) {
+ new_hwmon_device = 0;
+ mutex_unlock(&thermal_list_lock);
+ goto register_sys_interface;
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&hwmon->tz_list);
+ strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
+ hwmon->device = hwmon_device_register(NULL);
+ if (IS_ERR(hwmon->device)) {
+ result = PTR_ERR(hwmon->device);
+ goto free_mem;
+ }
+ hwmon->device->driver_data = hwmon;
+ result = device_create_file(hwmon->device, &dev_attr_name);
+ if (result)
+ goto unregister_hwmon_device;
+
+ register_sys_interface:
+ tz->hwmon = hwmon;
+ hwmon->count++;
+
+ snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
+ "temp%d_input", hwmon->count);
+ tz->temp_input.attr.attr.name = tz->temp_input.name;
+ tz->temp_input.attr.attr.mode = 0444;
+ tz->temp_input.attr.show = temp_input_show;
+ result = device_create_file(hwmon->device, &tz->temp_input.attr);
+ if (result)
+ goto unregister_hwmon_device;
+
+ if (tz->ops->get_crit_temp) {
+ unsigned long temperature;
+ if (!tz->ops->get_crit_temp(tz, &temperature)) {
+ snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
+ "temp%d_crit", hwmon->count);
+ tz->temp_crit.attr.attr.name = tz->temp_crit.name;
+ tz->temp_crit.attr.attr.mode = 0444;
+ tz->temp_crit.attr.show = temp_crit_show;
+ result = device_create_file(hwmon->device,
+ &tz->temp_crit.attr);
+ if (result)
+ goto unregister_hwmon_device;
+ }
+ }
+
+ mutex_lock(&thermal_list_lock);
+ if (new_hwmon_device)
+ list_add_tail(&hwmon->node, &thermal_hwmon_list);
+ list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
+ mutex_unlock(&thermal_list_lock);
+
+ return 0;
+
+ unregister_hwmon_device:
+ device_remove_file(hwmon->device, &tz->temp_crit.attr);
+ device_remove_file(hwmon->device, &tz->temp_input.attr);
+ if (new_hwmon_device) {
+ device_remove_file(hwmon->device, &dev_attr_name);
+ hwmon_device_unregister(hwmon->device);
+ }
+ free_mem:
+ if (new_hwmon_device)
+ kfree(hwmon);
+
+ return result;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ struct thermal_hwmon_device *hwmon = tz->hwmon;
+
+ tz->hwmon = NULL;
+ device_remove_file(hwmon->device, &tz->temp_input.attr);
+ device_remove_file(hwmon->device, &tz->temp_crit.attr);
+
+ mutex_lock(&thermal_list_lock);
+ list_del(&tz->hwmon_node);
+ if (!list_empty(&hwmon->tz_list)) {
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+ list_del(&hwmon->node);
+ mutex_unlock(&thermal_list_lock);
+
+ device_remove_file(hwmon->device, &dev_attr_name);
+ hwmon_device_unregister(hwmon->device);
+ kfree(hwmon);
+}
+#else
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ return 0;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+}
+#endif
+
+
/**
* thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
* @tz: thermal zone device
@@ -642,6 +800,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
goto unregister;
}
+ result = thermal_add_hwmon_sysfs(tz);
+ if (result)
+ goto unregister;
+
mutex_lock(&thermal_list_lock);
list_add_tail(&tz->node, &thermal_tz_list);
if (ops->bind)
@@ -700,6 +862,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
for (count = 0; count < tz->trips; count++)
TRIP_POINT_ATTR_REMOVE(&tz->device, count);
+ thermal_remove_hwmon_sysfs(tz);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index a51eeedc18d4..5ea3093bc40f 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -38,6 +38,7 @@
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
+#include <asm/unaligned.h>
#include "usbatm.h"
@@ -444,7 +445,7 @@ CXACRU_ALL_FILES(INIT);
/* the following three functions are stolen from drivers/usb/core/message.c */
static void cxacru_blocking_completion(struct urb *urb)
{
- complete((struct completion *)urb->context);
+ complete(urb->context);
}
static void cxacru_timeout_kill(unsigned long data)
@@ -573,7 +574,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
u32 *data, int size)
{
int ret, len;
- u32 *buf;
+ __le32 *buf;
int offb, offd;
const int stride = CMD_PACKET_SIZE / (4 * 2) - 1;
int buflen = ((size - 1) / stride + 1 + size * 2) * 4;
@@ -837,7 +838,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
buf[offb++] = l;
buf[offb++] = code1;
buf[offb++] = code2;
- *((u32 *) (buf + offb)) = cpu_to_le32(addr);
+ put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb));
offb += 4;
addr += l;
if(l)
@@ -874,8 +875,9 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
int off;
struct usbatm_data *usbatm = instance->usbatm;
struct usb_device *usb_dev = usbatm->usb_dev;
- u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct };
- u32 val;
+ __le16 signature[] = { usb_dev->descriptor.idVendor,
+ usb_dev->descriptor.idProduct };
+ __le32 val;
dbg("cxacru_upload_firmware");
@@ -955,7 +957,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
/* Load config data (le32), doing one packet at a time */
if (cf)
for (off = 0; off < cf->size / 4; ) {
- u32 buf[CMD_PACKET_SIZE / 4 - 1];
+ __le32 buf[CMD_PACKET_SIZE / 4 - 1];
int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
buf[0] = cpu_to_le32(len);
for (i = 0; i < len; i++, off++) {
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index c5ec1a55eee3..4220f22b6660 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -83,7 +83,7 @@
if (debug >= 1) \
dev_dbg(&(usb_dev)->dev, \
"[ueagle-atm dbg] %s: " format, \
- __FUNCTION__, ##args); \
+ __func__, ##args); \
} while (0)
#define uea_vdbg(usb_dev, format, args...) \
@@ -94,10 +94,10 @@
} while (0)
#define uea_enters(usb_dev) \
- uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
+ uea_vdbg(usb_dev, "entering %s\n", __func__)
#define uea_leaves(usb_dev) \
- uea_vdbg(usb_dev, "leaving %s\n", __FUNCTION__)
+ uea_vdbg(usb_dev, "leaving %s\n", __func__)
#define uea_err(usb_dev, format,args...) \
dev_err(&(usb_dev)->dev ,"[UEAGLE-ATM] " format , ##args)
@@ -996,7 +996,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
bi.dwSize = cpu_to_be32(blocksize);
- bi.dwAddress = swab32(blockidx->PageAddress);
+ bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress));
uea_dbg(INS_TO_USBDEV(sc),
"sending block %u for DSP page %u size %u address %x\n",
@@ -1040,7 +1040,7 @@ static void uea_load_page_e4(struct work_struct *work)
return;
p = (struct l1_code *) sc->dsp_firm->data;
- if (pageno >= p->page_header[0].PageNumber) {
+ if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) {
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
return;
}
@@ -1065,7 +1065,7 @@ static void uea_load_page_e4(struct work_struct *work)
bi.bPageNumber = 0xff;
bi.wReserved = cpu_to_be16(UEA_RESERVED);
bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
- bi.dwAddress = swab32(p->page_header[0].PageAddress);
+ bi.dwAddress = cpu_to_be32(le32_to_cpu(p->page_header[0].PageAddress));
/* send block info through the IDMA pipe */
if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index e717f5b1caee..07228721cafe 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -80,6 +80,7 @@
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/wait.h>
+#include <linux/kthread.h>
#ifdef VERBOSE_DEBUG
static int usbatm_print_packet(const unsigned char *data, int len);
@@ -1014,10 +1015,7 @@ static int usbatm_do_heavy_init(void *arg)
struct usbatm_data *instance = arg;
int ret;
- daemonize(instance->driver->driver_name);
allow_signal(SIGTERM);
- instance->thread_pid = current->pid;
-
complete(&instance->thread_started);
ret = instance->driver->heavy_init(instance, instance->usb_intf);
@@ -1026,7 +1024,7 @@ static int usbatm_do_heavy_init(void *arg)
ret = usbatm_atm_init(instance);
mutex_lock(&instance->serialize);
- instance->thread_pid = -1;
+ instance->thread = NULL;
mutex_unlock(&instance->serialize);
complete_and_exit(&instance->thread_exited, ret);
@@ -1034,13 +1032,18 @@ static int usbatm_do_heavy_init(void *arg)
static int usbatm_heavy_init(struct usbatm_data *instance)
{
- int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
-
- if (ret < 0) {
- usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
- return ret;
+ struct task_struct *t;
+
+ t = kthread_create(usbatm_do_heavy_init, instance,
+ instance->driver->driver_name);
+ if (IS_ERR(t)) {
+ usb_err(instance, "%s: failed to create kernel_thread (%ld)!\n",
+ __func__, PTR_ERR(t));
+ return PTR_ERR(t);
}
+ instance->thread = t;
+ wake_up_process(t);
wait_for_completion(&instance->thread_started);
return 0;
@@ -1124,7 +1127,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */
mutex_init(&instance->serialize);
- instance->thread_pid = -1;
+ instance->thread = NULL;
init_completion(&instance->thread_started);
init_completion(&instance->thread_exited);
@@ -1287,8 +1290,8 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
mutex_lock(&instance->serialize);
instance->disconnected = 1;
- if (instance->thread_pid >= 0)
- kill_proc(instance->thread_pid, SIGTERM, 1);
+ if (instance->thread != NULL)
+ send_sig(SIGTERM, instance->thread, 1);
mutex_unlock(&instance->serialize);
wait_for_completion(&instance->thread_exited);
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index fc6c2be5999c..e6887c6cf3cf 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -175,7 +175,7 @@ struct usbatm_data {
int disconnected;
/* heavy init */
- int thread_pid;
+ struct task_struct *thread;
struct completion thread_started;
struct completion thread_exited;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 0147ea39340e..7b572e75e73c 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -31,6 +31,7 @@
* v0.23 - use softirq for rx processing, as needed by tty layer
* v0.24 - change probe method to evaluate CDC union descriptor
* v0.25 - downstream tasks paralelized to maximize throughput
+ * v0.26 - multiple write urbs, writesize increased
*/
/*
@@ -72,7 +73,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.25"
+#define DRIVER_VERSION "v0.26"
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
@@ -118,7 +119,7 @@ static int acm_wb_alloc(struct acm *acm)
int i, wbn;
struct acm_wb *wb;
- wbn = acm->write_current;
+ wbn = 0;
i = 0;
for (;;) {
wb = &acm->wb[wbn];
@@ -132,11 +133,6 @@ static int acm_wb_alloc(struct acm *acm)
}
}
-static void acm_wb_free(struct acm *acm, int wbn)
-{
- acm->wb[wbn].use = 0;
-}
-
static int acm_wb_is_avail(struct acm *acm)
{
int i, n;
@@ -156,26 +152,22 @@ static inline int acm_wb_is_used(struct acm *acm, int wbn)
/*
* Finish write.
*/
-static void acm_write_done(struct acm *acm)
+static void acm_write_done(struct acm *acm, struct acm_wb *wb)
{
unsigned long flags;
- int wbn;
spin_lock_irqsave(&acm->write_lock, flags);
acm->write_ready = 1;
- wbn = acm->write_current;
- acm_wb_free(acm, wbn);
- acm->write_current = (wbn + 1) % ACM_NW;
+ wb->use = 0;
spin_unlock_irqrestore(&acm->write_lock, flags);
}
/*
* Poke write.
*/
-static int acm_write_start(struct acm *acm)
+static int acm_write_start(struct acm *acm, int wbn)
{
unsigned long flags;
- int wbn;
struct acm_wb *wb;
int rc;
@@ -190,24 +182,24 @@ static int acm_write_start(struct acm *acm)
return 0; /* A white lie */
}
- wbn = acm->write_current;
if (!acm_wb_is_used(acm, wbn)) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0;
}
wb = &acm->wb[wbn];
- acm->write_ready = 0;
+ if(acm_wb_is_avail(acm) <= 1)
+ acm->write_ready = 0;
spin_unlock_irqrestore(&acm->write_lock, flags);
- acm->writeurb->transfer_buffer = wb->buf;
- acm->writeurb->transfer_dma = wb->dmah;
- acm->writeurb->transfer_buffer_length = wb->len;
- acm->writeurb->dev = acm->dev;
+ wb->urb->transfer_buffer = wb->buf;
+ wb->urb->transfer_dma = wb->dmah;
+ wb->urb->transfer_buffer_length = wb->len;
+ wb->urb->dev = acm->dev;
- if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
+ if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
dbg("usb_submit_urb(write bulk) failed: %d", rc);
- acm_write_done(acm);
+ acm_write_done(acm, wb);
}
return rc;
}
@@ -268,10 +260,10 @@ static void acm_ctrl_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
+ dbg("%s - urb shutting down with status: %d", __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
+ dbg("%s - nonzero urb status received: %d", __func__, status);
goto exit;
}
@@ -315,7 +307,7 @@ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __func__, retval);
}
/* data interface returns incoming bytes, or we got unthrottled */
@@ -450,12 +442,13 @@ urbs:
/* data interface wrote those outgoing bytes */
static void acm_write_bulk(struct urb *urb)
{
- struct acm *acm = (struct acm *)urb->context;
+ struct acm *acm;
+ struct acm_wb *wb = urb->context;
dbg("Entering acm_write_bulk with status %d", urb->status);
- acm_write_done(acm);
- acm_write_start(acm);
+ acm = wb->instance;
+ acm_write_done(acm, wb);
if (ACM_READY(acm))
schedule_work(&acm->work);
}
@@ -489,6 +482,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
else
rv = 0;
+ set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
tty->driver_data = acm;
acm->tty = tty;
@@ -556,7 +550,8 @@ static void acm_tty_unregister(struct acm *acm)
usb_put_intf(acm->control);
acm_table[acm->minor] = NULL;
usb_free_urb(acm->ctrlurb);
- usb_free_urb(acm->writeurb);
+ for (i = 0; i < ACM_NW; i++)
+ usb_free_urb(acm->wb[i].urb);
for (i = 0; i < nr; i++)
usb_free_urb(acm->ru[i].urb);
kfree(acm->country_codes);
@@ -577,7 +572,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (acm->dev) {
acm_set_control(acm, acm->ctrlout = 0);
usb_kill_urb(acm->ctrlurb);
- usb_kill_urb(acm->writeurb);
+ for (i = 0; i < ACM_NW; i++)
+ usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < nr; i++)
usb_kill_urb(acm->ru[i].urb);
usb_autopm_put_interface(acm->control);
@@ -605,7 +601,6 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
spin_lock_irqsave(&acm->write_lock, flags);
if ((wbn = acm_wb_alloc(acm)) < 0) {
spin_unlock_irqrestore(&acm->write_lock, flags);
- acm_write_start(acm);
return 0;
}
wb = &acm->wb[wbn];
@@ -616,7 +611,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
wb->len = count;
spin_unlock_irqrestore(&acm->write_lock, flags);
- if ((stat = acm_write_start(acm)) < 0)
+ if ((stat = acm_write_start(acm, wbn)) < 0)
return stat;
return count;
}
@@ -809,7 +804,7 @@ static int acm_probe (struct usb_interface *intf,
{
struct usb_cdc_union_desc *union_header = NULL;
struct usb_cdc_country_functional_desc *cfd = NULL;
- char *buffer = intf->altsetting->extra;
+ unsigned char *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface;
struct usb_interface *data_interface;
@@ -886,9 +881,13 @@ static int acm_probe (struct usb_interface *intf,
if ((call_management_function & 3) != 3)
err("This device cannot do calls on its own. It is no modem.");
break;
-
default:
- err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
+ /* there are LOTS more CDC descriptors that
+ * could legitimately be found here.
+ */
+ dev_dbg(&intf->dev, "Ignoring descriptor: "
+ "type %02x, length %d\n",
+ buffer[2], buffer[0]);
break;
}
next_desc:
@@ -976,7 +975,7 @@ skip_normal_probe:
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
- acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
+ acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
acm->control = control_interface;
acm->data = data_interface;
acm->minor = minor;
@@ -1031,10 +1030,19 @@ skip_normal_probe:
goto alloc_fail7;
}
}
- acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!acm->writeurb) {
- dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
- goto alloc_fail7;
+ for(i = 0; i < ACM_NW; i++)
+ {
+ struct acm_wb *snd = &(acm->wb[i]);
+
+ if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
+ dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
+ goto alloc_fail7;
+ }
+
+ usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+ NULL, acm->writesize, acm_write_bulk, snd);
+ snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ snd->instance = acm;
}
usb_set_intfdata (intf, acm);
@@ -1070,10 +1078,6 @@ skip_countries:
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
- usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
- NULL, acm->writesize, acm_write_bulk, acm);
- acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
-
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
acm_set_control(acm, acm->ctrlout);
@@ -1091,7 +1095,8 @@ skip_countries:
return 0;
alloc_fail8:
- usb_free_urb(acm->writeurb);
+ for (i = 0; i < ACM_NW; i++)
+ usb_free_urb(acm->wb[i].urb);
alloc_fail7:
for (i = 0; i < num_rx_buf; i++)
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
@@ -1115,7 +1120,8 @@ static void stop_data_traffic(struct acm *acm)
tasklet_disable(&acm->urb_task);
usb_kill_urb(acm->ctrlurb);
- usb_kill_urb(acm->writeurb);
+ for(i = 0; i < ACM_NW; i++)
+ usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->ru[i].urb);
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 8df6a57dcf9e..046e064b033a 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -59,7 +59,7 @@
* when processing onlcr, so we only need 2 buffers. These values must be
* powers of 2.
*/
-#define ACM_NW 2
+#define ACM_NW 16
#define ACM_NR 16
struct acm_wb {
@@ -67,6 +67,8 @@ struct acm_wb {
dma_addr_t dmah;
int len;
int use;
+ struct urb *urb;
+ struct acm *instance;
};
struct acm_rb {
@@ -88,7 +90,7 @@ struct acm {
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
- struct urb *ctrlurb, *writeurb; /* urbs */
+ struct urb *ctrlurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma; /* dma handles of buffers */
u8 *country_codes; /* country codes from device */
@@ -103,7 +105,6 @@ struct acm {
struct list_head spare_read_urbs;
struct list_head spare_read_bufs;
struct list_head filled_read_bufs;
- int write_current; /* current write buffer */
int write_used; /* number of non-empty write buffers */
int write_ready; /* write urb is not running */
spinlock_t write_lock;
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a2b0aa48b8ea..cc9f397e8398 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -76,8 +76,8 @@ config USB_DEVICE_CLASS
NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
config USB_DYNAMIC_MINORS
- bool "Dynamic USB minor allocation (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ bool "Dynamic USB minor allocation"
+ depends on USB
help
If you say Y here, the USB subsystem will use dynamic minor
allocation for any device that uses the USB major number.
@@ -102,31 +102,6 @@ config USB_SUSPEND
If you are unsure about this, say N here.
-config USB_PERSIST
- bool "USB device persistence during system suspend (DANGEROUS)"
- depends on USB && PM && EXPERIMENTAL
- default n
- help
-
- If you say Y here and enable the "power/persist" attribute
- for a USB device, the device's data structures will remain
- persistent across system suspend, even if the USB bus loses
- power. (This includes hibernation, also known as swsusp or
- suspend-to-disk.) The devices will reappear as if by magic
- when the system wakes up, with no need to unmount USB
- filesystems, rmmod host-controller drivers, or do anything
- else.
-
- WARNING: This option can be dangerous!
-
- If a USB device is replaced by another of the same type while
- the system is asleep, there's a good chance the kernel won't
- detect the change. Likewise if the media in a USB storage
- device is replaced. When this happens it's almost certain to
- cause data corruption and maybe even crash your system.
-
- If you are unsure, say N here.
-
config USB_OTG
bool
depends on USB && EXPERIMENTAL
@@ -136,14 +111,16 @@ config USB_OTG
config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
- depends on USB_OTG
- default y
+ depends on USB_OTG || EMBEDDED
+ default y if USB_OTG
+ default n if EMBEDDED
help
If you say Y here, the "otg_whitelist.h" file will be used as a
product whitelist, so USB peripherals not listed there will be
rejected during enumeration. This behavior is required by the
USB OTG specification for all devices not on your product's
- "Targeted Peripherals List".
+ "Targeted Peripherals List". "Embedded Hosts" are likewise
+ allowed to support only a limited number of peripherals.
Otherwise, peripherals not listed there will only generate a
warning and enumeration will continue. That's more like what
@@ -152,9 +129,10 @@ config USB_OTG_WHITELIST
config USB_OTG_BLACKLIST_HUB
bool "Disable external hubs"
- depends on USB_OTG
+ depends on USB_OTG || EMBEDDED
help
If you say Y here, then Linux will refuse to enumerate
external hubs. OTG hosts are allowed to reduce hardware
- and software costs by not supporting external hubs.
+ and software costs by not supporting external hubs. So
+ are "Emedded Hosts" that don't offer OTG support.
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index a92122a216bc..568244c99bdc 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -145,6 +145,23 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
}
+ /*
+ * Some buggy high speed devices have bulk endpoints using
+ * maxpacket sizes other than 512. High speed HCDs may not
+ * be able to handle that particular bug, so let's warn...
+ */
+ if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
+ && usb_endpoint_xfer_bulk(d)) {
+ unsigned maxp;
+
+ maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
+ if (maxp != 512)
+ dev_warn(ddev, "config %d interface %d altsetting %d "
+ "bulk endpoint 0x%X has invalid maxpacket %d\n",
+ cfgno, inum, asnum, d->bEndpointAddress,
+ maxp);
+ }
+
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index ae94176c64e4..de17738f3acb 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -647,6 +647,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
struct usbdevfs_ctrltransfer ctrl;
unsigned int tmo;
unsigned char *tbuf;
+ unsigned wLength;
int i, j, ret;
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
@@ -654,7 +655,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
if (ret)
return ret;
- if (ctrl.wLength > PAGE_SIZE)
+ wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
+ if (wLength > PAGE_SIZE)
return -EINVAL;
tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!tbuf)
@@ -946,8 +948,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
int ret, ifnum = -1;
int is_in;
- if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
- URB_NO_FSBR|URB_ZERO_PACKET))
+ if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
+ USBDEVFS_URB_SHORT_NOT_OK |
+ USBDEVFS_URB_NO_FSBR |
+ USBDEVFS_URB_ZERO_PACKET |
+ USBDEVFS_URB_NO_INTERRUPT))
return -EINVAL;
if (!uurb->buffer)
return -EINVAL;
@@ -1102,8 +1107,24 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->urb->pipe = (uurb->type << 30) |
__create_pipe(ps->dev, uurb->endpoint & 0xf) |
(uurb->endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb->flags |
- (is_in ? URB_DIR_IN : URB_DIR_OUT);
+
+ /* This tedious sequence is necessary because the URB_* flags
+ * are internal to the kernel and subject to change, whereas
+ * the USBDEVFS_URB_* flags are a user API and must not be changed.
+ */
+ u = (is_in ? URB_DIR_IN : URB_DIR_OUT);
+ if (uurb->flags & USBDEVFS_URB_ISO_ASAP)
+ u |= URB_ISO_ASAP;
+ if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK)
+ u |= URB_SHORT_NOT_OK;
+ if (uurb->flags & USBDEVFS_URB_NO_FSBR)
+ u |= URB_NO_FSBR;
+ if (uurb->flags & USBDEVFS_URB_ZERO_PACKET)
+ u |= URB_ZERO_PACKET;
+ if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT)
+ u |= URB_NO_INTERRUPT;
+ as->urb->transfer_flags = u;
+
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char *)dr;
as->urb->start_frame = uurb->start_frame;
@@ -1509,60 +1530,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case USBDEVFS_CONTROL:
- snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: CONTROL\n", __func__);
ret = proc_control(ps, p);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
break;
case USBDEVFS_BULK:
- snoop(&dev->dev, "%s: BULK\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: BULK\n", __func__);
ret = proc_bulk(ps, p);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
break;
case USBDEVFS_RESETEP:
- snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: RESETEP\n", __func__);
ret = proc_resetep(ps, p);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
break;
case USBDEVFS_RESET:
- snoop(&dev->dev, "%s: RESET\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: RESET\n", __func__);
ret = proc_resetdevice(ps);
break;
case USBDEVFS_CLEAR_HALT:
- snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
ret = proc_clearhalt(ps, p);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
break;
case USBDEVFS_GETDRIVER:
- snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: GETDRIVER\n", __func__);
ret = proc_getdriver(ps, p);
break;
case USBDEVFS_CONNECTINFO:
- snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: CONNECTINFO\n", __func__);
ret = proc_connectinfo(ps, p);
break;
case USBDEVFS_SETINTERFACE:
- snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: SETINTERFACE\n", __func__);
ret = proc_setintf(ps, p);
break;
case USBDEVFS_SETCONFIGURATION:
- snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__);
ret = proc_setconfig(ps, p);
break;
case USBDEVFS_SUBMITURB:
- snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
ret = proc_submiturb(ps, p);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
@@ -1571,60 +1592,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
#ifdef CONFIG_COMPAT
case USBDEVFS_SUBMITURB32:
- snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
ret = proc_submiturb_compat(ps, p);
if (ret >= 0)
inode->i_mtime = CURRENT_TIME;
break;
case USBDEVFS_REAPURB32:
- snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: REAPURB32\n", __func__);
ret = proc_reapurb_compat(ps, p);
break;
case USBDEVFS_REAPURBNDELAY32:
- snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__);
ret = proc_reapurbnonblock_compat(ps, p);
break;
case USBDEVFS_IOCTL32:
- snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: IOCTL\n", __func__);
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
break;
#endif
case USBDEVFS_DISCARDURB:
- snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: DISCARDURB\n", __func__);
ret = proc_unlinkurb(ps, p);
break;
case USBDEVFS_REAPURB:
- snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: REAPURB\n", __func__);
ret = proc_reapurb(ps, p);
break;
case USBDEVFS_REAPURBNDELAY:
- snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__);
ret = proc_reapurbnonblock(ps, p);
break;
case USBDEVFS_DISCSIGNAL:
- snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
ret = proc_disconnectsignal(ps, p);
break;
case USBDEVFS_CLAIMINTERFACE:
- snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);
ret = proc_claiminterface(ps, p);
break;
case USBDEVFS_RELEASEINTERFACE:
- snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__);
ret = proc_releaseinterface(ps, p);
break;
case USBDEVFS_IOCTL:
- snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
+ snoop(&dev->dev, "%s: IOCTL\n", __func__);
ret = proc_ioctl_default(ps, p);
break;
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 801b6f142fa7..1e56f1cfa6dc 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -157,7 +157,7 @@ static int usb_probe_device(struct device *dev)
struct usb_device *udev;
int error = -ENODEV;
- dev_dbg(dev, "%s\n", __FUNCTION__);
+ dev_dbg(dev, "%s\n", __func__);
if (!is_usb_device(dev)) /* Sanity check */
return error;
@@ -194,7 +194,7 @@ static int usb_probe_interface(struct device *dev)
const struct usb_device_id *id;
int error = -ENODEV;
- dev_dbg(dev, "%s\n", __FUNCTION__);
+ dev_dbg(dev, "%s\n", __func__);
if (is_usb_device(dev)) /* Sanity check */
return error;
@@ -211,7 +211,7 @@ static int usb_probe_interface(struct device *dev)
if (!id)
id = usb_match_dynamic_id(intf, driver);
if (id) {
- dev_dbg(dev, "%s - got id\n", __FUNCTION__);
+ dev_dbg(dev, "%s - got id\n", __func__);
error = usb_autoresume_device(udev);
if (error)
@@ -793,9 +793,7 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
status = udriver->suspend(udev, msg);
done:
- dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
- if (status == 0)
- udev->dev.power.power_state.event = msg.event;
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
@@ -823,11 +821,9 @@ static int usb_resume_device(struct usb_device *udev)
status = udriver->resume(udev);
done:
- dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
- if (status == 0) {
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ if (status == 0)
udev->autoresume_disabled = 0;
- udev->dev.power.power_state.event = PM_EVENT_ON;
- }
return status;
}
@@ -864,7 +860,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
}
done:
- dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
return status;
}
@@ -914,7 +910,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
}
done:
- dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
if (status == 0)
mark_active(intf);
@@ -936,7 +932,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
* is disabled. Also fail if any interfaces require remote wakeup
* but it isn't available.
*/
- udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->pm_usage_cnt > 0)
return -EBUSY;
if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
@@ -1098,7 +1093,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
done:
- dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
@@ -1180,8 +1175,7 @@ static int usb_resume_both(struct usb_device *udev)
}
} else {
- /* Needed for setting udev->dev.power.power_state.event,
- * for possible debugging message, and for reset_resume. */
+ /* Needed for reset-resume */
status = usb_resume_device(udev);
}
@@ -1193,8 +1187,9 @@ static int usb_resume_both(struct usb_device *udev)
}
done:
- dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
- udev->reset_resume = 0;
+ dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ if (!status)
+ udev->reset_resume = 0;
return status;
}
@@ -1262,7 +1257,7 @@ void usb_autosuspend_device(struct usb_device *udev)
status = usb_autopm_do_device(udev, -1);
dev_vdbg(&udev->dev, "%s: cnt %d\n",
- __FUNCTION__, udev->pm_usage_cnt);
+ __func__, udev->pm_usage_cnt);
}
/**
@@ -1282,7 +1277,7 @@ void usb_try_autosuspend_device(struct usb_device *udev)
{
usb_autopm_do_device(udev, 0);
dev_vdbg(&udev->dev, "%s: cnt %d\n",
- __FUNCTION__, udev->pm_usage_cnt);
+ __func__, udev->pm_usage_cnt);
}
/**
@@ -1310,7 +1305,7 @@ int usb_autoresume_device(struct usb_device *udev)
status = usb_autopm_do_device(udev, 1);
dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
- __FUNCTION__, status, udev->pm_usage_cnt);
+ __func__, status, udev->pm_usage_cnt);
return status;
}
@@ -1382,7 +1377,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, -1);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __FUNCTION__, status, intf->pm_usage_cnt);
+ __func__, status, intf->pm_usage_cnt);
}
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
@@ -1426,7 +1421,7 @@ int usb_autopm_get_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, 1);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __FUNCTION__, status, intf->pm_usage_cnt);
+ __func__, status, intf->pm_usage_cnt);
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1448,7 +1443,7 @@ int usb_autopm_set_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, 0);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
- __FUNCTION__, status, intf->pm_usage_cnt);
+ __func__, status, intf->pm_usage_cnt);
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
@@ -1523,9 +1518,14 @@ static int usb_suspend(struct device *dev, pm_message_t message)
udev = to_usb_device(dev);
/* If udev is already suspended, we can skip this suspend and
- * we should also skip the upcoming system resume. */
+ * we should also skip the upcoming system resume. High-speed
+ * root hubs are an exception; they need to resume whenever the
+ * system wakes up in order for USB-PERSIST port handover to work
+ * properly.
+ */
if (udev->state == USB_STATE_SUSPENDED) {
- udev->skip_sys_resume = 1;
+ if (udev->parent || udev->speed != USB_SPEED_HIGH)
+ udev->skip_sys_resume = 1;
return 0;
}
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 84760ddbc332..5b87ae7f0a6a 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -73,7 +73,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (pci_enable_device(dev) < 0)
return -ENODEV;
dev->current_state = PCI_D0;
- dev->dev.power.power_state = PMSG_ON;
if (!dev->irq) {
dev_err(&dev->dev,
@@ -216,9 +215,9 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
hcd->state == HC_STATE_HALT))
return -EBUSY;
- if (hcd->driver->suspend) {
- retval = hcd->driver->suspend(hcd, message);
- suspend_report_result(hcd->driver->suspend, retval);
+ if (hcd->driver->pci_suspend) {
+ retval = hcd->driver->pci_suspend(hcd, message);
+ suspend_report_result(hcd->driver->pci_suspend, retval);
if (retval)
goto done;
}
@@ -302,8 +301,6 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
done:
if (retval == 0) {
- dev->dev.power.power_state = PMSG_SUSPEND;
-
#ifdef CONFIG_PPC_PMAC
/* Disable ASIC clocks for USB */
if (machine_is(powermac)) {
@@ -406,12 +403,10 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
pci_set_master(dev);
pci_restore_state(dev);
- dev->dev.power.power_state = PMSG_ON;
-
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
- if (hcd->driver->resume) {
- retval = hcd->driver->resume(hcd);
+ if (hcd->driver->pci_resume) {
+ retval = hcd->driver->pci_resume(hcd);
if (retval) {
dev_err(hcd->self.controller,
"PCI post-resume error %d!\n", retval);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e52ed1663b3c..bf10e9c4195e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -129,7 +129,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
- 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/
+ 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
@@ -291,7 +291,6 @@ static int ascii2utf (char *s, u8 *utf, int utfmax)
* rh_string - provides manufacturer, product and serial strings for root hub
* @id: the string ID number (1: serial number, 2: product, 3: vendor)
* @hcd: the host controller for this root hub
- * @type: string describing our driver
* @data: return packet in UTF-16 LE
* @len: length of the return packet
*
@@ -355,9 +354,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
__attribute__((aligned(4)));
const u8 *bufp = tbuf;
int len = 0;
- int patch_wakeup = 0;
int status;
int n;
+ u8 patch_wakeup = 0;
+ u8 patch_protocol = 0;
might_sleep();
@@ -434,6 +434,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
else
goto error;
len = 18;
+ if (hcd->has_tt)
+ patch_protocol = 1;
break;
case USB_DT_CONFIG << 8:
if (hcd->driver->flags & HCD_USB2) {
@@ -528,6 +530,13 @@ error:
bmAttributes))
((struct usb_config_descriptor *)ubuf)->bmAttributes
|= USB_CONFIG_ATT_WAKEUP;
+
+ /* report whether RH hardware has an integrated TT */
+ if (patch_protocol &&
+ len > offsetof(struct usb_device_descriptor,
+ bDeviceProtocol))
+ ((struct usb_device_descriptor *) ubuf)->
+ bDeviceProtocol = 1;
}
/* any errors get returned through the urb completion */
@@ -915,15 +924,6 @@ static int register_root_hub(struct usb_hcd *hcd)
return retval;
}
-void usb_enable_root_hub_irq (struct usb_bus *bus)
-{
- struct usb_hcd *hcd;
-
- hcd = container_of (bus, struct usb_hcd, self);
- if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
- hcd->driver->hub_irq_enable (hcd);
-}
-
/*-------------------------------------------------------------------------*/
@@ -1677,7 +1677,6 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
* @irq: the IRQ being raised
* @__hcd: pointer to the HCD whose IRQ is being signaled
- * @r: saved hardware registers
*
* If the controller isn't HALTed, calls the driver's irq handler.
* Checks whether the controller is now dead.
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 2d1c3d5e47b8..1e4b81e9eb50 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -28,7 +28,7 @@
/*
* USB Packet IDs (PIDs)
*/
-#define USB_PID_UNDEF_0 0xf0
+#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
@@ -99,6 +99,7 @@ struct usb_hcd {
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
unsigned authorized_default:1;
+ unsigned has_tt:1; /* Integrated TT in root hub */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -177,10 +178,10 @@ struct hc_driver {
* a whole, not just the root hub; they're for PCI bus glue.
*/
/* called after suspending the hub, before entering D3 etc */
- int (*suspend) (struct usb_hcd *hcd, pm_message_t message);
+ int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message);
/* called after entering D0 (etc), before resuming the hub */
- int (*resume) (struct usb_hcd *hcd);
+ int (*pci_resume) (struct usb_hcd *hcd);
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
@@ -209,8 +210,6 @@ struct hc_driver {
int (*bus_suspend)(struct usb_hcd *);
int (*bus_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
- void (*hub_irq_enable)(struct usb_hcd *);
- /* Needed only if port-change IRQs are level-triggered */
/* force handover of high-speed port to full-speed companion */
void (*relinquish_port)(struct usb_hcd *, int);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 57aeca160f38..eb57fcc701d7 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -30,12 +30,6 @@
#include "hcd.h"
#include "hub.h"
-#ifdef CONFIG_USB_PERSIST
-#define USB_PERSIST 1
-#else
-#define USB_PERSIST 0
-#endif
-
/* if we are in debug mode, always announce new devices */
#ifdef DEBUG
#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
@@ -333,6 +327,27 @@ static int get_port_status(struct usb_device *hdev, int port1,
return status;
}
+static int hub_port_status(struct usb_hub *hub, int port1,
+ u16 *status, u16 *change)
+{
+ int ret;
+
+ mutex_lock(&hub->status_mutex);
+ ret = get_port_status(hub->hdev, port1, &hub->status->port);
+ if (ret < 4) {
+ dev_err(hub->intfdev,
+ "%s failed (err = %d)\n", __func__, ret);
+ if (ret >= 0)
+ ret = -EIO;
+ } else {
+ *status = le16_to_cpu(hub->status->port.wPortStatus);
+ *change = le16_to_cpu(hub->status->port.wPortChange);
+ ret = 0;
+ }
+ mutex_unlock(&hub->status_mutex);
+ return ret;
+}
+
static void kick_khubd(struct usb_hub *hub)
{
unsigned long flags;
@@ -560,7 +575,7 @@ static int hub_hub_status(struct usb_hub *hub,
ret = get_hub_status(hub->hdev, &hub->status->hub);
if (ret < 0)
dev_err (hub->intfdev,
- "%s failed (err = %d)\n", __FUNCTION__, ret);
+ "%s failed (err = %d)\n", __func__, ret);
else {
*status = le16_to_cpu(hub->status->hub.wHubStatus);
*change = le16_to_cpu(hub->status->hub.wHubChange);
@@ -610,9 +625,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
}
/* caller has locked the hub device */
-static int hub_pre_reset(struct usb_interface *intf)
+static void hub_stop(struct usb_hub *hub)
{
- struct usb_hub *hub = usb_get_intfdata(intf);
struct usb_device *hdev = hub->hdev;
int i;
@@ -622,6 +636,89 @@ static int hub_pre_reset(struct usb_interface *intf)
usb_disconnect(&hdev->children[i]);
}
hub_quiesce(hub);
+}
+
+#define HUB_RESET 1
+#define HUB_RESUME 2
+#define HUB_RESET_RESUME 3
+
+#ifdef CONFIG_PM
+
+static void hub_restart(struct usb_hub *hub, int type)
+{
+ struct usb_device *hdev = hub->hdev;
+ int port1;
+
+ /* Check each of the children to see if they require
+ * USB-PERSIST handling or disconnection. Also check
+ * each unoccupied port to make sure it is still disabled.
+ */
+ for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+ struct usb_device *udev = hdev->children[port1-1];
+ int status = 0;
+ u16 portstatus, portchange;
+
+ if (!udev || udev->state == USB_STATE_NOTATTACHED) {
+ if (type != HUB_RESET) {
+ status = hub_port_status(hub, port1,
+ &portstatus, &portchange);
+ if (status == 0 && (portstatus &
+ USB_PORT_STAT_ENABLE))
+ clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_ENABLE);
+ }
+ continue;
+ }
+
+ /* Was the power session lost while we were suspended? */
+ switch (type) {
+ case HUB_RESET_RESUME:
+ portstatus = 0;
+ portchange = USB_PORT_STAT_C_CONNECTION;
+ break;
+
+ case HUB_RESET:
+ case HUB_RESUME:
+ status = hub_port_status(hub, port1,
+ &portstatus, &portchange);
+ break;
+ }
+
+ /* For "USB_PERSIST"-enabled children we must
+ * mark the child device for reset-resume and
+ * turn off the various status changes to prevent
+ * khubd from disconnecting it later.
+ */
+ if (udev->persist_enabled && status == 0 &&
+ !(portstatus & USB_PORT_STAT_ENABLE)) {
+ if (portchange & USB_PORT_STAT_C_ENABLE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_ENABLE);
+ if (portchange & USB_PORT_STAT_C_CONNECTION)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ udev->reset_resume = 1;
+ }
+
+ /* Otherwise for a reset_resume we must disconnect the child,
+ * but as we may not lock the child device here
+ * we have to do a "logical" disconnect.
+ */
+ else if (type == HUB_RESET_RESUME)
+ hub_port_logical_disconnect(hub, port1);
+ }
+
+ hub_activate(hub);
+}
+
+#endif /* CONFIG_PM */
+
+/* caller has locked the hub device */
+static int hub_pre_reset(struct usb_interface *intf)
+{
+ struct usb_hub *hub = usb_get_intfdata(intf);
+
+ hub_stop(hub);
return 0;
}
@@ -910,7 +1007,7 @@ static void hub_disconnect(struct usb_interface *intf)
/* Disconnect all children and quiesce the hub */
hub->error = 0;
- hub_pre_reset(intf);
+ hub_stop(hub);
usb_set_intfdata (intf, NULL);
@@ -1098,21 +1195,42 @@ void usb_set_device_state(struct usb_device *udev,
spin_unlock_irqrestore(&device_state_lock, flags);
}
+/*
+ * WUSB devices are simple: they have no hubs behind, so the mapping
+ * device <-> virtual port number becomes 1:1. Why? to simplify the
+ * life of the device connection logic in
+ * drivers/usb/wusbcore/devconnect.c. When we do the initial secret
+ * handshake we need to assign a temporary address in the unauthorized
+ * space. For simplicity we use the first virtual port number found to
+ * be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()]
+ * and that becomes it's address [X < 128] or its unauthorized address
+ * [X | 0x80].
+ *
+ * We add 1 as an offset to the one-based USB-stack port number
+ * (zero-based wusb virtual port index) for two reasons: (a) dev addr
+ * 0 is reserved by USB for default address; (b) Linux's USB stack
+ * uses always #1 for the root hub of the controller. So USB stack's
+ * port #1, which is wusb virtual-port #0 has address #2.
+ */
static void choose_address(struct usb_device *udev)
{
int devnum;
struct usb_bus *bus = udev->bus;
/* If khubd ever becomes multithreaded, this will need a lock */
-
- /* Try to allocate the next devnum beginning at bus->devnum_next. */
- devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
- bus->devnum_next);
- if (devnum >= 128)
- devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
-
- bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
-
+ if (udev->wusb) {
+ devnum = udev->portnum + 1;
+ BUG_ON(test_bit(devnum, bus->devmap.devicemap));
+ } else {
+ /* Try to allocate the next devnum beginning at
+ * bus->devnum_next. */
+ devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
+ bus->devnum_next);
+ if (devnum >= 128)
+ devnum = find_next_zero_bit(bus->devmap.devicemap,
+ 128, 1);
+ bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
+ }
if (devnum < 128) {
set_bit(devnum, bus->devmap.devicemap);
udev->devnum = devnum;
@@ -1127,6 +1245,13 @@ static void release_address(struct usb_device *udev)
}
}
+static void update_address(struct usb_device *udev, int devnum)
+{
+ /* The address for a WUSB device is managed by wusbcore. */
+ if (!udev->wusb)
+ udev->devnum = devnum;
+}
+
#ifdef CONFIG_USB_SUSPEND
static void usb_stop_pm(struct usb_device *udev)
@@ -1173,7 +1298,7 @@ void usb_disconnect(struct usb_device **pdev)
int i;
if (!udev) {
- pr_debug ("%s nodev\n", __FUNCTION__);
+ pr_debug ("%s nodev\n", __func__);
return;
}
@@ -1510,28 +1635,6 @@ out_authorized:
}
-static int hub_port_status(struct usb_hub *hub, int port1,
- u16 *status, u16 *change)
-{
- int ret;
-
- mutex_lock(&hub->status_mutex);
- ret = get_port_status(hub->hdev, port1, &hub->status->port);
- if (ret < 4) {
- dev_err (hub->intfdev,
- "%s failed (err = %d)\n", __FUNCTION__, ret);
- if (ret >= 0)
- ret = -EIO;
- } else {
- *status = le16_to_cpu(hub->status->port.wPortStatus);
- *change = le16_to_cpu(hub->status->port.wPortChange);
- ret = 0;
- }
- mutex_unlock(&hub->status_mutex);
- return ret;
-}
-
-
/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
static unsigned hub_is_wusb(struct usb_hub *hub)
{
@@ -1637,7 +1740,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
- udev->devnum = 0; /* Device now at address 0 */
+ update_address(udev, 0);
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@@ -1842,9 +1945,8 @@ static int finish_port_resume(struct usb_device *udev)
* the host and the device is the same as it was when the device
* suspended.
*
- * If CONFIG_USB_PERSIST and @udev->reset_resume are both set then this
- * routine won't check that the port is still enabled. Furthermore,
- * if @udev->reset_resume is set then finish_port_resume() above will
+ * If @udev->reset_resume is set then this routine won't check that the
+ * port is still enabled. Furthermore, finish_port_resume() above will
* reset @udev. The end result is that a broken power session can be
* recovered and @udev will appear to persist across a loss of VBUS power.
*
@@ -1856,8 +1958,8 @@ static int finish_port_resume(struct usb_device *udev)
* to it will be lost. Using the USB_PERSIST facility, the device can be
* made to appear as if it had not disconnected.
*
- * This facility is inherently dangerous. Although usb_reset_device()
- * makes every effort to insure that the same device is present after the
+ * This facility can be dangerous. Although usb_reset_device() makes
+ * every effort to insure that the same device is present after the
* reset as before, it cannot provide a 100% guarantee. Furthermore it's
* quite possible for a device to remain unaltered but its media to be
* changed. If the user replaces a flash memory card while the system is
@@ -1902,7 +2004,7 @@ int usb_port_resume(struct usb_device *udev)
status = hub_port_status(hub, port1, &portstatus, &portchange);
SuspendCleared:
- if (USB_PERSIST && udev->reset_resume)
+ if (udev->reset_resume)
want_flags = USB_PORT_STAT_POWER
| USB_PORT_STAT_CONNECTION;
else
@@ -1927,8 +2029,6 @@ int usb_port_resume(struct usb_device *udev)
}
clear_bit(port1, hub->busy_bits);
- if (!hub->hdev->parent && !hub->busy_bits[0])
- usb_enable_root_hub_irq(hub->hdev->bus);
if (status == 0)
status = finish_port_resume(udev);
@@ -2000,7 +2100,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
}
}
- dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&intf->dev, "%s\n", __func__);
/* stop khubd and related activity */
hub_quiesce(hub);
@@ -2009,49 +2109,20 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
static int hub_resume(struct usb_interface *intf)
{
- struct usb_hub *hub = usb_get_intfdata (intf);
-
- dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
+ struct usb_hub *hub = usb_get_intfdata(intf);
- /* tell khubd to look for changes on this hub */
- hub_activate(hub);
+ dev_dbg(&intf->dev, "%s\n", __func__);
+ hub_restart(hub, HUB_RESUME);
return 0;
}
static int hub_reset_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
- struct usb_device *hdev = hub->hdev;
- int port1;
+ dev_dbg(&intf->dev, "%s\n", __func__);
hub_power_on(hub);
-
- for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
- struct usb_device *child = hdev->children[port1-1];
-
- if (child) {
-
- /* For "USB_PERSIST"-enabled children we must
- * mark the child device for reset-resume and
- * turn off the connect-change status to prevent
- * khubd from disconnecting it later.
- */
- if (USB_PERSIST && child->persist_enabled) {
- child->reset_resume = 1;
- clear_port_feature(hdev, port1,
- USB_PORT_FEAT_C_CONNECTION);
-
- /* Otherwise we must disconnect the child,
- * but as we may not lock the child device here
- * we have to do a "logical" disconnect.
- */
- } else {
- hub_port_logical_disconnect(hub, port1);
- }
- }
- }
-
- hub_activate(hub);
+ hub_restart(hub, HUB_RESET_RESUME);
return 0;
}
@@ -2061,10 +2132,10 @@ static int hub_reset_resume(struct usb_interface *intf)
*
* The USB host controller driver calls this function when its root hub
* is resumed and Vbus power has been interrupted or the controller
- * has been reset. The routine marks @rhdev as having lost power. When
- * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
- * is enabled then it will carry out power-session recovery, otherwise
- * it will disconnect all the child devices.
+ * has been reset. The routine marks @rhdev as having lost power.
+ * When the hub driver is resumed it will take notice and carry out
+ * power-session recovery for all the "USB-PERSIST"-enabled child devices;
+ * the others will be disconnected.
*/
void usb_root_hub_lost_power(struct usb_device *rhdev)
{
@@ -2147,12 +2218,13 @@ static int hub_port_debounce(struct usb_hub *hub, int port1)
return portstatus;
}
-static void ep0_reinit(struct usb_device *udev)
+void usb_ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
usb_enable_endpoint(udev, &udev->ep0);
}
+EXPORT_SYMBOL_GPL(usb_ep0_reinit);
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
@@ -2171,9 +2243,10 @@ static int hub_set_address(struct usb_device *udev, int devnum)
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
- udev->devnum = devnum; /* Device now using proper address */
+ /* Device now using proper address. */
+ update_address(udev, devnum);
usb_set_device_state(udev, USB_STATE_ADDRESS);
- ep0_reinit(udev);
+ usb_ep0_reinit(udev);
}
return retval;
}
@@ -2355,26 +2428,33 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
#undef GET_DESCRIPTOR_BUFSIZE
}
- for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev, devnum);
- if (retval >= 0)
+ /*
+ * If device is WUSB, we already assigned an
+ * unauthorized address in the Connect Ack sequence;
+ * authorization will assign the final address.
+ */
+ if (udev->wusb == 0) {
+ for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
+ retval = hub_set_address(udev, devnum);
+ if (retval >= 0)
+ break;
+ msleep(200);
+ }
+ if (retval < 0) {
+ dev_err(&udev->dev,
+ "device not accepting address %d, error %d\n",
+ devnum, retval);
+ goto fail;
+ }
+
+ /* cope with hardware quirkiness:
+ * - let SET_ADDRESS settle, some device hardware wants it
+ * - read ep0 maxpacket even for high and low speed,
+ */
+ msleep(10);
+ if (USE_NEW_SCHEME(retry_counter))
break;
- msleep(200);
- }
- if (retval < 0) {
- dev_err(&udev->dev,
- "device not accepting address %d, error %d\n",
- devnum, retval);
- goto fail;
- }
-
- /* cope with hardware quirkiness:
- * - let SET_ADDRESS settle, some device hardware wants it
- * - read ep0 maxpacket even for high and low speed,
- */
- msleep(10);
- if (USE_NEW_SCHEME(retry_counter))
- break;
+ }
retval = usb_get_device_descriptor(udev, 8);
if (retval < 8) {
@@ -2391,7 +2471,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval)
goto fail;
- i = udev->descriptor.bMaxPacketSize0 == 0xff?
+ i = udev->descriptor.bMaxPacketSize0 == 0xff? /* wusb device? */
512 : udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL ||
@@ -2402,7 +2482,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
- ep0_reinit(udev);
+ usb_ep0_reinit(udev);
}
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
@@ -2419,7 +2499,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
fail:
if (retval) {
hub_port_disable(hub, port1, 0);
- udev->devnum = devnum; /* for disconnect processing */
+ update_address(udev, devnum); /* for disconnect processing */
}
mutex_unlock(&usb_address0_mutex);
return retval;
@@ -2568,6 +2648,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
+ udev->wusb = hub_is_wusb(hub);
/* set the address */
choose_address(udev);
@@ -2657,12 +2738,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
loop_disable:
hub_port_disable(hub, port1, 1);
loop:
- ep0_reinit(udev);
+ usb_ep0_reinit(udev);
release_address(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
+ dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1);
done:
hub_port_disable(hub, port1, 1);
@@ -2726,7 +2808,7 @@ static void hub_events(void)
/* If the hub has died, clean up after it */
if (hdev->state == USB_STATE_NOTATTACHED) {
hub->error = -ENODEV;
- hub_pre_reset(intf);
+ hub_stop(hub);
goto loop;
}
@@ -2872,11 +2954,6 @@ static void hub_events(void)
hub->activating = 0;
- /* If this is a root hub, tell the HCD it's okay to
- * re-enable port-change interrupts now. */
- if (!hdev->parent && !hub->busy_bits[0])
- usb_enable_root_hub_irq(hdev->bus);
-
loop_autopm:
/* Allow autosuspend if we're not going to run again */
if (list_empty(&hub->event_list))
@@ -2890,7 +2967,13 @@ loop:
static int hub_thread(void *__unused)
{
+ /* khubd needs to be freezable to avoid intefering with USB-PERSIST
+ * port handover. Otherwise it might see that a full-speed device
+ * was gone before the EHCI controller had handed its port over to
+ * the companion full-speed controller.
+ */
set_freezable();
+
do {
hub_events();
wait_event_freezable(khubd_wait,
@@ -2959,16 +3042,36 @@ void usb_hub_cleanup(void)
usb_deregister(&hub_driver);
} /* usb_hub_cleanup() */
-static int config_descriptors_changed(struct usb_device *udev)
+static int descriptors_changed(struct usb_device *udev,
+ struct usb_device_descriptor *old_device_descriptor)
{
- unsigned index;
- unsigned len = 0;
- struct usb_config_descriptor *buf;
+ int changed = 0;
+ unsigned index;
+ unsigned serial_len = 0;
+ unsigned len;
+ unsigned old_length;
+ int length;
+ char *buf;
+
+ if (memcmp(&udev->descriptor, old_device_descriptor,
+ sizeof(*old_device_descriptor)) != 0)
+ return 1;
+ /* Since the idVendor, idProduct, and bcdDevice values in the
+ * device descriptor haven't changed, we will assume the
+ * Manufacturer and Product strings haven't changed either.
+ * But the SerialNumber string could be different (e.g., a
+ * different flash card of the same brand).
+ */
+ if (udev->serial)
+ serial_len = strlen(udev->serial) + 1;
+
+ len = serial_len;
for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
- if (len < le16_to_cpu(udev->config[index].desc.wTotalLength))
- len = le16_to_cpu(udev->config[index].desc.wTotalLength);
+ old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
+ len = max(len, old_length);
}
+
buf = kmalloc(len, GFP_NOIO);
if (buf == NULL) {
dev_err(&udev->dev, "no mem to re-read configs after reset\n");
@@ -2976,25 +3079,41 @@ static int config_descriptors_changed(struct usb_device *udev)
return 1;
}
for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
- int length;
- int old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
-
+ old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
old_length);
- if (length < old_length) {
+ if (length != old_length) {
dev_dbg(&udev->dev, "config index %d, error %d\n",
index, length);
+ changed = 1;
break;
}
if (memcmp (buf, udev->rawdescriptors[index], old_length)
!= 0) {
dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
- index, buf->bConfigurationValue);
+ index,
+ ((struct usb_config_descriptor *) buf)->
+ bConfigurationValue);
+ changed = 1;
break;
}
}
+
+ if (!changed && serial_len) {
+ length = usb_string(udev, udev->descriptor.iSerialNumber,
+ buf, serial_len);
+ if (length + 1 != serial_len) {
+ dev_dbg(&udev->dev, "serial string error %d\n",
+ length);
+ changed = 1;
+ } else if (memcmp(buf, udev->serial, length) != 0) {
+ dev_dbg(&udev->dev, "serial string changed\n");
+ changed = 1;
+ }
+ }
+
kfree(buf);
- return index != udev->descriptor.bNumConfigurations;
+ return changed;
}
/**
@@ -3044,7 +3163,7 @@ int usb_reset_device(struct usb_device *udev)
if (!parent_hdev) {
/* this requires hcd-specific logic; see OHCI hc_restart() */
- dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__);
+ dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
return -EISDIR;
}
parent_hub = hdev_to_hub(parent_hdev);
@@ -3054,21 +3173,18 @@ int usb_reset_device(struct usb_device *udev)
/* ep0 maxpacket size may change; let the HCD know about it.
* Other endpoints will be handled by re-enumeration. */
- ep0_reinit(udev);
+ usb_ep0_reinit(udev);
ret = hub_port_init(parent_hub, udev, port1, i);
if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
break;
}
clear_bit(port1, parent_hub->busy_bits);
- if (!parent_hdev->parent && !parent_hub->busy_bits[0])
- usb_enable_root_hub_irq(parent_hdev->bus);
if (ret < 0)
goto re_enumerate;
/* Device might have changed firmware (DFU or similar) */
- if (memcmp(&udev->descriptor, &descriptor, sizeof descriptor)
- || config_descriptors_changed (udev)) {
+ if (descriptors_changed(udev, &descriptor)) {
dev_info(&udev->dev, "device firmware changed\n");
udev->descriptor = descriptor; /* for disconnect() calls */
goto re_enumerate;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 1551aed65e05..2a116ce53c9b 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -41,9 +41,10 @@
*/
#define USB_PORT_FEAT_CONNECTION 0
#define USB_PORT_FEAT_ENABLE 1
-#define USB_PORT_FEAT_SUSPEND 2
+#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */
#define USB_PORT_FEAT_OVER_CURRENT 3
#define USB_PORT_FEAT_RESET 4
+#define USB_PORT_FEAT_L1 5 /* L1 suspend */
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9
#define USB_PORT_FEAT_HIGHSPEED 10
@@ -54,6 +55,7 @@
#define USB_PORT_FEAT_C_RESET 20
#define USB_PORT_FEAT_TEST 21
#define USB_PORT_FEAT_INDICATOR 22
+#define USB_PORT_FEAT_C_PORT_L1 23
/*
* Hub Status and Hub Change results
@@ -73,7 +75,8 @@ struct usb_port_status {
#define USB_PORT_STAT_SUSPEND 0x0004
#define USB_PORT_STAT_OVERCURRENT 0x0008
#define USB_PORT_STAT_RESET 0x0010
-/* bits 5 to 7 are reserved */
+#define USB_PORT_STAT_L1 0x0020
+/* bits 6 to 7 are reserved */
#define USB_PORT_STAT_POWER 0x0100
#define USB_PORT_STAT_LOW_SPEED 0x0200
#define USB_PORT_STAT_HIGH_SPEED 0x0400
@@ -91,6 +94,7 @@ struct usb_port_status {
#define USB_PORT_STAT_C_SUSPEND 0x0004
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
#define USB_PORT_STAT_C_RESET 0x0010
+#define USB_PORT_STAT_C_L1 0x0020
/*
* wHubCharacteristics (masks)
@@ -191,5 +195,6 @@ struct usb_tt_clear {
};
extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
+extern void usb_ep0_reinit(struct usb_device *);
#endif /* __LINUX_HUB_H */
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 83a373e9cc36..8607846e3c3f 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -463,13 +463,13 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
if (!inode) {
- dbg("%s: could not get inode!",__FUNCTION__);
+ dbg("%s: could not get inode!",__func__);
return -ENOMEM;
}
root = d_alloc_root(inode);
if (!root) {
- dbg("%s: could not get root dentry!",__FUNCTION__);
+ dbg("%s: could not get root dentry!",__func__);
iput(inode);
return -ENOMEM;
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index c311f67b7f08..e819e5359d57 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -312,7 +312,7 @@ static void sg_complete(struct urb *urb)
retval != -EBUSY)
dev_err(&io->dev->dev,
"%s, unlink --> %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
} else if (urb == io->urbs [i])
found = 1;
}
@@ -550,7 +550,7 @@ void usb_sg_wait(struct usb_sg_request *io)
io->urbs[i]->dev = NULL;
io->urbs[i]->status = retval;
dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
usb_sg_cancel(io);
}
spin_lock_irq(&io->lock);
@@ -600,7 +600,7 @@ void usb_sg_cancel(struct usb_sg_request *io)
retval = usb_unlink_urb(io->urbs [i]);
if (retval != -EINPROGRESS && retval != -EBUSY)
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
spin_lock(&io->lock);
}
@@ -784,7 +784,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
if (size <= 0 || !buf || !index)
return -EINVAL;
buf[0] = 0;
- tbuf = kmalloc(256, GFP_KERNEL);
+ tbuf = kmalloc(256, GFP_NOIO);
if (!tbuf)
return -ENOMEM;
@@ -1068,7 +1068,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
{
int i;
- dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__,
+ dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
skip_ep0 ? "non-ep0" : "all");
for (i = skip_ep0; i < 16; ++i) {
usb_disable_endpoint(dev, i);
@@ -1089,8 +1089,8 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
continue;
dev_dbg(&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
- usb_remove_sysfs_intf_files(interface);
device_del(&interface->dev);
+ usb_remove_sysfs_intf_files(interface);
}
/* Now that the interfaces are unbound, nobody should
@@ -1231,7 +1231,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
- if (iface->cur_altsetting != alt && device_is_registered(&iface->dev))
+ if (iface->cur_altsetting != alt)
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface);
@@ -1330,8 +1330,7 @@ int usb_reset_configuration(struct usb_device *dev)
struct usb_interface *intf = config->interface[i];
struct usb_host_interface *alt;
- if (device_is_registered(&intf->dev))
- usb_remove_sysfs_intf_files(intf);
+ usb_remove_sysfs_intf_files(intf);
alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting.
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index dfc5418ea10c..2e2019390290 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -97,4 +97,18 @@ void usb_detect_quirks(struct usb_device *udev)
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
udev->autosuspend_disabled = 1;
#endif
+
+ /* For the present, all devices default to USB-PERSIST enabled */
+#if 0 /* was: #ifdef CONFIG_PM */
+ /* Hubs are automatically enabled for USB-PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ udev->persist_enabled = 1;
+
+#else
+ /* In the absence of PM, we can safely enable USB-PERSIST
+ * for all devices. It will affect things like hub resets
+ * and EMF-related port disables.
+ */
+ udev->persist_enabled = 1;
+#endif /* CONFIG_PM */
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index a37ccbd1e007..5b20a60de8ba 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -180,11 +180,9 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
-#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
-static const char power_group[] = "power";
-#endif
+#ifdef CONFIG_PM
-#ifdef CONFIG_USB_PERSIST
+static const char power_group[] = "power";
static ssize_t
show_persist(struct device *dev, struct device_attribute *attr, char *buf)
@@ -222,12 +220,13 @@ static int add_persist_attributes(struct device *dev)
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
- /* Hubs are automatically enabled for USB_PERSIST */
- if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
- udev->persist_enabled = 1;
- rc = sysfs_add_file_to_group(&dev->kobj,
- &dev_attr_persist.attr,
- power_group);
+ /* Hubs are automatically enabled for USB_PERSIST,
+ * no point in creating the attribute file.
+ */
+ if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
+ rc = sysfs_add_file_to_group(&dev->kobj,
+ &dev_attr_persist.attr,
+ power_group);
}
return rc;
}
@@ -238,13 +237,12 @@ static void remove_persist_attributes(struct device *dev)
&dev_attr_persist.attr,
power_group);
}
-
#else
#define add_persist_attributes(dev) 0
#define remove_persist_attributes(dev) do {} while (0)
-#endif /* CONFIG_USB_PERSIST */
+#endif /* CONFIG_PM */
#ifdef CONFIG_USB_SUSPEND
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9d7e63292c01..c0b1ae25ae2a 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -334,7 +334,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
- __FUNCTION__, max);
+ __func__, max);
return -EMSGSIZE;
}
@@ -590,6 +590,30 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor)
EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
/**
+ * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be unlinked starting
+ * from the back of the queue. This function is asynchronous.
+ * The unlinking is just tiggered. It may happen after this
+ * function has returned.
+ */
+void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+
+ spin_lock_irq(&anchor->lock);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
+ /* this will unanchor the URB */
+ usb_unlink_urb(victim);
+ }
+ spin_unlock_irq(&anchor->lock);
+}
+EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
+
+/**
* usb_wait_anchor_empty_timeout - wait for an anchor to be unused
* @anchor: the anchor you want to become unused
* @timeout: how long you are willing to wait in milliseconds
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 2375194a9d43..1bf8ccb9c58d 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -114,13 +114,11 @@ static inline int is_usb_device_driver(struct device_driver *drv)
static inline void mark_active(struct usb_interface *f)
{
f->is_active = 1;
- f->dev.power.power_state.event = PM_EVENT_ON;
}
static inline void mark_quiesced(struct usb_interface *f)
{
f->is_active = 0;
- f->dev.power.power_state.event = PM_EVENT_SUSPEND;
}
static inline int is_active(const struct usb_interface *f)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index d681bb27fa58..f7b54651dd42 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -44,8 +44,8 @@ menuconfig USB_GADGET
if USB_GADGET
config USB_GADGET_DEBUG
- boolean "Debugging messages"
- depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
+ boolean "Debugging messages (DEVELOPMENT)"
+ depends on USB_GADGET && DEBUG_KERNEL
help
Many controller and gadget drivers will print some debugging
messages if you use this option to ask for those messages.
@@ -58,7 +58,7 @@ config USB_GADGET_DEBUG
production build.
config USB_GADGET_DEBUG_FILES
- boolean "Debugging information files"
+ boolean "Debugging information files (DEVELOPMENT)"
depends on USB_GADGET && PROC_FS
help
Some of the drivers in the "gadget" framework can expose
@@ -69,7 +69,7 @@ config USB_GADGET_DEBUG_FILES
here. If in doubt, or to conserve kernel memory, say "N".
config USB_GADGET_DEBUG_FS
- boolean "Debugging information files in debugfs"
+ boolean "Debugging information files in debugfs (DEVELOPMENT)"
depends on USB_GADGET && DEBUG_FS
help
Some of the drivers in the "gadget" framework can expose
@@ -337,7 +337,7 @@ config USB_AT91
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
- depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
+ depends on USB=y || (USB=m && USB_GADGET=m)
select USB_GADGET_DUALSPEED
help
This host controller driver emulates USB, looping all data transfer
@@ -404,7 +404,6 @@ choice
config USB_ZERO
tristate "Gadget Zero (DEVELOPMENT)"
- depends on EXPERIMENTAL
help
Gadget Zero is a two-configuration device. It either sinks and
sources bulk data; or it loops back a configurable number of
@@ -468,8 +467,8 @@ config USB_ETH
dynamically linked module called "g_ether".
config USB_ETH_RNDIS
- bool "RNDIS support (EXPERIMENTAL)"
- depends on USB_ETH && EXPERIMENTAL
+ bool "RNDIS support"
+ depends on USB_ETH
default y
help
Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
@@ -495,6 +494,9 @@ config USB_GADGETFS
All endpoints, transfer speeds, and transfer types supported by
the hardware are available, through read() and write() calls.
+ Currently, this option is still labelled as EXPERIMENTAL because
+ of existing race conditions in the underlying in-kernel AIO core.
+
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "gadgetfs".
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index b663f23f2642..ce337cb5d137 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -328,6 +328,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
u32 tmp;
unsigned long iflags;
u8 udc_csr_epix;
+ unsigned maxpacket;
if (!usbep
|| usbep->name == ep0_string
@@ -354,9 +355,10 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
writel(tmp, &dev->ep[ep->num].regs->ctl);
/* set max packet size */
+ maxpacket = le16_to_cpu(desc->wMaxPacketSize);
tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
- tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
- ep->ep.maxpacket = desc->wMaxPacketSize;
+ tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
+ ep->ep.maxpacket = maxpacket;
writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
/* IN ep */
@@ -370,8 +372,8 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
/* double buffering: fifo size = 2 x max packet size */
tmp = AMD_ADDBITS(
tmp,
- desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
- / UDC_DWORD_BYTES,
+ maxpacket * UDC_EPIN_BUFF_SIZE_MULT
+ / UDC_DWORD_BYTES,
UDC_EPIN_BUFF_SIZE);
writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
@@ -390,7 +392,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
/* set max packet size UDC CSR */
tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
- tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+ tmp = AMD_ADDBITS(tmp, maxpacket,
UDC_CSR_NE_MAX_PKT);
writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
@@ -407,7 +409,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
/* set ep values */
tmp = readl(&dev->csr->ne[udc_csr_epix]);
/* max packet */
- tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT);
/* ep number */
tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
/* ep direction */
@@ -2832,7 +2834,7 @@ __acquires(dev->lock)
/* make usb request for gadget driver */
memset(&setup_data, 0 , sizeof(union udc_setup_data));
setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
- setup_data.request.wValue = dev->cur_config;
+ setup_data.request.wValue = cpu_to_le16(dev->cur_config);
/* programm the NE registers */
for (i = 0; i < UDC_EP_NUM; i++) {
@@ -2881,8 +2883,8 @@ __acquires(dev->lock)
memset(&setup_data, 0 , sizeof(union udc_setup_data));
setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
setup_data.request.bRequestType = USB_RECIP_INTERFACE;
- setup_data.request.wValue = dev->cur_alt;
- setup_data.request.wIndex = dev->cur_intf;
+ setup_data.request.wValue = cpu_to_le16(dev->cur_alt);
+ setup_data.request.wIndex = cpu_to_le16(dev->cur_intf);
DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
dev->cur_alt, dev->cur_intf);
@@ -3248,6 +3250,8 @@ static int udc_pci_probe(
/* pci setup */
if (pci_enable_device(pdev) < 0) {
+ kfree(dev);
+ dev = 0;
retval = -ENODEV;
goto finished;
}
@@ -3259,6 +3263,8 @@ static int udc_pci_probe(
if (!request_mem_region(resource, len, name)) {
dev_dbg(&pdev->dev, "pci device used already\n");
+ kfree(dev);
+ dev = 0;
retval = -EBUSY;
goto finished;
}
@@ -3267,18 +3273,24 @@ static int udc_pci_probe(
dev->virt_addr = ioremap_nocache(resource, len);
if (dev->virt_addr == NULL) {
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+ kfree(dev);
+ dev = 0;
retval = -EFAULT;
goto finished;
}
if (!pdev->irq) {
dev_err(&dev->pdev->dev, "irq not set\n");
+ kfree(dev);
+ dev = 0;
retval = -ENODEV;
goto finished;
}
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+ kfree(dev);
+ dev = 0;
retval = -EBUSY;
goto finished;
}
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index fd15ced899d8..9b913afb2e6d 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -389,6 +389,7 @@ static int write_fifo(struct at91_ep *ep, struct at91_request *req)
u32 csr = __raw_readl(creg);
u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
unsigned total, count, is_last;
+ u8 *buf;
/*
* TODO: allow for writing two packets to the fifo ... that'll
@@ -413,6 +414,8 @@ static int write_fifo(struct at91_ep *ep, struct at91_request *req)
return 0;
}
+ buf = req->req.buf + req->req.actual;
+ prefetch(buf);
total = req->req.length - req->req.actual;
if (ep->ep.maxpacket < total) {
count = ep->ep.maxpacket;
@@ -435,7 +438,7 @@ static int write_fifo(struct at91_ep *ep, struct at91_request *req)
* recover when the actual bytecount matters (e.g. for USB Test
* and Measurement Class devices).
*/
- __raw_writesb(dreg, req->req.buf + req->req.actual, count);
+ __raw_writesb(dreg, buf, count);
csr &= ~SET_FX;
csr |= CLR_FX | AT91_UDP_TXPKTRDY;
__raw_writel(csr, creg);
@@ -457,7 +460,7 @@ static void nuke(struct at91_ep *ep, int status)
if (list_empty(&ep->queue))
return;
- VDBG("%s %s\n", __FUNCTION__, ep->ep.name);
+ VDBG("%s %s\n", __func__, ep->ep.name);
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next, struct at91_request, queue);
done(ep, req, status);
@@ -792,7 +795,7 @@ static int at91_wakeup(struct usb_gadget *gadget)
int status = -EINVAL;
unsigned long flags;
- DBG("%s\n", __FUNCTION__ );
+ DBG("%s\n", __func__ );
local_irq_save(flags);
if (!udc->clocked || !udc->suspended)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index cbe44535c0f0..42036192a03c 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -365,16 +365,14 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
case USB_SPEED_HIGH:
if (max == 512)
break;
- /* conserve return statements */
- default:
- switch (max) {
- case 8: case 16: case 32: case 64:
+ goto done;
+ case USB_SPEED_FULL:
+ if (max == 8 || max == 16 || max == 32 || max == 64)
/* we'll fake any legal size */
break;
- default:
- case USB_SPEED_LOW:
- goto done;
- }
+ /* save a return statement */
+ default:
+ goto done;
}
break;
case USB_ENDPOINT_XFER_INT:
@@ -894,13 +892,12 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
{
struct dummy *dum = platform_get_drvdata(pdev);
- dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+ dev_dbg (&pdev->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
dum->udc_suspended = 1;
set_link_state (dum);
spin_unlock_irq (&dum->lock);
- pdev->dev.power.power_state = state;
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
}
@@ -909,13 +906,12 @@ static int dummy_udc_resume (struct platform_device *pdev)
{
struct dummy *dum = platform_get_drvdata(pdev);
- dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+ dev_dbg (&pdev->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
dum->udc_suspended = 0;
set_link_state (dum);
spin_unlock_irq (&dum->lock);
- pdev->dev.power.power_state = PMSG_ON;
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
}
@@ -1559,8 +1555,7 @@ hub_descriptor (struct usb_hub_descriptor *desc)
memset (desc, 0, sizeof *desc);
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
- desc->wHubCharacteristics = (__force __u16)
- (__constant_cpu_to_le16 (0x0001));
+ desc->wHubCharacteristics = cpu_to_le16(0x0001);
desc->bNbrPorts = 1;
desc->bitmap [0] = 0xff;
desc->bitmap [1] = 0xff;
@@ -1711,7 +1706,7 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
{
struct dummy *dum = hcd_to_dummy (hcd);
- dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
+ dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
dum->rh_state = DUMMY_RH_SUSPENDED;
@@ -1726,7 +1721,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
struct dummy *dum = hcd_to_dummy (hcd);
int rc = 0;
- dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
+ dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
@@ -1900,7 +1895,7 @@ static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
struct dummy *dum;
int rc = 0;
- dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+ dev_dbg (&pdev->dev, "%s\n", __func__);
hcd = platform_get_drvdata (pdev);
dum = hcd_to_dummy (hcd);
@@ -1916,7 +1911,7 @@ static int dummy_hcd_resume (struct platform_device *pdev)
{
struct usb_hcd *hcd;
- dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+ dev_dbg (&pdev->dev, "%s\n", __func__);
hcd = platform_get_drvdata (pdev);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -1937,69 +1932,57 @@ static struct platform_driver dummy_hcd_driver = {
/*-------------------------------------------------------------------------*/
-/* These don't need to do anything because the pdev structures are
- * statically allocated. */
-static void
-dummy_udc_release (struct device *dev) {}
-
-static void
-dummy_hcd_release (struct device *dev) {}
-
-static struct platform_device the_udc_pdev = {
- .name = (char *) gadget_name,
- .id = -1,
- .dev = {
- .release = dummy_udc_release,
- },
-};
-
-static struct platform_device the_hcd_pdev = {
- .name = (char *) driver_name,
- .id = -1,
- .dev = {
- .release = dummy_hcd_release,
- },
-};
+static struct platform_device *the_udc_pdev;
+static struct platform_device *the_hcd_pdev;
static int __init init (void)
{
- int retval;
+ int retval = -ENOMEM;
if (usb_disabled ())
return -ENODEV;
- retval = platform_driver_register (&dummy_hcd_driver);
- if (retval < 0)
+ the_hcd_pdev = platform_device_alloc(driver_name, -1);
+ if (!the_hcd_pdev)
return retval;
+ the_udc_pdev = platform_device_alloc(gadget_name, -1);
+ if (!the_udc_pdev)
+ goto err_alloc_udc;
- retval = platform_driver_register (&dummy_udc_driver);
+ retval = platform_driver_register(&dummy_hcd_driver);
+ if (retval < 0)
+ goto err_register_hcd_driver;
+ retval = platform_driver_register(&dummy_udc_driver);
if (retval < 0)
goto err_register_udc_driver;
- retval = platform_device_register (&the_hcd_pdev);
+ retval = platform_device_add(the_hcd_pdev);
if (retval < 0)
- goto err_register_hcd;
-
- retval = platform_device_register (&the_udc_pdev);
+ goto err_add_hcd;
+ retval = platform_device_add(the_udc_pdev);
if (retval < 0)
- goto err_register_udc;
+ goto err_add_udc;
return retval;
-err_register_udc:
- platform_device_unregister (&the_hcd_pdev);
-err_register_hcd:
- platform_driver_unregister (&dummy_udc_driver);
+err_add_udc:
+ platform_device_del(the_hcd_pdev);
+err_add_hcd:
+ platform_driver_unregister(&dummy_udc_driver);
err_register_udc_driver:
- platform_driver_unregister (&dummy_hcd_driver);
+ platform_driver_unregister(&dummy_hcd_driver);
+err_register_hcd_driver:
+ platform_device_put(the_udc_pdev);
+err_alloc_udc:
+ platform_device_put(the_hcd_pdev);
return retval;
}
module_init (init);
static void __exit cleanup (void)
{
- platform_device_unregister (&the_udc_pdev);
- platform_device_unregister (&the_hcd_pdev);
- platform_driver_unregister (&dummy_udc_driver);
- platform_driver_unregister (&dummy_hcd_driver);
+ platform_device_unregister(the_udc_pdev);
+ platform_device_unregister(the_hcd_pdev);
+ platform_driver_unregister(&dummy_udc_driver);
+ platform_driver_unregister(&dummy_hcd_driver);
}
module_exit (cleanup);
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index f9d07108bc30..8bdad221fa91 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -34,12 +34,12 @@
/* we must assign addresses for configurable endpoints (like net2280) */
-static __devinitdata unsigned epnum;
+static __initdata unsigned epnum;
// #define MANY_ENDPOINTS
#ifdef MANY_ENDPOINTS
/* more than 15 configurable endpoints */
-static __devinitdata unsigned in_epnum;
+static __initdata unsigned in_epnum;
#endif
@@ -59,7 +59,7 @@ static __devinitdata unsigned in_epnum;
* NOTE: each endpoint is unidirectional, as specified by its USB
* descriptor; and isn't specific to a configuration or altsetting.
*/
-static int __devinit
+static int __init
ep_matches (
struct usb_gadget *gadget,
struct usb_ep *ep,
@@ -186,7 +186,7 @@ ep_matches (
return 1;
}
-static struct usb_ep * __devinit
+static struct usb_ep * __init
find_ep (struct usb_gadget *gadget, const char *name)
{
struct usb_ep *ep;
@@ -228,7 +228,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
*
* On failure, this returns a null endpoint descriptor.
*/
-struct usb_ep * __devinit usb_ep_autoconfig (
+struct usb_ep * __init usb_ep_autoconfig (
struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc
)
@@ -295,7 +295,7 @@ struct usb_ep * __devinit usb_ep_autoconfig (
* state such as ep->driver_data and the record of assigned endpoints
* used by usb_ep_autoconfig().
*/
-void __devinit usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget)
{
struct usb_ep *ep;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index e99872308144..bb93bdd76593 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -1102,7 +1102,7 @@ static void eth_reset_config (struct eth_dev *dev)
if (dev->config == 0)
return;
- DEBUG (dev, "%s\n", __FUNCTION__);
+ DEBUG (dev, "%s\n", __func__);
netif_stop_queue (dev->net);
netif_carrier_off (dev->net);
@@ -1263,7 +1263,7 @@ static void issue_start_status (struct eth_dev *dev)
struct usb_cdc_notification *event;
int value;
- DEBUG (dev, "%s, flush old status first\n", __FUNCTION__);
+ DEBUG (dev, "%s, flush old status first\n", __func__);
/* flush old status
*
@@ -1329,7 +1329,7 @@ static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
spin_lock(&dev->lock);
status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf);
if (status < 0)
- ERROR(dev, "%s: rndis parse error %d\n", __FUNCTION__, status);
+ ERROR(dev, "%s: rndis parse error %d\n", __func__, status);
spin_unlock(&dev->lock);
}
@@ -2113,7 +2113,7 @@ static int rndis_control_ack (struct net_device *net)
static void eth_start (struct eth_dev *dev, gfp_t gfp_flags)
{
- DEBUG (dev, "%s\n", __FUNCTION__);
+ DEBUG (dev, "%s\n", __func__);
/* fill the rx queue */
rx_fill (dev, gfp_flags);
@@ -2133,7 +2133,7 @@ static int eth_open (struct net_device *net)
{
struct eth_dev *dev = netdev_priv(net);
- DEBUG (dev, "%s\n", __FUNCTION__);
+ DEBUG (dev, "%s\n", __func__);
if (netif_carrier_ok (dev->net))
eth_start (dev, GFP_KERNEL);
return 0;
@@ -2143,7 +2143,7 @@ static int eth_stop (struct net_device *net)
{
struct eth_dev *dev = netdev_priv(net);
- VDEBUG (dev, "%s\n", __FUNCTION__);
+ VDEBUG (dev, "%s\n", __func__);
netif_stop_queue (net);
DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
@@ -2229,7 +2229,7 @@ eth_unbind (struct usb_gadget *gadget)
set_gadget_data (gadget, NULL);
}
-static u8 __devinit nibble (unsigned char c)
+static u8 __init nibble (unsigned char c)
{
if (likely (isdigit (c)))
return c - '0';
@@ -2239,7 +2239,7 @@ static u8 __devinit nibble (unsigned char c)
return 0;
}
-static int __devinit get_ether_addr(const char *str, u8 *dev_addr)
+static int __init get_ether_addr(const char *str, u8 *dev_addr)
{
if (str) {
unsigned i;
@@ -2260,7 +2260,7 @@ static int __devinit get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
-static int __devinit
+static int __init
eth_bind (struct usb_gadget *gadget)
{
struct eth_dev *dev;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 017a196d041f..bf3f946fd455 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -644,7 +644,7 @@ struct fsg_dev {
unsigned long atomic_bitflags;
#define REGISTERED 0
-#define CLEAR_BULK_HALTS 1
+#define IGNORE_BULK_OUT 1
#define SUSPENDED 2
struct usb_ep *bulk_in;
@@ -1104,7 +1104,7 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
if (req->actual > 0)
dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
if (req->status || req->actual != req->length)
- DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
req->status, req->actual, req->length);
if (req->status == -ECONNRESET) // Request was cancelled
usb_ep_fifo_flush(ep);
@@ -1125,7 +1125,7 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
- DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
req->status, req->actual, req->length);
if (req->status == -ECONNRESET) // Request was cancelled
usb_ep_fifo_flush(ep);
@@ -1146,7 +1146,7 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
dump_msg(fsg, "bulk-out", req->buf, req->actual);
if (req->status || req->actual != bh->bulk_out_intended_length)
- DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
req->status, req->actual,
bh->bulk_out_intended_length);
if (req->status == -ECONNRESET) // Request was cancelled
@@ -1169,7 +1169,7 @@ static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
- DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
+ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
req->status, req->actual, req->length);
if (req->status == -ECONNRESET) // Request was cancelled
usb_ep_fifo_flush(ep);
@@ -2936,8 +2936,8 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
struct usb_request *req = bh->outreq;
struct bulk_cb_wrap *cbw = req->buf;
- /* Was this a real packet? */
- if (req->status)
+ /* Was this a real packet? Should it be ignored? */
+ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
return -EINVAL;
/* Is the CBW valid? */
@@ -2948,13 +2948,17 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
req->actual,
le32_to_cpu(cbw->Signature));
- /* The Bulk-only spec says we MUST stall the bulk pipes!
- * If we want to avoid stalls, set a flag so that we will
- * clear the endpoint halts at the next reset. */
- if (!mod_data.can_stall)
- set_bit(CLEAR_BULK_HALTS, &fsg->atomic_bitflags);
- fsg_set_halt(fsg, fsg->bulk_out);
+ /* The Bulk-only spec says we MUST stall the IN endpoint
+ * (6.6.1), so it's unavoidable. It also says we must
+ * retain this state until the next reset, but there's
+ * no way to tell the controller driver it should ignore
+ * Clear-Feature(HALT) requests.
+ *
+ * We aren't required to halt the OUT endpoint; instead
+ * we can simply accept and discard any data received
+ * until the next reset. */
halt_bulk_in_endpoint(fsg);
+ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
return -EINVAL;
}
@@ -3140,6 +3144,7 @@ reset:
goto reset;
fsg->bulk_out_enabled = 1;
fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
if (transport_is_cbi()) {
d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc);
@@ -3321,11 +3326,8 @@ static void handle_exception(struct fsg_dev *fsg)
/* In case we were forced against our will to halt a
* bulk endpoint, clear the halt now. (The SuperH UDC
* requires this.) */
- if (test_and_clear_bit(CLEAR_BULK_HALTS,
- &fsg->atomic_bitflags)) {
+ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
usb_ep_clear_halt(fsg->bulk_in);
- usb_ep_clear_halt(fsg->bulk_out);
- }
if (transport_is_bbb()) {
if (fsg->ep0_req_tag == exception_req_tag)
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 254012ad2b91..651b82701394 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -773,11 +773,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
- VDBG("%s, bad params\n", __FUNCTION__);
+ VDBG("%s, bad params\n", __func__);
return -EINVAL;
}
if (unlikely(!_ep || !ep->desc)) {
- VDBG("%s, bad ep\n", __FUNCTION__);
+ VDBG("%s, bad ep\n", __func__);
return -EINVAL;
}
if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 9fb0b1ec8526..98b1483ef6a5 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -512,7 +512,7 @@ struct fsl_udc {
#ifdef DEBUG
#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
- __FUNCTION__, ## args)
+ __func__, ## args)
#else
#define DBG(fmt, args...) do{}while(0)
#endif
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 5b42ccd0035f..7f4d4828e3aa 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -229,7 +229,7 @@ static const struct usb_ac_header_descriptor_1 ac_header_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
.bcdADC = __constant_cpu_to_le16(0x0100),
- .wTotalLength = USB_DT_AC_HEADER_SIZE(1),
+ .wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_SIZE(1)),
.bInCollection = 1,
.baInterfaceNr = {
[0] = GMIDI_MS_INTERFACE,
@@ -253,9 +253,9 @@ static const struct usb_ms_header_descriptor ms_header_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
.bcdMSC = __constant_cpu_to_le16(0x0100),
- .wTotalLength = USB_DT_MS_HEADER_SIZE
+ .wTotalLength = __constant_cpu_to_le16(USB_DT_MS_HEADER_SIZE
+ 2*USB_DT_MIDI_IN_SIZE
- + 2*USB_DT_MIDI_OUT_SIZE(1),
+ + 2*USB_DT_MIDI_OUT_SIZE(1)),
};
#define JACK_IN_EMB 1
@@ -1149,7 +1149,7 @@ fail:
/*
* Creates an output endpoint, and initializes output ports.
*/
-static int __devinit gmidi_bind(struct usb_gadget *gadget)
+static int __init gmidi_bind(struct usb_gadget *gadget)
{
struct gmidi_device *dev;
struct usb_ep *in_ep, *out_ep;
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d3e702576de6..64a592cbbe7b 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -692,7 +692,7 @@ static void abort_dma(struct goku_ep *ep, int status)
req->req.actual = (curr - req->req.dma) + 1;
req->req.status = status;
- VDBG(ep->dev, "%s %s %s %d/%d\n", __FUNCTION__, ep->ep.name,
+ VDBG(ep->dev, "%s %s %s %d/%d\n", __func__, ep->ep.name,
ep->is_in ? "IN" : "OUT",
req->req.actual, req->req.length);
@@ -826,7 +826,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req)
if (dev->ep0state == EP0_SUSPEND)
return -EBUSY;
- VDBG(dev, "%s %s %s %s %p\n", __FUNCTION__, _ep->name,
+ VDBG(dev, "%s %s %s %s %p\n", __func__, _ep->name,
ep->is_in ? "IN" : "OUT",
ep->dma ? "dma" : "pio",
_req);
@@ -898,7 +898,7 @@ static int goku_set_halt(struct usb_ep *_ep, int value)
/* don't change EPxSTATUS_EP_INVALID to READY */
} else if (!ep->desc) {
- DBG(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);
+ DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
return -EINVAL;
}
@@ -940,7 +940,7 @@ static int goku_fifo_status(struct usb_ep *_ep)
regs = ep->dev->regs;
size = readl(&regs->EPxSizeLA[ep->num]) & DATASIZE;
size += readl(&regs->EPxSizeLB[ep->num]) & DATASIZE;
- VDBG(ep->dev, "%s %s %u\n", __FUNCTION__, ep->ep.name, size);
+ VDBG(ep->dev, "%s %s %u\n", __func__, ep->ep.name, size);
return size;
}
@@ -953,11 +953,11 @@ static void goku_fifo_flush(struct usb_ep *_ep)
if (!_ep)
return;
ep = container_of(_ep, struct goku_ep, ep);
- VDBG(ep->dev, "%s %s\n", __FUNCTION__, ep->ep.name);
+ VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name);
/* don't change EPxSTATUS_EP_INVALID to READY */
if (!ep->desc && ep->num != 0) {
- DBG(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);
+ DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
return;
}
@@ -1286,7 +1286,7 @@ static void ep0_start(struct goku_udc *dev)
struct goku_udc_regs __iomem *regs = dev->regs;
unsigned i;
- VDBG(dev, "%s\n", __FUNCTION__);
+ VDBG(dev, "%s\n", __func__);
udc_reset(dev);
udc_reinit (dev);
@@ -1322,7 +1322,7 @@ static void udc_enable(struct goku_udc *dev)
if (readl(&dev->regs->power_detect) & PW_DETECT)
ep0_start(dev);
else {
- DBG(dev, "%s\n", __FUNCTION__);
+ DBG(dev, "%s\n", __func__);
dev->int_enable = INT_PWRDETECT;
writel(dev->int_enable, &dev->regs->int_enable);
}
@@ -1387,7 +1387,7 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
{
unsigned i;
- DBG (dev, "%s\n", __FUNCTION__);
+ DBG (dev, "%s\n", __func__);
if (dev->gadget.speed == USB_SPEED_UNKNOWN)
driver = NULL;
@@ -1726,7 +1726,7 @@ static void goku_remove(struct pci_dev *pdev)
{
struct goku_udc *dev = pci_get_drvdata(pdev);
- DBG(dev, "%s\n", __FUNCTION__);
+ DBG(dev, "%s\n", __func__);
BUG_ON(dev->driver);
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 0a6feafc8d28..69b0a2754f2a 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1107,13 +1107,13 @@ scan:
switch (state) {
default:
- DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
+ DBG (dev, "fail %s, state %d\n", __func__, state);
retval = -ESRCH;
break;
case STATE_DEV_UNCONNECTED:
case STATE_DEV_CONNECTED:
spin_unlock_irq (&dev->lock);
- DBG (dev, "%s wait\n", __FUNCTION__);
+ DBG (dev, "%s wait\n", __func__);
/* wait for events */
retval = wait_event_interruptible (dev->wait,
@@ -1222,7 +1222,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
DBG(dev, "bogus ep0out stall!\n");
}
} else
- DBG (dev, "fail %s, state %d\n", __FUNCTION__, dev->state);
+ DBG (dev, "fail %s, state %d\n", __func__, dev->state);
spin_unlock_irq (&dev->lock);
return retval;
@@ -1233,7 +1233,7 @@ ep0_fasync (int f, struct file *fd, int on)
{
struct dev_data *dev = fd->private_data;
// caller must F_SETOWN before signal delivery happens
- VDEBUG (dev, "%s %s\n", __FUNCTION__, on ? "on" : "off");
+ VDEBUG (dev, "%s %s\n", __func__, on ? "on" : "off");
return fasync_helper (f, fd, on, &dev->fasync);
}
@@ -1575,7 +1575,7 @@ static void destroy_ep_files (struct dev_data *dev)
{
struct list_head *entry, *tmp;
- DBG (dev, "%s %d\n", __FUNCTION__, dev->state);
+ DBG (dev, "%s %d\n", __func__, dev->state);
/* dev->state must prevent interference */
restart:
@@ -1662,7 +1662,7 @@ enomem1:
put_dev (dev);
kfree (data);
enomem0:
- DBG (dev, "%s enomem\n", __FUNCTION__);
+ DBG (dev, "%s enomem\n", __func__);
destroy_ep_files (dev);
return -ENOMEM;
}
@@ -1672,7 +1672,7 @@ gadgetfs_unbind (struct usb_gadget *gadget)
{
struct dev_data *dev = get_gadget_data (gadget);
- DBG (dev, "%s\n", __FUNCTION__);
+ DBG (dev, "%s\n", __func__);
spin_lock_irq (&dev->lock);
dev->state = STATE_DEV_UNBOUND;
@@ -1685,7 +1685,7 @@ gadgetfs_unbind (struct usb_gadget *gadget)
/* we've already been disconnected ... no i/o is active */
if (dev->req)
usb_ep_free_request (gadget->ep0, dev->req);
- DBG (dev, "%s done\n", __FUNCTION__);
+ DBG (dev, "%s done\n", __func__);
put_dev (dev);
}
@@ -1933,7 +1933,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
fail:
spin_unlock_irq (&dev->lock);
- pr_debug ("%s: %s fail %Zd, %p\n", shortname, __FUNCTION__, value, dev);
+ pr_debug ("%s: %s fail %Zd, %p\n", shortname, __func__, value, dev);
kfree (dev->buf);
dev->buf = NULL;
return value;
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 078f72467671..825abd2621b3 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -253,7 +253,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
*/
static void udc_disable(struct lh7a40x_udc *dev)
{
- DEBUG("%s, %p\n", __FUNCTION__, dev);
+ DEBUG("%s, %p\n", __func__, dev);
udc_set_address(dev, 0);
@@ -285,7 +285,7 @@ static void udc_reinit(struct lh7a40x_udc *dev)
{
u32 i;
- DEBUG("%s, %p\n", __FUNCTION__, dev);
+ DEBUG("%s, %p\n", __func__, dev);
/* device/ep0 records init */
INIT_LIST_HEAD(&dev->gadget.ep_list);
@@ -318,7 +318,7 @@ static void udc_enable(struct lh7a40x_udc *dev)
{
int ep;
- DEBUG("%s, %p\n", __FUNCTION__, dev);
+ DEBUG("%s, %p\n", __func__, dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
@@ -412,7 +412,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
struct lh7a40x_udc *dev = the_controller;
int retval;
- DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name);
+ DEBUG("%s: %s\n", __func__, driver->driver.name);
if (!driver
|| driver->speed != USB_SPEED_FULL
@@ -521,7 +521,7 @@ static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
is_short = unlikely(max < ep_maxpacket(ep));
}
- DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__,
+ DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __func__,
ep->ep.name, count,
is_last ? "/L" : "", is_short ? "/S" : "",
req->req.length - req->req.actual, req);
@@ -555,7 +555,7 @@ static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
/* make sure there's a packet in the FIFO. */
csr = usb_read(ep->csr1);
if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) {
- DEBUG("%s: Packet NOT ready!\n", __FUNCTION__);
+ DEBUG("%s: Packet NOT ready!\n", __func__);
return -EINVAL;
}
@@ -614,7 +614,7 @@ static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status)
unsigned int stopped = ep->stopped;
u32 index;
- DEBUG("%s, %p\n", __FUNCTION__, ep);
+ DEBUG("%s, %p\n", __func__, ep);
list_del_init(&req->queue);
if (likely(req->req.status == -EINPROGRESS))
@@ -644,7 +644,7 @@ static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status)
/** Enable EP interrupt */
static void pio_irq_enable(int ep)
{
- DEBUG("%s: %d\n", __FUNCTION__, ep);
+ DEBUG("%s: %d\n", __func__, ep);
switch (ep) {
case 1:
@@ -665,7 +665,7 @@ static void pio_irq_enable(int ep)
/** Disable EP interrupt */
static void pio_irq_disable(int ep)
{
- DEBUG("%s: %d\n", __FUNCTION__, ep);
+ DEBUG("%s: %d\n", __func__, ep);
switch (ep) {
case 1:
@@ -690,7 +690,7 @@ void nuke(struct lh7a40x_ep *ep, int status)
{
struct lh7a40x_request *req;
- DEBUG("%s, %p\n", __FUNCTION__, ep);
+ DEBUG("%s, %p\n", __func__, ep);
/* Flush FIFO */
flush(ep);
@@ -734,7 +734,7 @@ static void flush_all(struct lh7a40x_udc *dev)
*/
static void flush(struct lh7a40x_ep *ep)
{
- DEBUG("%s, %p\n", __FUNCTION__, ep);
+ DEBUG("%s, %p\n", __func__, ep);
switch (ep->ep_type) {
case ep_control:
@@ -766,7 +766,7 @@ static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
usb_set_index(ep_idx);
csr = usb_read(ep->csr1);
- DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr);
+ DEBUG("%s: %d, csr %x\n", __func__, ep_idx, csr);
if (csr & USB_IN_CSR1_SENT_STALL) {
DEBUG("USB_IN_CSR1_SENT_STALL\n");
@@ -776,7 +776,7 @@ static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
}
if (!ep->desc) {
- DEBUG("%s: NO EP DESC\n", __FUNCTION__);
+ DEBUG("%s: NO EP DESC\n", __func__);
return;
}
@@ -802,7 +802,7 @@ static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
struct lh7a40x_ep *ep = &dev->ep[ep_idx];
struct lh7a40x_request *req;
- DEBUG("%s: %d\n", __FUNCTION__, ep_idx);
+ DEBUG("%s: %d\n", __func__, ep_idx);
usb_set_index(ep_idx);
@@ -814,11 +814,11 @@ static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
usb_read(ep->
csr1)) & (USB_OUT_CSR1_OUT_PKT_RDY |
USB_OUT_CSR1_SENT_STALL)) {
- DEBUG("%s: %x\n", __FUNCTION__, csr);
+ DEBUG("%s: %x\n", __func__, csr);
if (csr & USB_OUT_CSR1_SENT_STALL) {
DEBUG("%s: stall sent, flush fifo\n",
- __FUNCTION__);
+ __func__);
/* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */
flush(ep);
} else if (csr & USB_OUT_CSR1_OUT_PKT_RDY) {
@@ -832,7 +832,7 @@ static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
if (!req) {
printk("%s: NULL REQ %d\n",
- __FUNCTION__, ep_idx);
+ __func__, ep_idx);
flush(ep);
break;
} else {
@@ -844,7 +844,7 @@ static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
} else {
/* Throw packet away.. */
- printk("%s: No descriptor?!?\n", __FUNCTION__);
+ printk("%s: No descriptor?!?\n", __func__);
flush(ep);
}
}
@@ -886,7 +886,7 @@ static void lh7a40x_reset_intr(struct lh7a40x_udc *dev)
#if 0 /* def CONFIG_ARCH_LH7A404 */
/* Does not work always... */
- DEBUG("%s: %d\n", __FUNCTION__, dev->usb_address);
+ DEBUG("%s: %d\n", __func__, dev->usb_address);
if (!dev->usb_address) {
/*usb_set(USB_RESET_IO, USB_RESET);
@@ -936,7 +936,7 @@ static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev)
if (!intr_out && !intr_in && !intr_int)
break;
- DEBUG("%s (on state %s)\n", __FUNCTION__,
+ DEBUG("%s (on state %s)\n", __func__,
state_names[dev->ep0state]);
DEBUG("intr_out = %x\n", intr_out);
DEBUG("intr_in = %x\n", intr_in);
@@ -1016,14 +1016,14 @@ static int lh7a40x_ep_enable(struct usb_ep *_ep,
struct lh7a40x_udc *dev;
unsigned long flags;
- DEBUG("%s, %p\n", __FUNCTION__, _ep);
+ DEBUG("%s, %p\n", __func__, _ep);
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) {
- DEBUG("%s, bad ep or descriptor\n", __FUNCTION__);
+ DEBUG("%s, bad ep or descriptor\n", __func__);
return -EINVAL;
}
@@ -1031,7 +1031,7 @@ static int lh7a40x_ep_enable(struct usb_ep *_ep,
if (ep->bmAttributes != desc->bmAttributes
&& ep->bmAttributes != USB_ENDPOINT_XFER_BULK
&& desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
- DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
+ DEBUG("%s, %s type mismatch\n", __func__, _ep->name);
return -EINVAL;
}
@@ -1039,13 +1039,13 @@ static int lh7a40x_ep_enable(struct usb_ep *_ep,
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep))
|| !desc->wMaxPacketSize) {
- DEBUG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
+ DEBUG("%s, bad %s maxpacket\n", __func__, _ep->name);
return -ERANGE;
}
dev = ep->dev;
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
- DEBUG("%s, bogus device state\n", __FUNCTION__);
+ DEBUG("%s, bogus device state\n", __func__);
return -ESHUTDOWN;
}
@@ -1061,7 +1061,7 @@ static int lh7a40x_ep_enable(struct usb_ep *_ep,
/* Reset halt state (does flush) */
lh7a40x_set_halt(_ep, 0);
- DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name);
+ DEBUG("%s: enabled %s\n", __func__, _ep->name);
return 0;
}
@@ -1073,11 +1073,11 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep)
struct lh7a40x_ep *ep;
unsigned long flags;
- DEBUG("%s, %p\n", __FUNCTION__, _ep);
+ DEBUG("%s, %p\n", __func__, _ep);
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (!_ep || !ep->desc) {
- DEBUG("%s, %s not enabled\n", __FUNCTION__,
+ DEBUG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -1097,7 +1097,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep)
spin_unlock_irqrestore(&ep->dev->lock, flags);
- DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name);
+ DEBUG("%s: disabled %s\n", __func__, _ep->name);
return 0;
}
@@ -1106,7 +1106,7 @@ static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,
{
struct lh7a40x_request *req;
- DEBUG("%s, %p\n", __FUNCTION__, ep);
+ DEBUG("%s, %p\n", __func__, ep);
req = kzalloc(sizeof(*req), gfp_flags);
if (!req)
@@ -1121,7 +1121,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
{
struct lh7a40x_request *req;
- DEBUG("%s, %p\n", __FUNCTION__, ep);
+ DEBUG("%s, %p\n", __func__, ep);
req = container_of(_req, struct lh7a40x_request, req);
WARN_ON(!list_empty(&req->queue));
@@ -1140,25 +1140,25 @@ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req,
struct lh7a40x_udc *dev;
unsigned long flags;
- DEBUG("\n\n\n%s, %p\n", __FUNCTION__, _ep);
+ DEBUG("\n\n\n%s, %p\n", __func__, _ep);
req = container_of(_req, struct lh7a40x_request, req);
if (unlikely
(!_req || !_req->complete || !_req->buf
|| !list_empty(&req->queue))) {
- DEBUG("%s, bad params\n", __FUNCTION__);
+ DEBUG("%s, bad params\n", __func__);
return -EINVAL;
}
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
- DEBUG("%s, bad ep\n", __FUNCTION__);
+ DEBUG("%s, bad ep\n", __func__);
return -EINVAL;
}
dev = ep->dev;
if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
- DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver);
+ DEBUG("%s, bogus device state %p\n", __func__, dev->driver);
return -ESHUTDOWN;
}
@@ -1218,7 +1218,7 @@ static int lh7a40x_dequeue(struct usb_ep *_ep, struct usb_request *_req)
struct lh7a40x_request *req;
unsigned long flags;
- DEBUG("%s, %p\n", __FUNCTION__, _ep);
+ DEBUG("%s, %p\n", __func__, _ep);
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (!_ep || ep->ep.name == ep0name)
@@ -1253,13 +1253,13 @@ static int lh7a40x_set_halt(struct usb_ep *_ep, int value)
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
- DEBUG("%s, bad ep\n", __FUNCTION__);
+ DEBUG("%s, bad ep\n", __func__);
return -EINVAL;
}
usb_set_index(ep_index(ep));
- DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value);
+ DEBUG("%s, ep %d, val %d\n", __func__, ep_index(ep), value);
spin_lock_irqsave(&ep->dev->lock, flags);
@@ -1325,11 +1325,11 @@ static int lh7a40x_fifo_status(struct usb_ep *_ep)
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (!_ep) {
- DEBUG("%s, bad ep\n", __FUNCTION__);
+ DEBUG("%s, bad ep\n", __func__);
return -ENODEV;
}
- DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep));
+ DEBUG("%s, %d\n", __func__, ep_index(ep));
/* LPD can't report unclaimed bytes from IN fifos */
if (ep_is_in(ep))
@@ -1355,7 +1355,7 @@ static void lh7a40x_fifo_flush(struct usb_ep *_ep)
ep = container_of(_ep, struct lh7a40x_ep, ep);
if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
- DEBUG("%s, bad ep\n", __FUNCTION__);
+ DEBUG("%s, bad ep\n", __func__);
return;
}
@@ -1376,7 +1376,7 @@ static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
max = ep_maxpacket(ep);
- DEBUG_EP0("%s\n", __FUNCTION__);
+ DEBUG_EP0("%s\n", __func__);
count = write_packet(ep, req, max);
@@ -1390,7 +1390,7 @@ static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
is_last = 1;
}
- DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,
+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __func__,
ep->ep.name, count,
is_last ? "/L" : "", req->req.length - req->req.actual, req);
@@ -1434,7 +1434,7 @@ static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
unsigned bufferspace, count, is_short;
volatile u32 *fifo = (volatile u32 *)ep->fifo;
- DEBUG_EP0("%s\n", __FUNCTION__);
+ DEBUG_EP0("%s\n", __func__);
csr = usb_read(USB_EP0_CSR);
if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY))
@@ -1492,7 +1492,7 @@ static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
*/
static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address)
{
- DEBUG_EP0("%s: %d\n", __FUNCTION__, address);
+ DEBUG_EP0("%s: %d\n", __func__, address);
/* c.f. 15.1.2.2 Table 15-4 address will be used after DATA_END is set */
dev->usb_address = address;
usb_set((address & USB_FA_FUNCTION_ADDR), USB_FA);
@@ -1514,7 +1514,7 @@ static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr)
struct lh7a40x_ep *ep = &dev->ep[0];
int ret;
- DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: %x\n", __func__, csr);
if (list_empty(&ep->queue))
req = 0;
@@ -1533,13 +1533,13 @@ static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr)
if (ret) {
/* Done! */
DEBUG_EP0("%s: finished, waiting for status\n",
- __FUNCTION__);
+ __func__);
usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);
dev->ep0state = WAIT_FOR_SETUP;
} else {
/* Not done yet.. */
- DEBUG_EP0("%s: not finished\n", __FUNCTION__);
+ DEBUG_EP0("%s: not finished\n", __func__);
usb_set(EP0_CLR_OUT, USB_EP0_CSR);
}
} else {
@@ -1556,7 +1556,7 @@ static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr)
struct lh7a40x_ep *ep = &dev->ep[0];
int ret, need_zlp = 0;
- DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: %x\n", __func__, csr);
if (list_empty(&ep->queue))
req = 0;
@@ -1564,7 +1564,7 @@ static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr)
req = list_entry(ep->queue.next, struct lh7a40x_request, queue);
if (!req) {
- DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);
+ DEBUG_EP0("%s: NULL REQ\n", __func__);
return 0;
}
@@ -1585,17 +1585,17 @@ static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr)
if (ret == 1 && !need_zlp) {
/* Last packet */
- DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__);
+ DEBUG_EP0("%s: finished, waiting for status\n", __func__);
usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);
dev->ep0state = WAIT_FOR_SETUP;
} else {
- DEBUG_EP0("%s: not finished\n", __FUNCTION__);
+ DEBUG_EP0("%s: not finished\n", __func__);
usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR);
}
if (need_zlp) {
- DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__);
+ DEBUG_EP0("%s: Need ZLP!\n", __func__);
usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR);
dev->ep0state = DATA_STATE_NEED_ZLP;
}
@@ -1694,7 +1694,7 @@ static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr)
struct usb_ctrlrequest ctrl;
int i, bytes, is_in;
- DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr);
+ DEBUG_SETUP("%s: %x\n", __func__, csr);
/* Nuke all previous transfers */
nuke(ep, -EPROTO);
@@ -1799,7 +1799,7 @@ static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr)
*/
static void lh7a40x_ep0_in_zlp(struct lh7a40x_udc *dev, u32 csr)
{
- DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: %x\n", __func__, csr);
/* c.f. Table 15-14 */
usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);
@@ -1818,7 +1818,7 @@ static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr)
usb_set_index(0);
csr = usb_read(USB_EP0_CSR);
- DEBUG_EP0("%s: csr = %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: csr = %x\n", __func__, csr);
/*
* For overview of what we should be doing see c.f. Chapter 18.1.2.4
@@ -1832,7 +1832,7 @@ static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr)
* - clear the SENT_STALL bit
*/
if (csr & EP0_SENT_STALL) {
- DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __func__, csr);
usb_clear((EP0_SENT_STALL | EP0_SEND_STALL), USB_EP0_CSR);
nuke(ep, -ECONNABORTED);
dev->ep0state = WAIT_FOR_SETUP;
@@ -1849,7 +1849,7 @@ static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr)
*/
if (!(csr & (EP0_IN_PKT_RDY | EP0_OUT_PKT_RDY))) {
DEBUG_EP0("%s: IN_PKT_RDY and OUT_PKT_RDY are clear\n",
- __FUNCTION__);
+ __func__);
switch (dev->ep0state) {
case DATA_STATE_XMIT:
@@ -1877,7 +1877,7 @@ static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr)
* - set SERVICED_SETUP_END_BIT
*/
if (csr & EP0_SETUP_END) {
- DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __func__, csr);
usb_set(EP0_CLR_SETUP_END, USB_EP0_CSR);
@@ -1896,7 +1896,7 @@ static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr)
*/
if (csr & EP0_OUT_PKT_RDY) {
- DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__,
+ DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __func__,
csr);
switch (dev->ep0state) {
@@ -1926,7 +1926,7 @@ static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep)
usb_set_index(0);
csr = usb_read(USB_EP0_CSR);
- DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+ DEBUG_EP0("%s: %x\n", __func__, csr);
/* Clear "out packet ready" */
usb_set(EP0_CLR_OUT, USB_EP0_CSR);
@@ -1949,7 +1949,7 @@ static int lh7a40x_udc_get_frame(struct usb_gadget *_gadget)
{
u32 frame1 = usb_read(USB_FRM_NUM1); /* Least significant 8 bits */
u32 frame2 = usb_read(USB_FRM_NUM2); /* Most significant 3 bits */
- DEBUG("%s, %p\n", __FUNCTION__, _gadget);
+ DEBUG("%s, %p\n", __func__, _gadget);
return ((frame2 & 0x07) << 8) | (frame1 & 0xff);
}
@@ -1970,7 +1970,7 @@ static const struct usb_gadget_ops lh7a40x_udc_ops = {
static void nop_release(struct device *dev)
{
- DEBUG("%s %s\n", __FUNCTION__, dev->bus_id);
+ DEBUG("%s %s\n", __func__, dev->bus_id);
}
static struct lh7a40x_udc memory = {
@@ -2065,7 +2065,7 @@ static int lh7a40x_udc_probe(struct platform_device *pdev)
struct lh7a40x_udc *dev = &memory;
int retval;
- DEBUG("%s: %p\n", __FUNCTION__, pdev);
+ DEBUG("%s: %p\n", __func__, pdev);
spin_lock_init(&dev->lock);
dev->dev = &pdev->dev;
@@ -2098,7 +2098,7 @@ static int lh7a40x_udc_remove(struct platform_device *pdev)
{
struct lh7a40x_udc *dev = platform_get_drvdata(pdev);
- DEBUG("%s: %p\n", __FUNCTION__, pdev);
+ DEBUG("%s: %p\n", __func__, pdev);
if (dev->driver)
return -EBUSY;
@@ -2131,7 +2131,7 @@ static struct platform_driver udc_driver = {
static int __init udc_init(void)
{
- DEBUG("%s: %s version %s\n", __FUNCTION__, driver_name, DRIVER_VERSION);
+ DEBUG("%s: %s version %s\n", __func__, driver_name, DRIVER_VERSION);
return platform_driver_register(&udc_driver);
}
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 17b792b7f6bf..f118f00f1466 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -485,11 +485,11 @@ struct m66592 {
struct m66592_ep *epaddr2ep[16];
struct usb_request *ep0_req; /* for internal request */
- u16 ep0_data; /* for internal request */
+ __le16 ep0_data; /* for internal request */
+ u16 old_vbus;
struct timer_list timer;
- u16 old_vbus;
int scount;
int old_dvsq;
diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
index 44ca139983d8..1f2af398a9a4 100644
--- a/drivers/usb/gadget/net2280.h
+++ b/drivers/usb/gadget/net2280.h
@@ -299,7 +299,7 @@ static inline void assert_out_naking (struct net2280_ep *ep, const char *where)
&ep->regs->ep_rsp);
}
}
-#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__FUNCTION__)
+#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__func__)
#else
#define ASSERT_OUT_NAKING(ep) do {} while (0)
#endif
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index ee1e9a314cd1..95f7662376f1 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -163,7 +163,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->maxpacket < le16_to_cpu
(desc->wMaxPacketSize)) {
- DBG("%s, bad ep or descriptor\n", __FUNCTION__);
+ DBG("%s, bad ep or descriptor\n", __func__);
return -EINVAL;
}
maxp = le16_to_cpu (desc->wMaxPacketSize);
@@ -171,7 +171,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
&& maxp != ep->maxpacket)
|| le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
|| !desc->wMaxPacketSize) {
- DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
+ DBG("%s, bad %s maxpacket\n", __func__, _ep->name);
return -ERANGE;
}
@@ -194,13 +194,13 @@ static int omap_ep_enable(struct usb_ep *_ep,
if (ep->bmAttributes != desc->bmAttributes
&& ep->bmAttributes != USB_ENDPOINT_XFER_BULK
&& desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
- DBG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
+ DBG("%s, %s type mismatch\n", __func__, _ep->name);
return -EINVAL;
}
udc = ep->udc;
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
- DBG("%s, bogus device state\n", __FUNCTION__);
+ DBG("%s, bogus device state\n", __func__);
return -ESHUTDOWN;
}
@@ -249,7 +249,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
unsigned long flags;
if (!_ep || !ep->desc) {
- DBG("%s, %s not enabled\n", __FUNCTION__,
+ DBG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -936,11 +936,11 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
- DBG("%s, bad params\n", __FUNCTION__);
+ DBG("%s, bad params\n", __func__);
return -EINVAL;
}
if (!_ep || (!ep->desc && ep->bEndpointAddress)) {
- DBG("%s, bad ep\n", __FUNCTION__);
+ DBG("%s, bad ep\n", __func__);
return -EINVAL;
}
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
@@ -959,7 +959,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
&& (ep->bEndpointAddress & USB_DIR_IN) == 0
&& !cpu_class_is_omap2()
&& (req->req.length % ep->ep.maxpacket) != 0) {
- DBG("%s, no partial packet OUT reads\n", __FUNCTION__);
+ DBG("%s, no partial packet OUT reads\n", __func__);
return -EMSGSIZE;
}
@@ -1265,8 +1265,6 @@ static int can_pullup(struct omap_udc *udc)
static void pullup_enable(struct omap_udc *udc)
{
- udc->gadget.dev.parent->power.power_state = PMSG_ON;
- udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG |= OTG_BSESSVLD;
@@ -3061,8 +3059,6 @@ static int omap_udc_suspend(struct platform_device *dev, pm_message_t message)
omap_pullup(&udc->gadget, 0);
}
- udc->gadget.dev.power.power_state = PMSG_SUSPEND;
- udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
return 0;
}
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 2c32bd08ee7d..76be75e3ab8f 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -390,9 +390,12 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
/* normal completion */
case 0:
- list_add_tail(&req->list, &dev->rx_buffers);
- wake_up_interruptible(&dev->rx_wait);
- DBG(dev, "G_Printer : rx length %d\n", req->actual);
+ if (req->actual > 0) {
+ list_add_tail(&req->list, &dev->rx_buffers);
+ DBG(dev, "G_Printer : rx length %d\n", req->actual);
+ } else {
+ list_add(&req->list, &dev->rx_reqs);
+ }
break;
/* software-driven interface shutdown */
@@ -417,6 +420,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
list_add(&req->list, &dev->rx_reqs);
break;
}
+
+ wake_up_interruptible(&dev->rx_wait);
spin_unlock_irqrestore(&dev->lock, flags);
}
@@ -494,6 +499,39 @@ printer_close(struct inode *inode, struct file *fd)
return 0;
}
+/* This function must be called with interrupts turned off. */
+static void
+setup_rx_reqs(struct printer_dev *dev)
+{
+ struct usb_request *req;
+
+ while (likely(!list_empty(&dev->rx_reqs))) {
+ int error;
+
+ req = container_of(dev->rx_reqs.next,
+ struct usb_request, list);
+ list_del_init(&req->list);
+
+ /* The USB Host sends us whatever amount of data it wants to
+ * so we always set the length field to the full USB_BUFSIZE.
+ * If the amount of data is more than the read() caller asked
+ * for it will be stored in the request buffer until it is
+ * asked for by read().
+ */
+ req->length = USB_BUFSIZE;
+ req->complete = rx_complete;
+
+ error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+ if (error) {
+ DBG(dev, "rx submit --> %d\n", error);
+ list_add(&req->list, &dev->rx_reqs);
+ break;
+ } else {
+ list_add(&req->list, &dev->rx_reqs_active);
+ }
+ }
+}
+
static ssize_t
printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
@@ -522,31 +560,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
*/
dev->reset_printer = 0;
- while (likely(!list_empty(&dev->rx_reqs))) {
- int error;
-
- req = container_of(dev->rx_reqs.next,
- struct usb_request, list);
- list_del_init(&req->list);
-
- /* The USB Host sends us whatever amount of data it wants to
- * so we always set the length field to the full USB_BUFSIZE.
- * If the amount of data is more than the read() caller asked
- * for it will be stored in the request buffer until it is
- * asked for by read().
- */
- req->length = USB_BUFSIZE;
- req->complete = rx_complete;
-
- error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
- if (error) {
- DBG(dev, "rx submit --> %d\n", error);
- list_add(&req->list, &dev->rx_reqs);
- break;
- } else {
- list_add(&req->list, &dev->rx_reqs_active);
- }
- }
+ setup_rx_reqs(dev);
bytes_copied = 0;
current_rx_req = dev->current_rx_req;
@@ -615,9 +629,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irqsave(&dev->lock, flags);
- /* We've disconnected or reset free the req and buffer */
+ /* We've disconnected or reset so return. */
if (dev->reset_printer) {
- printer_req_free(dev->out_ep, current_rx_req);
+ list_add(&current_rx_req->list, &dev->rx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
spin_unlock(&dev->lock_printer_io);
return -EAGAIN;
@@ -735,7 +749,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
/* We've disconnected or reset so free the req and buffer */
if (dev->reset_printer) {
- printer_req_free(dev->in_ep, req);
+ list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
spin_unlock(&dev->lock_printer_io);
return -EAGAIN;
@@ -791,6 +805,12 @@ printer_poll(struct file *fd, poll_table *wait)
unsigned long flags;
int status = 0;
+ spin_lock(&dev->lock_printer_io);
+ spin_lock_irqsave(&dev->lock, flags);
+ setup_rx_reqs(dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+
poll_wait(fd, &dev->rx_wait, wait);
poll_wait(fd, &dev->tx_wait, wait);
@@ -798,7 +818,8 @@ printer_poll(struct file *fd, poll_table *wait)
if (likely(!list_empty(&dev->tx_reqs)))
status |= POLLOUT | POLLWRNORM;
- if (likely(!list_empty(&dev->rx_buffers)))
+ if (likely(dev->current_rx_bytes) ||
+ likely(!list_empty(&dev->rx_buffers)))
status |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&dev->lock, flags);
@@ -894,7 +915,7 @@ static void printer_reset_interface(struct printer_dev *dev)
if (dev->interface < 0)
return;
- DBG(dev, "%s\n", __FUNCTION__);
+ DBG(dev, "%s\n", __func__);
if (dev->in)
usb_ep_disable(dev->in_ep);
@@ -1084,6 +1105,7 @@ static void printer_soft_reset(struct printer_dev *dev)
if (usb_ep_enable(dev->out_ep, dev->out))
DBG(dev, "Failed to enable USB out_ep\n");
+ wake_up_interruptible(&dev->rx_wait);
wake_up_interruptible(&dev->tx_wait);
wake_up_interruptible(&dev->tx_flush_wait);
}
@@ -1262,7 +1284,7 @@ printer_disconnect(struct usb_gadget *gadget)
struct printer_dev *dev = get_gadget_data(gadget);
unsigned long flags;
- DBG(dev, "%s\n", __FUNCTION__);
+ DBG(dev, "%s\n", __func__);
spin_lock_irqsave(&dev->lock, flags);
@@ -1278,7 +1300,7 @@ printer_unbind(struct usb_gadget *gadget)
struct usb_request *req;
- DBG(dev, "%s\n", __FUNCTION__);
+ DBG(dev, "%s\n", __func__);
/* Remove sysfs files */
device_destroy(usb_gadget_class, g_printer_devno);
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index c00cd8b9d3d1..08f699b1fc57 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -235,7 +235,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->fifo_size < le16_to_cpu
(desc->wMaxPacketSize)) {
- DMSG("%s, bad ep or descriptor\n", __FUNCTION__);
+ DMSG("%s, bad ep or descriptor\n", __func__);
return -EINVAL;
}
@@ -243,7 +243,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
if (ep->bmAttributes != desc->bmAttributes
&& ep->bmAttributes != USB_ENDPOINT_XFER_BULK
&& desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
- DMSG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
+ DMSG("%s, %s type mismatch\n", __func__, _ep->name);
return -EINVAL;
}
@@ -252,13 +252,13 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
&& le16_to_cpu (desc->wMaxPacketSize)
!= BULK_FIFO_SIZE)
|| !desc->wMaxPacketSize) {
- DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
+ DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
return -ERANGE;
}
dev = ep->dev;
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
- DMSG("%s, bogus device state\n", __FUNCTION__);
+ DMSG("%s, bogus device state\n", __func__);
return -ESHUTDOWN;
}
@@ -283,7 +283,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
ep = container_of (_ep, struct pxa2xx_ep, ep);
if (!_ep || !ep->desc) {
- DMSG("%s, %s not enabled\n", __FUNCTION__,
+ DMSG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -461,7 +461,7 @@ void ep0start(struct pxa2xx_udc *dev, u32 flags, const char *tag)
USIR0 = USIR0_IR0;
dev->req_pending = 0;
DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n",
- __FUNCTION__, tag, UDCCS0, flags);
+ __func__, tag, UDCCS0, flags);
}
static int
@@ -651,20 +651,20 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = container_of(_req, struct pxa2xx_request, req);
if (unlikely (!_req || !_req->complete || !_req->buf
|| !list_empty(&req->queue))) {
- DMSG("%s, bad params\n", __FUNCTION__);
+ DMSG("%s, bad params\n", __func__);
return -EINVAL;
}
ep = container_of(_ep, struct pxa2xx_ep, ep);
if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
- DMSG("%s, bad ep\n", __FUNCTION__);
+ DMSG("%s, bad ep\n", __func__);
return -EINVAL;
}
dev = ep->dev;
if (unlikely (!dev->driver
|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
- DMSG("%s, bogus device state\n", __FUNCTION__);
+ DMSG("%s, bogus device state\n", __func__);
return -ESHUTDOWN;
}
@@ -807,7 +807,7 @@ static int pxa2xx_ep_set_halt(struct usb_ep *_ep, int value)
if (unlikely (!_ep
|| (!ep->desc && ep->ep.name != ep0name))
|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
- DMSG("%s, bad ep\n", __FUNCTION__);
+ DMSG("%s, bad ep\n", __func__);
return -EINVAL;
}
if (value == 0) {
@@ -859,7 +859,7 @@ static int pxa2xx_ep_fifo_status(struct usb_ep *_ep)
ep = container_of(_ep, struct pxa2xx_ep, ep);
if (!_ep) {
- DMSG("%s, bad ep\n", __FUNCTION__);
+ DMSG("%s, bad ep\n", __func__);
return -ENODEV;
}
/* pxa can't report unclaimed bytes from IN fifos */
@@ -878,7 +878,7 @@ static void pxa2xx_ep_fifo_flush(struct usb_ep *_ep)
ep = container_of(_ep, struct pxa2xx_ep, ep);
if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) {
- DMSG("%s, bad ep\n", __FUNCTION__);
+ DMSG("%s, bad ep\n", __func__);
return;
}
@@ -1813,7 +1813,7 @@ pxa2xx_udc_irq(int irq, void *_dev)
static void nop_release (struct device *dev)
{
- DMSG("%s %s\n", __FUNCTION__, dev->bus_id);
+ DMSG("%s %s\n", __func__, dev->bus_id);
}
/* this uses load-time allocation and initialization (instead of
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 3d036647431f..bd58dd504f6f 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -204,7 +204,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
- DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
+ DBG("%s: OID_GEN_SUPPORTED_LIST\n", __func__);
length = sizeof (oid_supported_list);
count = length / sizeof (u32);
for (i = 0; i < count; i++)
@@ -214,7 +214,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
- DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_HARDWARE_STATUS\n", __func__);
/* Bogus question!
* Hardware must be ready to receive high level protocols.
* BTW:
@@ -227,14 +227,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
- DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
- DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_IN_USE\n", __func__);
/* one medium, one transport... (maybe you do it better) */
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
@@ -242,7 +242,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MAXIMUM_FRAME_SIZE:
- DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -253,7 +253,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_LINK_SPEED:
if (rndis_debug > 1)
- DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+ DBG("%s: OID_GEN_LINK_SPEED\n", __func__);
if (rndis_per_dev_params [configNr].media_state
== NDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = __constant_cpu_to_le32 (0);
@@ -265,7 +265,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
- DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -275,7 +275,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
- DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -285,7 +285,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_ID:
- DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_ID\n", __func__);
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].vendorID);
retval = 0;
@@ -293,7 +293,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_DESCRIPTION:
- DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
memcpy (outbuf,
rndis_per_dev_params [configNr].vendorDescr, length);
@@ -301,7 +301,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
- DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
/* Created as LE */
*outbuf = rndis_driver_version;
retval = 0;
@@ -309,14 +309,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
- DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
+ DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
- DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
@@ -324,14 +324,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
if (rndis_debug > 1)
- DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
- DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
+ DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -341,7 +341,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
* versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
*/
case OID_GEN_MAC_OPTIONS: /* from WinME */
- DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAC_OPTIONS\n", __func__);
*outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
@@ -353,7 +353,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_OK:
if (rndis_debug > 1)
- DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+ DBG("%s: OID_GEN_XMIT_OK\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->tx_packets -
@@ -366,7 +366,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_OK:
if (rndis_debug > 1)
- DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_OK\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->rx_packets -
@@ -379,7 +379,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_ERROR:
if (rndis_debug > 1)
- DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_XMIT_ERROR\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_errors);
@@ -390,7 +390,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_ERROR:
if (rndis_debug > 1)
- DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_ERROR\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_errors);
@@ -400,7 +400,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
- DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_dropped);
@@ -410,7 +410,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_OPTIONAL_STATS
case OID_GEN_DIRECTED_BYTES_XMIT:
- DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__);
/*
* Aunt Tilly's size of shoes
* minus antarctica count of penguins
@@ -430,7 +430,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_FRAMES_XMIT:
- DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__);
/* dito */
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
@@ -446,7 +446,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
- DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast*1234);
@@ -455,7 +455,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
- DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@@ -464,7 +464,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
- DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42*255);
@@ -473,7 +473,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
- DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42);
@@ -482,19 +482,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_BYTES_RCV:
- DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
- DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
- DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
@@ -503,7 +503,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
- DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@@ -512,7 +512,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_RCV:
- DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
@@ -521,7 +521,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
- DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
@@ -530,7 +530,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_RCV_CRC_ERROR:
- DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
@@ -539,7 +539,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
- DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
+ DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -549,7 +549,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_PERMANENT_ADDRESS:
- DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@@ -561,7 +561,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_CURRENT_ADDRESS:
- DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __func__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@@ -573,7 +573,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MULTICAST_LIST:
- DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MULTICAST_LIST\n", __func__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (0xE0000000);
retval = 0;
@@ -581,21 +581,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
- DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (1);
retval = 0;
break;
case OID_802_3_MAC_OPTIONS:
- DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MAC_OPTIONS\n", __func__);
break;
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
- DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
+ DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
@@ -605,51 +605,51 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
- DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
- DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
#ifdef RNDIS_OPTIONAL_STATS
case OID_802_3_XMIT_DEFERRED:
- DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_DEFERRED\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
- DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__);
/* TODO */
break;
case OID_802_3_RCV_OVERRUN:
- DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
+ DBG("%s: OID_802_3_RCV_OVERRUN\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_UNDERRUN:
- DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
- DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
- DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__);
/* TODO */
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
- DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__);
/* TODO */
break;
#endif /* RNDIS_OPTIONAL_STATS */
@@ -657,7 +657,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_PM
/* power management OIDs (table 4-5) */
case OID_PNP_CAPABILITIES:
- DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
+ DBG("%s: OID_PNP_CAPABILITIES\n", __func__);
/* for now, no wakeup capabilities */
length = sizeof (struct NDIS_PNP_CAPABILITIES);
@@ -665,7 +665,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
retval = 0;
break;
case OID_PNP_QUERY_POWER:
- DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+ DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
/* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
@@ -677,7 +677,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
default:
pr_warning("%s: query unknown OID 0x%08X\n",
- __FUNCTION__, OID);
+ __func__, OID);
}
if (retval < 0)
length = 0;
@@ -729,7 +729,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
*params->filter = (u16) le32_to_cpu(get_unaligned(
(__le32 *)buf));
DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
- __FUNCTION__, *params->filter);
+ __func__, *params->filter);
/* this call has a significant side effect: it's
* what makes the packet flow start and stop, like
@@ -753,7 +753,7 @@ update_linkstate:
case OID_802_3_MULTICAST_LIST:
/* I think we can ignore this */
- DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MULTICAST_LIST\n", __func__);
retval = 0;
break;
#if 0
@@ -762,7 +762,7 @@ update_linkstate:
struct rndis_config_parameter *param;
param = (struct rndis_config_parameter *) buf;
DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
- __FUNCTION__,
+ __func__,
min(cpu_to_le32(param->ParameterNameLength),80),
buf + param->ParameterNameOffset);
retval = 0;
@@ -778,7 +778,7 @@ update_linkstate:
* FIXME ... then things go batty; Windows wedges itself.
*/
i = le32_to_cpu(get_unaligned((__le32 *)buf));
- DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+ DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
switch (i) {
case NdisDeviceStateD0:
*params->filter = params->saved_filter;
@@ -802,7 +802,7 @@ update_linkstate:
default:
pr_warning("%s: set unknown OID 0x%08X, size %d\n",
- __FUNCTION__, OID, buf_len);
+ __func__, OID, buf_len);
}
return retval;
@@ -855,7 +855,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
- // DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
+ // DBG("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID));
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
/*
@@ -908,9 +908,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
#ifdef VERBOSE
- DBG("%s: Length: %d\n", __FUNCTION__, BufLength);
- DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
- DBG("%s: InfoBuffer: ", __FUNCTION__);
+ DBG("%s: Length: %d\n", __func__, BufLength);
+ DBG("%s: Offset: %d\n", __func__, BufOffset);
+ DBG("%s: InfoBuffer: ", __func__);
for (i = 0; i < BufLength; i++) {
DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
@@ -1080,14 +1080,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
switch (MsgType) {
case REMOTE_NDIS_INITIALIZE_MSG:
DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
- __FUNCTION__ );
+ __func__ );
params->state = RNDIS_INITIALIZED;
return rndis_init_response (configNr,
(rndis_init_msg_type *) buf);
case REMOTE_NDIS_HALT_MSG:
DBG("%s: REMOTE_NDIS_HALT_MSG\n",
- __FUNCTION__ );
+ __func__ );
params->state = RNDIS_UNINITIALIZED;
if (params->dev) {
netif_carrier_off (params->dev);
@@ -1105,7 +1105,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
case REMOTE_NDIS_RESET_MSG:
DBG("%s: REMOTE_NDIS_RESET_MSG\n",
- __FUNCTION__ );
+ __func__ );
return rndis_reset_response (configNr,
(rndis_reset_msg_type *) buf);
@@ -1113,7 +1113,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
/* For USB: host does this every 5 seconds */
if (rndis_debug > 1)
DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
- __FUNCTION__ );
+ __func__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
buf);
@@ -1124,7 +1124,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
* suspending itself.
*/
pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
- __FUNCTION__ , MsgType, MsgLength);
+ __func__ , MsgType, MsgLength);
{
unsigned i;
for (i = 0; i < MsgLength; i += 16) {
@@ -1159,7 +1159,7 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *))
if (!rndis_per_dev_params [i].used) {
rndis_per_dev_params [i].used = 1;
rndis_per_dev_params [i].ack = rndis_control_ack;
- DBG("%s: configNr = %d\n", __FUNCTION__, i);
+ DBG("%s: configNr = %d\n", __func__, i);
return i;
}
}
@@ -1170,7 +1170,7 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *))
void rndis_deregister (int configNr)
{
- DBG("%s: \n", __FUNCTION__ );
+ DBG("%s: \n", __func__ );
if (configNr >= RNDIS_MAX_CONFIGS) return;
rndis_per_dev_params [configNr].used = 0;
@@ -1182,7 +1182,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
struct net_device_stats *stats,
u16 *cdc_filter)
{
- DBG("%s:\n", __FUNCTION__ );
+ DBG("%s:\n", __func__ );
if (!dev || !stats) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@@ -1195,7 +1195,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
{
- DBG("%s:\n", __FUNCTION__ );
+ DBG("%s:\n", __func__ );
if (!vendorDescr) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@@ -1207,7 +1207,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
- DBG("%s: %u %u\n", __FUNCTION__, medium, speed);
+ DBG("%s: %u %u\n", __func__, medium, speed);
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
rndis_per_dev_params [configNr].medium = medium;
@@ -1403,7 +1403,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-int __devinit rndis_init (void)
+int __init rndis_init (void)
{
u8 i;
@@ -1415,7 +1415,7 @@ int __devinit rndis_init (void)
if (!(rndis_connect_state [i]
= create_proc_entry (name, 0660, NULL)))
{
- DBG("%s :remove entries", __FUNCTION__);
+ DBG("%s :remove entries", __func__);
while (i) {
sprintf (name, NAME_TEMPLATE, --i);
remove_proc_entry (name, NULL);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f5c3896b1d95..433b3f44f42e 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -2163,8 +2163,7 @@ static void gs_free_ports(struct gs_dev *dev)
port->port_dev = NULL;
wake_up_interruptible(&port->port_write_wait);
if (port->port_tty) {
- wake_up_interruptible(&port->port_tty->read_wait);
- wake_up_interruptible(&port->port_tty->write_wait);
+ tty_hangup(port->port_tty);
}
spin_unlock_irqrestore(&port->port_lock, flags);
} else {
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index bf8be2a41a4a..0b87480dd713 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -30,8 +30,8 @@ config USB_EHCI_HCD
module will be called ehci-hcd.
config USB_EHCI_ROOT_HUB_TT
- bool "Root Hub Transaction Translators (EXPERIMENTAL)"
- depends on USB_EHCI_HCD && EXPERIMENTAL
+ bool "Root Hub Transaction Translators"
+ depends on USB_EHCI_HCD
---help---
Some EHCI chips have vendor-specific extensions to integrate
transaction translators, so that no OHCI or UHCI companion
@@ -260,3 +260,9 @@ config USB_R8A66597_HCD
To compile this driver as a module, choose M here: the
module will be called r8a66597-hcd.
+config SUPERH_ON_CHIP_R8A66597
+ boolean "Enable SuperH on-chip USB like the R8A66597"
+ depends on USB_R8A66597_HCD && CPU_SUBTYPE_SH7366
+ help
+ Renesas SuperH processor has USB like the R8A66597.
+ This driver supported processor is SH7366.
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index da7532d38bf1..8b5f991e949c 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -237,6 +237,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
if (usb_disabled())
return -ENODEV;
+ /* FIXME we only want one one probe() not two */
ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
return ret;
}
@@ -245,6 +246,7 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ /* FIXME we only want one one remove() not two */
usb_ehci_au1xxx_remove(hcd, pdev);
return 0;
}
@@ -265,7 +267,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
return 0;
}
*/
-MODULE_ALIAS("au1xxx-ehci");
+MODULE_ALIAS("platform:au1xxx-ehci");
static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
@@ -274,6 +276,5 @@ static struct platform_driver ehci_hcd_au1xxx_driver = {
/*.resume = ehci_hcd_au1xxx_drv_resume, */
.driver = {
.name = "au1xxx-ehci",
- .bus = &platform_bus_type
}
};
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 64ebfc5548a3..0f82fdcaef09 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -27,7 +27,7 @@
#define ehci_warn(ehci, fmt, args...) \
dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#ifdef EHCI_VERBOSE_DEBUG
+#ifdef VERBOSE_DEBUG
# define vdbg dbg
# define ehci_vdbg ehci_dbg
#else
@@ -398,7 +398,7 @@ static void qh_lines (
unsigned size = *sizep;
char *next = *nextp;
char mark;
- u32 list_end = EHCI_LIST_END(ehci);
+ __le32 list_end = EHCI_LIST_END(ehci);
if (qh->hw_qtd_next == list_end) /* NEC does this */
mark = '@';
@@ -670,7 +670,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
spin_lock_irqsave (&ehci->lock, flags);
- if (buf->bus->controller->power.power_state.event) {
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
size = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index adb0defa1631..6d9bed6c1f48 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,5 +1,4 @@
/*
- * (C) Copyright David Brownell 2000-2002
* Copyright (c) 2005 MontaVista Software
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,7 +27,6 @@
/* FIXME: Power Management is un-ported so temporarily disable it */
#undef CONFIG_PM
-/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -331,6 +329,7 @@ static int ehci_fsl_drv_probe(struct platform_device *pdev)
if (usb_disabled())
return -ENODEV;
+ /* FIXME we only want one one probe() not two */
return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
}
@@ -338,12 +337,12 @@ static int ehci_fsl_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ /* FIXME we only want one one remove() not two */
usb_hcd_fsl_remove(hcd, pdev);
-
return 0;
}
-MODULE_ALIAS("fsl-ehci");
+MODULE_ALIAS("platform:fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
.probe = ehci_fsl_drv_probe,
@@ -351,5 +350,5 @@ static struct platform_driver ehci_fsl_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
- },
+ },
};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 85074cb36f38..369a8a5ea7bb 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -57,35 +57,6 @@
* Special thanks to Intel and VIA for providing host controllers to
* test this driver on, and Cypress (including In-System Design) for
* providing early devices for those host controllers to talk to!
- *
- * HISTORY:
- *
- * 2004-05-10 Root hub and PCI suspend/resume support; remote wakeup. (db)
- * 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net)
- * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
- * <sojkam@centrum.cz>, updates by DB).
- *
- * 2002-11-29 Correct handling for hw async_next register.
- * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared;
- * only scheduling is different, no arbitrary limitations.
- * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support,
- * clean up HC run state handshaking.
- * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts
- * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other
- * missing pieces: enabling 64bit dma, handoff from BIOS/SMM.
- * 2002-05-07 Some error path cleanups to report better errors; wmb();
- * use non-CVS version id; better iso bandwidth claim.
- * 2002-04-19 Control/bulk/interrupt submit no longer uses giveback() on
- * errors in submit path. Bugfixes to interrupt scheduling/processing.
- * 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift
- * more checking to generic hcd framework (db). Make it work with
- * Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
- * 2002-01-14 Minor cleanup; version synch.
- * 2002-01-08 Fix roothub handoff of FS/LS to companion controllers.
- * 2002-01-04 Control/Bulk queuing behaves.
- *
- * 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
- * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "10 Dec 2004"
@@ -95,7 +66,7 @@
static const char hcd_name [] = "ehci_hcd";
-#undef EHCI_VERBOSE_DEBUG
+#undef VERBOSE_DEBUG
#undef EHCI_URB_TRACE
#ifdef DEBUG
@@ -174,6 +145,16 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
return -ETIMEDOUT;
}
+static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ int error = handshake(ehci, ptr, mask, done, usec);
+ if (error)
+ ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+
+ return error;
+}
+
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
@@ -246,11 +227,9 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
/* wait for any schedule enables/disables to take effect */
temp = ehci_readl(ehci, &ehci->regs->command) << 10;
temp &= STS_ASS | STS_PSS;
- if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
- temp, 16 * 125) != 0) {
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+ if (handshake_on_error_set_halt(ehci, &ehci->regs->status,
+ STS_ASS | STS_PSS, temp, 16 * 125))
return;
- }
/* then disable anything that's still active */
temp = ehci_readl(ehci, &ehci->regs->command);
@@ -258,11 +237,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
ehci_writel(ehci, temp, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
- if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
- 0, 16 * 125) != 0) {
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
- return;
- }
+ handshake_on_error_set_halt(ehci, &ehci->regs->status,
+ STS_ASS | STS_PSS, 0, 16 * 125);
}
/*-------------------------------------------------------------------------*/
@@ -355,17 +331,13 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
&ehci->regs->port_status[port]);
}
-/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
- * This forcibly disables dma and IRQs, helping kexec and other cases
- * where the next system software may expect clean state.
+/*
+ * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
+ * Should be called with ehci->lock held.
*/
-static void
-ehci_shutdown (struct usb_hcd *hcd)
+static void ehci_silence_controller(struct ehci_hcd *ehci)
{
- struct ehci_hcd *ehci;
-
- ehci = hcd_to_ehci (hcd);
- (void) ehci_halt (ehci);
+ ehci_halt(ehci);
ehci_turn_off_all_ports(ehci);
/* make BIOS/etc use companion controller during reboot */
@@ -375,6 +347,22 @@ ehci_shutdown (struct usb_hcd *hcd)
ehci_readl(ehci, &ehci->regs->configured_flag);
}
+/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
+ */
+static void ehci_shutdown(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ del_timer_sync(&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);
+
+ spin_lock_irq(&ehci->lock);
+ ehci_silence_controller(ehci);
+ spin_unlock_irq(&ehci->lock);
+}
+
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
{
unsigned port;
@@ -425,15 +413,15 @@ static void ehci_work (struct ehci_hcd *ehci)
timer_action (ehci, TIMER_IO_WATCHDOG);
}
+/*
+ * Called when the ehci_hcd module is removed.
+ */
static void ehci_stop (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
ehci_dbg (ehci, "stop\n");
- /* Turn off port power on all root hub ports. */
- ehci_port_power (ehci, 0);
-
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
del_timer_sync(&ehci->iaa_watchdog);
@@ -442,13 +430,10 @@ static void ehci_stop (struct usb_hcd *hcd)
if (HC_IS_RUNNING (hcd->state))
ehci_quiesce (ehci);
+ ehci_silence_controller(ehci);
ehci_reset (ehci);
- ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
- /* let companion controllers work when we aren't */
- ehci_writel(ehci, 0, &ehci->regs->configured_flag);
-
remove_companion_file(ehci);
remove_debug_files (ehci);
@@ -676,7 +661,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
cmd = ehci_readl(ehci, &ehci->regs->command);
bh = 0;
-#ifdef EHCI_VERBOSE_DEBUG
+#ifdef VERBOSE_DEBUG
/* unrequested/ignored: Frame List Rollover */
dbg_status (ehci, "irq", status);
#endif
@@ -710,6 +695,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
+
+ /* kick root hub later */
pcd_status = status;
/* resume root hub? */
@@ -738,8 +725,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
- /* bogus "fatal" IRQs appear on some chips... why? */
- status = ehci_readl(ehci, &ehci->regs->status);
dbg_cmd (ehci, "fatal", ehci_readl(ehci,
&ehci->regs->command));
dbg_status (ehci, "fatal", status);
@@ -758,7 +743,7 @@ dead:
if (bh)
ehci_work (ehci);
spin_unlock (&ehci->lock);
- if (pcd_status & STS_PCD)
+ if (pcd_status)
usb_hcd_poll_rh_status(hcd);
return IRQ_HANDLED;
}
@@ -788,8 +773,14 @@ static int ehci_urb_enqueue (
INIT_LIST_HEAD (&qtd_list);
switch (usb_pipetype (urb->pipe)) {
- // case PIPE_CONTROL:
- // case PIPE_BULK:
+ case PIPE_CONTROL:
+ /* qh_completions() code doesn't handle all the fault cases
+ * in multi-TD control transfers. Even 1KB is rare anyway.
+ */
+ if (urb->transfer_buffer_length > (16 * 1024))
+ return -EMSGSIZE;
+ /* FALLTHROUGH */
+ /* case PIPE_BULK: */
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 4e065e556e4b..f13d1029aeb2 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -28,7 +28,9 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_PERSIST
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+#ifdef CONFIG_PM
static int ehci_hub_control(
struct usb_hcd *hcd,
@@ -104,15 +106,6 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
ehci->owned_ports = 0;
}
-#else /* CONFIG_USB_PERSIST */
-
-static inline void ehci_handover_companion_ports(struct ehci_hcd *ehci)
-{ }
-
-#endif
-
-#ifdef CONFIG_PM
-
static int ehci_bus_suspend (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
@@ -158,10 +151,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
/* enable remote wakeup on all ports */
- if (device_may_wakeup(&hcd->self.root_hub->dev))
- t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
+ if (hcd->self.root_hub->do_remote_wakeup)
+ t2 |= PORT_WAKE_BITS;
else
- t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+ t2 &= ~PORT_WAKE_BITS;
if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
@@ -183,7 +176,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
/* allow remote wakeup */
mask = INTR_MASK;
- if (!device_may_wakeup(&hcd->self.root_hub->dev))
+ if (!hcd->self.root_hub->do_remote_wakeup)
mask &= ~STS_PCD;
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
ehci_readl(ehci, &ehci->regs->intr_enable);
@@ -241,8 +234,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
- temp &= ~(PORT_RWC_BITS
- | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
+ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
@@ -281,9 +273,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
spin_unlock_irq (&ehci->lock);
-
- if (!power_okay)
- ehci_handover_companion_ports(ehci);
+ ehci_handover_companion_ports(ehci);
return 0;
}
@@ -540,13 +530,11 @@ ehci_hub_descriptor (
if (HCS_INDICATOR (ehci->hcs_params))
temp |= 0x0080; /* per-port indicators (LEDs) */
#endif
- desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp);
+ desc->wHubCharacteristics = cpu_to_le16(temp);
}
/*-------------------------------------------------------------------------*/
-#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-
static int ehci_hub_control (
struct usb_hcd *hcd,
u16 typeReq,
@@ -778,7 +766,7 @@ static int ehci_hub_control (
if (temp & PORT_POWER)
status |= 1 << USB_PORT_FEAT_POWER;
-#ifndef EHCI_VERBOSE_DEBUG
+#ifndef VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */
#endif
dbg_port (ehci, "GetStatus", wIndex + 1, temp);
@@ -812,8 +800,6 @@ static int ehci_hub_control (
if ((temp & PORT_PE) == 0
|| (temp & PORT_RESET) != 0)
goto error;
- if (device_may_wakeup(&hcd->self.root_hub->dev))
- temp |= PORT_WAKE_BITS;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
break;
case USB_PORT_FEAT_POWER:
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index 3041d8f055f4..601c8795a854 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -140,13 +140,12 @@ static int ixp4xx_ehci_remove(struct platform_device *pdev)
return 0;
}
-MODULE_ALIAS("ixp4xx-ehci");
+MODULE_ALIAS("platform:ixp4xx-ehci");
static struct platform_driver ixp4xx_ehci_driver = {
.probe = ixp4xx_ehci_probe,
.remove = ixp4xx_ehci_remove,
.driver = {
.name = "ixp4xx-ehci",
- .bus = &platform_bus_type
},
};
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 72ccd56e36dd..5bb7f6bb13f3 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -130,6 +130,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
ehci->is_tdi_rh_tt = 1;
+ hcd->has_tt = 1;
tdi_reset(ehci);
}
break;
@@ -221,6 +222,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
#endif
+ ehci_port_power(ehci, 1);
retval = ehci_pci_reinit(ehci, pdev);
done:
return retval;
@@ -299,7 +301,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK;
- if (!device_may_wakeup(&hcd->self.root_hub->dev))
+ if (!hcd->self.root_hub->do_remote_wakeup)
mask &= ~STS_PCD;
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
ehci_readl(ehci, &ehci->regs->intr_enable);
@@ -329,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- ehci_handover_companion_ports(ehci);
hcd->state = HC_STATE_SUSPENDED;
return 0;
@@ -353,8 +354,8 @@ static const struct hc_driver ehci_pci_hc_driver = {
.reset = ehci_pci_setup,
.start = ehci_run,
#ifdef CONFIG_PM
- .suspend = ehci_pci_suspend,
- .resume = ehci_pci_resume,
+ .pci_suspend = ehci_pci_suspend,
+ .pci_resume = ehci_pci_resume,
#endif
.stop = ehci_stop,
.shutdown = ehci_shutdown,
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index a3249078c808..6c76036783a1 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -175,6 +175,7 @@ static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
if (usb_disabled())
return -ENODEV;
+ /* FIXME we only want one one probe() not two */
ret = usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver, &hcd, pdev);
return ret;
}
@@ -183,17 +184,17 @@ static int ehci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ /* FIXME we only want one one remove() not two */
usb_ehci_ppc_soc_remove(hcd, pdev);
return 0;
}
-MODULE_ALIAS("ppc-soc-ehci");
+MODULE_ALIAS("platform:ppc-soc-ehci");
static struct platform_driver ehci_ppc_soc_driver = {
.probe = ehci_hcd_ppc_soc_drv_probe,
.remove = ehci_hcd_ppc_soc_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-soc-ehci",
- .bus = &platform_bus_type
}
};
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index bbda58eb8813..69782221bcf3 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -125,7 +125,6 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
goto fail_irq;
}
- dev->core.power.power_state = PMSG_ON;
dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 2e49de820b14..b85b54160cda 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -242,7 +242,8 @@ __acquires(ehci->lock)
if (unlikely(urb->unlinked)) {
COUNT(ehci->stats.unlink);
} else {
- if (likely(status == -EINPROGRESS))
+ /* report non-error and short read status as zero */
+ if (status == -EINPROGRESS || status == -EREMOTEIO)
status = 0;
COUNT(ehci->stats.complete);
}
@@ -250,7 +251,7 @@ __acquires(ehci->lock)
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
"%s %s urb %p ep%d%s status %d len %d/%d\n",
- __FUNCTION__, urb->dev->devpath, urb,
+ __func__, urb->dev->devpath, urb,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
status,
@@ -283,9 +284,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
int last_status = -EINPROGRESS;
int stopped;
unsigned count = 0;
- int do_status = 0;
u8 state;
- u32 halt = HALT_BIT(ehci);
+ __le32 halt = HALT_BIT(ehci);
if (unlikely (list_empty (&qh->qtd_list)))
return count;
@@ -309,7 +309,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct ehci_qtd *qtd;
struct urb *urb;
u32 token = 0;
- int qtd_status;
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@@ -336,11 +335,20 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* always clean up qtds the hc de-activated */
if ((token & QTD_STS_ACTIVE) == 0) {
+ /* on STALL, error, and short reads this urb must
+ * complete and all its qtds must be recycled.
+ */
if ((token & QTD_STS_HALT) != 0) {
stopped = 1;
/* magic dummy for some short reads; qh won't advance.
* that silicon quirk can kick in with this dummy too.
+ *
+ * other short reads won't stop the queue, including
+ * control transfers (status stage handles that) or
+ * most other single-qtd reads ... the queue stops if
+ * URB_SHORT_NOT_OK was set so the driver submitting
+ * the urbs could clean it up.
*/
} else if (IS_SHORT_READ (token)
&& !(qtd->hw_alt_next
@@ -354,28 +362,21 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
break;
+ /* scan the whole queue for unlinks whenever it stops */
} else {
stopped = 1;
- if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
+ /* cancel everything if we halt, suspend, etc */
+ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
last_status = -ESHUTDOWN;
- /* ignore active urbs unless some previous qtd
- * for the urb faulted (including short read) or
- * its urb was canceled. we may patch qh or qtds.
+ /* this qtd is active; skip it unless a previous qtd
+ * for its urb faulted, or its urb was canceled.
*/
- if (likely(last_status == -EINPROGRESS &&
- !urb->unlinked))
- continue;
-
- /* issue status after short control reads */
- if (unlikely (do_status != 0)
- && QTD_PID (token) == 0 /* OUT */) {
- do_status = 0;
+ else if (last_status == -EINPROGRESS && !urb->unlinked)
continue;
- }
- /* token in overlay may be most current */
+ /* qh unlinked; token in overlay may be most current */
if (state == QH_STATE_IDLE
&& cpu_to_hc32(ehci, qtd->qtd_dma)
== qh->hw_current)
@@ -392,21 +393,32 @@ halt:
}
}
- /* remove it from the queue */
- qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
- if (unlikely(qtd_status == -EREMOTEIO)) {
- do_status = (!urb->unlinked &&
- usb_pipecontrol(urb->pipe));
- qtd_status = 0;
+ /* unless we already know the urb's status, collect qtd status
+ * and update count of bytes transferred. in common short read
+ * cases with only one data qtd (including control transfers),
+ * queue processing won't halt. but with two or more qtds (for
+ * example, with a 32 KB transfer), when the first qtd gets a
+ * short read the second must be removed by hand.
+ */
+ if (last_status == -EINPROGRESS) {
+ last_status = qtd_copy_status(ehci, urb,
+ qtd->length, token);
+ if (last_status == -EREMOTEIO
+ && (qtd->hw_alt_next
+ & EHCI_LIST_END(ehci)))
+ last_status = -EINPROGRESS;
}
- if (likely(last_status == -EINPROGRESS))
- last_status = qtd_status;
+ /* if we're removing something not at the queue head,
+ * patch the hardware queue pointer.
+ */
if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
last = list_entry (qtd->qtd_list.prev,
struct ehci_qtd, qtd_list);
last->hw_next = qtd->hw_next;
}
+
+ /* remove qtd; it's recycled after possible urb completion */
list_del (&qtd->qtd_list);
last = qtd;
}
@@ -431,7 +443,15 @@ halt:
qh_refresh(ehci, qh);
break;
case QH_STATE_LINKED:
- /* should be rare for periodic transfers,
+ /* We won't refresh a QH that's linked (after the HC
+ * stopped the queue). That avoids a race:
+ * - HC reads first part of QH;
+ * - CPU updates that first part and the token;
+ * - HC reads rest of that QH, including token
+ * Result: HC gets an inconsistent image, and then
+ * DMAs to/from the wrong memory (corrupting it).
+ *
+ * That should be rare for interrupt transfers,
* except maybe high bandwidth ...
*/
if ((cpu_to_hc32(ehci, QH_SMASK)
@@ -549,6 +569,12 @@ qh_urb_transaction (
this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket);
len -= this_qtd_len;
buf += this_qtd_len;
+
+ /*
+ * short reads advance to a "magic" dummy instead of the next
+ * qtd ... that forces the queue to stop, for manual cleanup.
+ * (this will usually be overridden later.)
+ */
if (is_input)
qtd->hw_alt_next = ehci->async->hw_alt_next;
@@ -568,8 +594,10 @@ qh_urb_transaction (
list_add_tail (&qtd->qtd_list, head);
}
- /* unless the bulk/interrupt caller wants a chance to clean
- * up after short reads, hc should advance qh past this urb
+ /*
+ * unless the caller requires manual cleanup after short reads,
+ * have the alt_next mechanism keep the queue running after the
+ * last data qtd (the only one, for control and most other cases).
*/
if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
|| usb_pipecontrol (urb->pipe)))
@@ -657,6 +685,14 @@ qh_make (
type = usb_pipetype (urb->pipe);
maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+ /* 1024 byte maxpacket is a hardware ceiling. High bandwidth
+ * acts like up to 3KB, but is built from smaller packets.
+ */
+ if (max_packet(maxp) > 1024) {
+ ehci_dbg(ehci, "bogus qh maxpacket %d\n", max_packet(maxp));
+ goto done;
+ }
+
/* Compute interrupt scheduling parameters just once, and save.
* - allowing for high bandwidth, how many nsec/uframe are used?
* - split transactions need a second CSPLIT uframe; same question
@@ -757,7 +793,13 @@ qh_make (
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (type == PIPE_BULK) {
info1 |= (EHCI_TUNE_RL_HS << 28);
- info1 |= 512 << 16; /* usb2 fixed maxpacket */
+ /* The USB spec says that high speed bulk endpoints
+ * always use 512 byte maxpacket. But some device
+ * vendors decided to ignore that, and MSFT is happy
+ * to help them do so. So now people expect to use
+ * such nonconformant devices with Linux too; sigh.
+ */
+ info1 |= max_packet(maxp) << 16;
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else { /* PIPE_INTERRUPT */
info1 |= max_packet (maxp) << 16;
@@ -841,7 +883,7 @@ static struct ehci_qh *qh_append_tds (
)
{
struct ehci_qh *qh = NULL;
- u32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f);
+ __hc32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f);
qh = (struct ehci_qh *) *ptr;
if (unlikely (qh == NULL)) {
@@ -932,7 +974,7 @@ submit_async (
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
- __FUNCTION__, urb->dev->devpath, urb,
+ __func__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
qtd, urb->ep->hcpriv);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 8a8e08a51ba3..be575e46eac3 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -440,11 +440,10 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* did clearing PSE did take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
- if (status != 0) {
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+ status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
+ STS_PSS, 0, 9 * 125);
+ if (status)
return status;
- }
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
@@ -465,11 +464,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
- if (status != 0) {
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+ status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
+ STS_PSS, STS_PSS, 9 * 125);
+ if (status)
return status;
- }
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
@@ -1183,21 +1181,18 @@ itd_urb_transaction (
struct ehci_itd, itd_list);
list_del (&itd->itd_list);
itd_dma = itd->itd_dma;
- } else
- itd = NULL;
-
- if (!itd) {
+ } else {
spin_unlock_irqrestore (&ehci->lock, flags);
itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
&itd_dma);
spin_lock_irqsave (&ehci->lock, flags);
+ if (!itd) {
+ iso_sched_free(stream, sched);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ return -ENOMEM;
+ }
}
- if (unlikely (NULL == itd)) {
- iso_sched_free (stream, sched);
- spin_unlock_irqrestore (&ehci->lock, flags);
- return -ENOMEM;
- }
memset (itd, 0, sizeof *itd);
itd->itd_dma = itd_dma;
list_add (&itd->itd_list, &sched->td_list);
@@ -1682,7 +1677,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
"%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n",
- __FUNCTION__, urb->dev->devpath, urb,
+ __func__, urb->dev->devpath, urb,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
urb->transfer_buffer_length,
@@ -1816,21 +1811,18 @@ sitd_urb_transaction (
struct ehci_sitd, sitd_list);
list_del (&sitd->sitd_list);
sitd_dma = sitd->sitd_dma;
- } else
- sitd = NULL;
-
- if (!sitd) {
+ } else {
spin_unlock_irqrestore (&ehci->lock, flags);
sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
&sitd_dma);
spin_lock_irqsave (&ehci->lock, flags);
+ if (!sitd) {
+ iso_sched_free(stream, iso_sched);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ return -ENOMEM;
+ }
}
- if (!sitd) {
- iso_sched_free (stream, iso_sched);
- spin_unlock_irqrestore (&ehci->lock, flags);
- return -ENOMEM;
- }
memset (sitd, 0, sizeof *sitd);
sitd->sitd_dma = sitd_dma;
list_add (&sitd->sitd_list, &iso_sched->td_list);
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 203a3359a648..20b9a0d07420 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1400,7 +1400,7 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd)
spin_unlock_irqrestore(&isp116x->lock, flags);
val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
val |= HCCONTROL_USB_SUSPEND;
- if (device_may_wakeup(&hcd->self.root_hub->dev))
+ if (hcd->self.root_hub->do_remote_wakeup)
val |= HCCONTROL_RWE;
/* Wait for usb transfers to finish */
msleep(2);
@@ -1442,11 +1442,6 @@ static int isp116x_bus_resume(struct usb_hcd *hcd)
break;
case HCCONTROL_USB_OPER:
spin_unlock_irq(&isp116x->lock);
- /* Without setting power_state here the
- SUSPENDED state won't be removed from
- sysfs/usbN/power.state as a response to remote
- wakeup. Maybe in the future. */
- hcd->self.root_hub->dev.power.power_state = PMSG_ON;
return 0;
default:
/* HCCONTROL_USB_RESET: this may happen, when during
@@ -1460,7 +1455,6 @@ static int isp116x_bus_resume(struct usb_hcd *hcd)
if ((isp116x->rhdesca & RH_A_NDP) == 2)
isp116x_hub_control(hcd, SetPortFeature,
USB_PORT_FEAT_POWER, 2, NULL, 0);
- hcd->self.root_hub->dev.power.power_state = PMSG_ON;
return 0;
}
@@ -1486,8 +1480,6 @@ static int isp116x_bus_resume(struct usb_hcd *hcd)
isp116x_write_reg32(isp116x, HCCONTROL,
(val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);
spin_unlock_irq(&isp116x->lock);
- /* see analogous comment above */
- hcd->self.root_hub->dev.power.power_state = PMSG_ON;
hcd->state = HC_STATE_RUNNING;
return 0;
@@ -1663,7 +1655,6 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
static int isp116x_suspend(struct platform_device *dev, pm_message_t state)
{
VDBG("%s: state %x\n", __func__, state.event);
- dev->dev.power.power_state = state;
return 0;
}
@@ -1672,8 +1663,7 @@ static int isp116x_suspend(struct platform_device *dev, pm_message_t state)
*/
static int isp116x_resume(struct platform_device *dev)
{
- VDBG("%s: state %x\n", __func__, dev->power.power_state.event);
- dev->dev.power.power_state = PMSG_ON;
+ VDBG("%s\n", __func__);
return 0;
}
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index d72dc07dda01..c96db1153dcf 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -261,7 +261,6 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -348,6 +347,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
if (!clocked)
at91_start_clock();
+ ohci_finish_controller_resume(hcd);
return 0;
}
#else
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index f90fe0c7373f..1b9abdba920b 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -288,7 +288,6 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index a22c30aa745d..e06bfaebec54 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -655,7 +655,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
hcd->product_desc,
hcd_name);
- if (bus->controller->power.power_state.event) {
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
size -= scnprintf (next, size,
"SUSPENDED (no register access)\n");
goto done;
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 156e93a9d0df..06aadfb0ec29 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -135,7 +135,6 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -177,7 +176,6 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_
ep93xx_stop_hc(&pdev->dev);
hcd->state = HC_STATE_SUSPENDED;
- pdev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
@@ -193,9 +191,8 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
ohci->next_statechange = jiffies;
ep93xx_start_hc(&pdev->dev);
- pdev->dev.power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(hcd);
+ ohci_finish_controller_resume(hcd);
return 0;
}
#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 48e4b11f4d3e..5be3bb3e6a9d 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,18 +36,6 @@
/*-------------------------------------------------------------------------*/
-/* hcd->hub_irq_enable() */
-static void ohci_rhsc_enable (struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-
- spin_lock_irq(&ohci->lock);
- if (!ohci->autostop)
- del_timer(&hcd->rh_timer); /* Prevent next poll */
- ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
- spin_unlock_irq(&ohci->lock);
-}
-
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
@@ -103,11 +91,11 @@ __acquires(ohci->lock)
finish_unlinks (ohci, ohci_frame_no(ohci));
/* maybe resume can wake root hub */
- if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) ||
- autostop)
+ if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {
ohci->hc_control |= OHCI_CTRL_RWE;
- else {
- ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
+ } else {
+ ohci_writel(ohci, OHCI_INTR_RHSC | OHCI_INTR_RD,
+ &ohci->regs->intrdisable);
ohci->hc_control &= ~OHCI_CTRL_RWE;
}
@@ -326,23 +314,76 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
return rc;
}
+/* Carry out the final steps of resuming the controller device */
+static void ohci_finish_controller_resume(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int port;
+ bool need_reinit = false;
+
+ /* See if the controller is already running or has been reset */
+ ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
+ if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
+ need_reinit = true;
+ } else {
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ case OHCI_USB_RESET:
+ need_reinit = true;
+ }
+ }
+
+ /* If needed, reinitialize and suspend the root hub */
+ if (need_reinit) {
+ spin_lock_irq(&ohci->lock);
+ hcd->state = HC_STATE_RESUMING;
+ ohci_rh_resume(ohci);
+ hcd->state = HC_STATE_QUIESCING;
+ ohci_rh_suspend(ohci, 0);
+ hcd->state = HC_STATE_SUSPENDED;
+ spin_unlock_irq(&ohci->lock);
+ }
+
+ /* Normally just turn on port power and enable interrupts */
+ else {
+ ohci_dbg(ohci, "powerup ports\n");
+ for (port = 0; port < ohci->num_ports; port++)
+ ohci_writel(ohci, RH_PS_PPS,
+ &ohci->regs->roothub.portstatus[port]);
+
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable);
+ ohci_readl(ohci, &ohci->regs->intrenable);
+ msleep(20);
+ }
+}
+
/* Carry out polling-, autostop-, and autoresume-related state changes */
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
int poll_rh = 1;
+ int rhsc;
+ rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_OPER:
- /* keep on polling until we know a device is connected
- * and RHSC is enabled */
+ /* If no status changes are pending, enable status-change
+ * interrupts.
+ */
+ if (!rhsc && !changed) {
+ rhsc = OHCI_INTR_RHSC;
+ ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
+ }
+
+ /* Keep on polling until we know a device is connected
+ * and RHSC is enabled, or until we autostop.
+ */
if (!ohci->autostop) {
if (any_connected ||
!device_may_wakeup(&ohci_to_hcd(ohci)
->self.root_hub->dev)) {
- if (ohci_readl(ohci, &ohci->regs->intrenable) &
- OHCI_INTR_RHSC)
+ if (rhsc)
poll_rh = 0;
} else {
ohci->autostop = 1;
@@ -355,12 +396,13 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
ohci->autostop = 0;
ohci->next_statechange = jiffies +
STATECHANGE_DELAY;
- } else if (time_after_eq(jiffies,
+ } else if (rhsc && time_after_eq(jiffies,
ohci->next_statechange)
&& !ohci->ed_rm_list
&& !(ohci->hc_control &
OHCI_SCHED_ENABLES)) {
ohci_rh_suspend(ohci, 1);
+ poll_rh = 0;
}
}
break;
@@ -374,6 +416,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
else
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
} else {
+ if (!rhsc && (ohci->autostop ||
+ ohci_to_hcd(ohci)->self.root_hub->
+ do_remote_wakeup))
+ ohci_writel(ohci, OHCI_INTR_RHSC,
+ &ohci->regs->intrenable);
+
/* everything is idle, no need for polling */
poll_rh = 0;
}
@@ -395,12 +443,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
- int poll_rh = 1;
-
- /* keep on polling until RHSC is enabled */
+ /* If RHSC is enabled, don't poll */
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
- poll_rh = 0;
- return poll_rh;
+ return 0;
+
+ /* If no status changes are pending, enable status-change interrupts */
+ if (!changed) {
+ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+ return 0;
+ }
+ return 1;
}
#endif /* CONFIG_PM */
@@ -564,14 +616,18 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
u32 temp;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
+ int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
/* build a "continuous enough" reset signal, with up to
* 3msec gap between pulses. scheduler HZ==100 must work;
* this might need to be deadline-scheduled.
*/
do {
+ int limit_2;
+
/* spin until any current reset finishes */
- for (;;) {
+ limit_2 = PORT_RESET_HW_MSEC * 2;
+ while (--limit_2 >= 0) {
temp = ohci_readl (ohci, portstat);
/* handle e.g. CardBus eject */
if (temp == ~(u32)0)
@@ -581,6 +637,17 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
udelay (500);
}
+ /* timeout (a hardware error) has been observed when
+ * EHCI sets CF while this driver is resetting a port;
+ * presumably other disconnect paths might do it too.
+ */
+ if (limit_2 < 0) {
+ ohci_dbg(ohci,
+ "port[%d] reset timeout, stat %08x\n",
+ port, temp);
+ break;
+ }
+
if (!(temp & RH_PS_CCS))
break;
if (temp & RH_PS_PRSC)
@@ -590,8 +657,11 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
ohci_writel (ohci, RH_PS_PRS, portstat);
msleep(PORT_RESET_HW_MSEC);
now = ohci_readl(ohci, &ohci->regs->fmnumber);
- } while (tick_before(now, reset_done));
- /* caller synchronizes using PRSC */
+ } while (tick_before(now, reset_done) && --limit_1 >= 0);
+
+ /* caller synchronizes using PRSC ... and handles PRS
+ * still being set when this returns.
+ */
return 0;
}
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 13c12ed22252..96d14fa1d833 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -193,7 +193,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 7bfca1ed1b58..6859fb5f1d6f 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -466,7 +466,6 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -505,21 +504,20 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
- dev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
static int ohci_omap_resume(struct platform_device *dev)
{
- struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev));
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
omap_ohci_clock_power(1);
- dev->dev.power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(platform_get_drvdata(dev));
+ ohci_finish_controller_resume(hcd);
return 0;
}
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index d0360f65ebd9..3bf175d95a23 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -238,42 +238,6 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
return ret;
}
-#if defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \
- defined(CONFIG_USB_EHCI_HCD_MODULE))
-
-/* Following a power loss, we must prepare to regain control of the ports
- * we used to own. This means turning on the port power before ehci-hcd
- * tries to switch ownership.
- *
- * This isn't a 100% perfect solution. On most systems the OHCI controllers
- * lie at lower PCI addresses than the EHCI controller, so they will be
- * discovered (and hence resumed) first. But there is no guarantee things
- * will always work this way. If the EHCI controller is resumed first and
- * the OHCI ports are unpowered, then the handover will fail.
- */
-static void prepare_for_handover(struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- int port;
-
- /* Here we "know" root ports should always stay powered */
- ohci_dbg(ohci, "powerup ports\n");
- for (port = 0; port < ohci->num_ports; port++)
- ohci_writel(ohci, RH_PS_PPS,
- &ohci->regs->roothub.portstatus[port]);
-
- /* Flush those writes */
- ohci_readl(ohci, &ohci->regs->control);
- msleep(20);
-}
-
-#else
-
-static inline void prepare_for_handover(struct usb_hcd *hcd)
-{ }
-
-#endif /* CONFIG_USB_PERSIST etc. */
-
#ifdef CONFIG_PM
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
@@ -313,10 +277,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
static int ohci_pci_resume (struct usb_hcd *hcd)
{
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- /* FIXME: we should try to detect loss of VBUS power here */
- prepare_for_handover(hcd);
-
+ ohci_finish_controller_resume(hcd);
return 0;
}
@@ -345,9 +306,8 @@ static const struct hc_driver ohci_pci_hc_driver = {
.shutdown = ohci_shutdown,
#ifdef CONFIG_PM
- /* these suspend/resume entries are for upstream PCI glue ONLY */
- .suspend = ohci_pci_suspend,
- .resume = ohci_pci_resume,
+ .pci_suspend = ohci_pci_suspend,
+ .pci_resume = ohci_pci_resume,
#endif
/*
@@ -367,7 +327,6 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 28b458f20cc3..664f07ee8732 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -280,7 +280,6 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 605d59cba28e..28467e288a93 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -201,7 +201,6 @@ static const struct hc_driver ohci_pnx8550_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index a67252791223..50e55db13636 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -72,7 +72,6 @@ static const struct hc_driver ohci_ppc_of_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 523c30125577..cd3398b675b2 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -172,7 +172,6 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 01a0caeaa6bc..bfdeb0d22d05 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -68,7 +68,6 @@ static const struct hc_driver ps3_ohci_hc_driver = {
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
.start_port_reset = ohci_start_port_reset,
#if defined(CONFIG_PM)
.bus_suspend = ohci_bus_suspend,
@@ -127,7 +126,6 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
goto fail_irq;
}
- dev->core.power.power_state = PMSG_ON;
dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 8ad9b3b604b5..70b0d4b459e7 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -298,7 +298,6 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -339,7 +338,6 @@ static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_
pxa27x_stop_hc(&pdev->dev);
hcd->state = HC_STATE_SUSPENDED;
- pdev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
@@ -357,9 +355,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
if ((status = pxa27x_start_hc(&pdev->dev)) < 0)
return status;
- pdev->dev.power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(hcd);
-
+ ohci_finish_controller_resume(hcd);
return 0;
}
#endif
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index ead4772f0f27..a73d2ff322e2 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -466,7 +466,6 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 0f48f2d99226..99438c65981b 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -231,7 +231,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index e7ee607278fe..60f03cc7ec4f 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -68,7 +68,6 @@ static const struct hc_driver ohci_sh_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 4ea92762fb28..77204f001b9a 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -75,7 +75,6 @@ static const struct hc_driver ohci_sm501_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -199,7 +198,8 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
usb_put_hcd(hcd);
dma_release_declared_memory(&pdev->dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- release_mem_region(mem->start, mem->end - mem->start + 1);
+ if (mem)
+ release_mem_region(mem->start, mem->end - mem->start + 1);
/* mask interrupts and disable power */
@@ -224,24 +224,26 @@ static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
- dev->power.power_state = PMSG_SUSPEND;
return 0;
}
static int ohci_sm501_resume(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
- dev->power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(platform_get_drvdata(pdev));
+ ohci_finish_controller_resume(hcd);
return 0;
}
+#else
+#define ohci_sm501_suspend NULL
+#define ohci_sm501_resume NULL
#endif
/*-------------------------------------------------------------------------*/
@@ -253,10 +255,8 @@ static struct platform_driver ohci_hcd_sm501_driver = {
.probe = ohci_hcd_sm501_drv_probe,
.remove = ohci_hcd_sm501_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
-#ifdef CONFIG_PM
.suspend = ohci_sm501_suspend,
.resume = ohci_sm501_resume,
-#endif
.driver = {
.owner = THIS_MODULE,
.name = "sm501-usb",
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
index 6e9c2d6db887..c4265caec780 100644
--- a/drivers/usb/host/ohci-ssb.c
+++ b/drivers/usb/host/ohci-ssb.c
@@ -60,36 +60,6 @@ static int ssb_ohci_start(struct usb_hcd *hcd)
return err;
}
-#ifdef CONFIG_PM
-static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
-{
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
- struct ohci_hcd *ohci = &ohcidev->ohci;
- unsigned long flags;
-
- spin_lock_irqsave(&ohci->lock, flags);
-
- ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
- ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
-
- /* make sure snapshot being resumed re-enumerates everything */
- if (message.event == PM_EVENT_PRETHAW)
- ohci_usb_reset(ohci);
-
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
- spin_unlock_irqrestore(&ohci->lock, flags);
- return 0;
-}
-
-static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
-{
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- usb_hcd_resume_root_hub(hcd);
- return 0;
-}
-#endif /* CONFIG_PM */
-
static const struct hc_driver ssb_ohci_hc_driver = {
.description = "ssb-usb-ohci",
.product_desc = "SSB OHCI Controller",
@@ -103,11 +73,6 @@ static const struct hc_driver ssb_ohci_hc_driver = {
.stop = ohci_stop,
.shutdown = ohci_shutdown,
-#ifdef CONFIG_PM
- .suspend = ssb_ohci_hcd_suspend,
- .resume = ssb_ohci_hcd_resume,
-#endif
-
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
@@ -116,7 +81,6 @@ static const struct hc_driver ssb_ohci_hc_driver = {
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
- .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -224,6 +188,7 @@ static int ssb_ohci_resume(struct ssb_device *dev)
ssb_device_enable(dev, ohcidev->enable_flags);
+ ohci_finish_controller_resume(hcd);
return 0;
}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 0ee694f043cc..ae6e70edd745 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -106,7 +106,7 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup);
if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) {
dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n",
- __FUNCTION__, legsup);
+ __func__, legsup);
goto reset_needed;
}
@@ -114,14 +114,14 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) ||
!(cmd & UHCI_USBCMD_EGSM)) {
dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n",
- __FUNCTION__, cmd);
+ __func__, cmd);
goto reset_needed;
}
intr = inw(base + UHCI_USBINTR);
if (intr & (~UHCI_USBINTR_RESUME)) {
dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n",
- __FUNCTION__, intr);
+ __func__, intr);
goto reset_needed;
}
return 0;
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 9f80e5285575..16667342b3c3 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -46,15 +46,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:r8a66597_hcd");
-#define DRIVER_VERSION "29 May 2007"
+#define DRIVER_VERSION "10 Apr 2008"
static const char hcd_name[] = "r8a66597_hcd";
/* module parameters */
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
static unsigned short clock = XTAL12;
module_param(clock, ushort, 0644);
MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
"(default=0)");
+#endif
static unsigned short vif = LDRV;
module_param(vif, ushort, 0644);
@@ -106,11 +108,22 @@ static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
r8a66597_write(r8a66597, val, devadd_reg);
}
-static int enable_controller(struct r8a66597 *r8a66597)
+static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
{
u16 tmp;
int i = 0;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ do {
+ r8a66597_write(r8a66597, SCKE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ err("register access fail.");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ r8a66597_write(r8a66597, 0x04, 0x02);
+#else
do {
r8a66597_write(r8a66597, USBE, SYSCFG0);
tmp = r8a66597_read(r8a66597, SYSCFG0);
@@ -132,13 +145,63 @@ static int enable_controller(struct r8a66597 *r8a66597)
return -ENXIO;
}
} while ((tmp & SCKE) != SCKE);
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+
+ return 0;
+}
+
+static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
+{
+ r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+ udelay(1);
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+#endif
+}
+
+static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
+{
+ u16 val;
+
+ val = port ? DRPD : DCFM | DRPD;
+ r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
+ r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+
+ r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port));
+ r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port));
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+}
- r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
- r8a66597_bset(r8a66597, DRPD, SYSCFG1);
+static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
+{
+ u16 val, tmp;
+
+ r8a66597_write(r8a66597, 0, get_intenb_reg(port));
+ r8a66597_write(r8a66597, 0, get_intsts_reg(port));
+
+ r8a66597_port_power(r8a66597, port, 0);
+
+ do {
+ tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
+ udelay(640);
+ } while (tmp == EDGESTS);
+
+ val = port ? DRPD : DCFM | DRPD;
+ r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
+ r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+ int ret, port;
+
+ ret = r8a66597_clock_enable(r8a66597);
+ if (ret < 0)
+ return ret;
r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
- r8a66597_bset(r8a66597, HSE, SYSCFG0);
- r8a66597_bset(r8a66597, HSE, SYSCFG1);
r8a66597_bset(r8a66597, USBE, SYSCFG0);
r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
@@ -146,53 +209,30 @@ static int enable_controller(struct r8a66597 *r8a66597)
r8a66597_bset(r8a66597, BRDY0, BRDYENB);
r8a66597_bset(r8a66597, BEMP0, BEMPENB);
- r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA0CFG);
- r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA1CFG);
-
r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
-
r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
- r8a66597_bclr(r8a66597, DTCHE, INTENB1);
- r8a66597_bset(r8a66597, ATTCHE, INTENB1);
- r8a66597_bclr(r8a66597, DTCHE, INTENB2);
- r8a66597_bset(r8a66597, ATTCHE, INTENB2);
+
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ r8a66597_enable_port(r8a66597, port);
return 0;
}
static void disable_controller(struct r8a66597 *r8a66597)
{
- u16 tmp;
+ int port;
r8a66597_write(r8a66597, 0, INTENB0);
- r8a66597_write(r8a66597, 0, INTENB1);
- r8a66597_write(r8a66597, 0, INTENB2);
r8a66597_write(r8a66597, 0, INTSTS0);
- r8a66597_write(r8a66597, 0, INTSTS1);
- r8a66597_write(r8a66597, 0, INTSTS2);
-
- r8a66597_port_power(r8a66597, 0, 0);
- r8a66597_port_power(r8a66597, 1, 0);
-
- do {
- tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
- udelay(640);
- } while (tmp == EDGESTS);
- r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0);
- r8a66597_bclr(r8a66597, DRPD, SYSCFG1);
- r8a66597_bclr(r8a66597, HSE, SYSCFG0);
- r8a66597_bclr(r8a66597, HSE, SYSCFG1);
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ r8a66597_disable_port(r8a66597, port);
- r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
- udelay(1);
- r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
- r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_clock_disable(r8a66597);
}
static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
@@ -577,13 +617,9 @@ static void pipe_buffer_setting(struct r8a66597 *r8a66597,
PIPEBUF);
r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket,
PIPEMAXP);
- if (info->interval)
- info->interval--;
r8a66597_write(r8a66597, info->interval, PIPEPERI);
}
-
-
/* this function must be called with interrupt disabled */
static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
@@ -715,6 +751,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
struct r8a66597_pipe *pipe,
struct urb *urb)
{
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
int i;
struct r8a66597_pipe_info *info = &pipe->info;
@@ -742,6 +779,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
break;
}
}
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
}
/* this function must be called with interrupt disabled */
@@ -825,6 +863,25 @@ static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,
dev->dma_map = 0;
}
+static unsigned long get_timer_interval(struct urb *urb, __u8 interval)
+{
+ __u8 i;
+ unsigned long time = 1;
+
+ if (usb_pipeisoc(urb->pipe))
+ return 0;
+
+ if (get_r8a66597_usb_speed(urb->dev->speed) == HSMODE) {
+ for (i = 0; i < (interval - 1); i++)
+ time *= 2;
+ time = time * 125 / 1000; /* uSOF -> msec */
+ } else {
+ time = interval;
+ }
+
+ return time;
+}
+
/* this function must be called with interrupt disabled */
static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
struct usb_host_endpoint *hep,
@@ -840,7 +897,16 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
& USB_ENDPOINT_XFERTYPE_MASK);
info.bufnum = get_bufnum(info.pipenum);
info.buf_bsize = get_buf_bsize(info.pipenum);
- info.interval = ep->bInterval;
+ if (info.type == R8A66597_BULK) {
+ info.interval = 0;
+ info.timer_interval = 0;
+ } else {
+ if (ep->bInterval > IITV)
+ info.interval = IITV;
+ else
+ info.interval = ep->bInterval ? ep->bInterval - 1 : 0;
+ info.timer_interval = get_timer_interval(urb, ep->bInterval);
+ }
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
info.dir_in = 1;
else
@@ -876,10 +942,19 @@ static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum)
}
/* this function must be called with interrupt disabled */
-static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
+static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
+ u16 syssts)
{
- r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
- | (1 << USB_PORT_FEAT_C_CONNECTION);
+ if (syssts == SE0) {
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+ return;
+ }
+
+ if (syssts == FS_JSTS)
+ r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+ else if (syssts == LS_JSTS)
+ r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+
r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
}
@@ -918,7 +993,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
struct r8a66597_td *td)
{
int i;
- u16 *p = (u16 *)td->urb->setup_packet;
+ __le16 *p = (__le16 *)td->urb->setup_packet;
unsigned long setup_addr = USBREQ;
r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
@@ -926,7 +1001,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
- r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
+ r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
setup_addr += 2;
}
r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -960,9 +1035,9 @@ static void prepare_packet_read(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, TRCLR,
td->pipe->pipetre);
r8a66597_write(r8a66597,
- (urb->transfer_buffer_length
- + td->maxpacket - 1)
- / td->maxpacket,
+ DIV_ROUND_UP
+ (urb->transfer_buffer_length,
+ td->maxpacket),
td->pipe->pipetrn);
r8a66597_bset(r8a66597, TRENB,
td->pipe->pipetre);
@@ -1021,8 +1096,7 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
- r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+ r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
enable_irq_empty(r8a66597, 0);
} else {
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
@@ -1454,13 +1528,21 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
}
}
+static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597)
+{
+ mod_timer(&r8a66597->rh_timer,
+ jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME));
+}
+
static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port)
{
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
rh->scount = R8A66597_MAX_SAMPLING;
- mod_timer(&r8a66597->rh_timer, jiffies + msecs_to_jiffies(50));
+ r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
+ | (1 << USB_PORT_FEAT_C_CONNECTION);
+ r8a66597_root_hub_start_polling(r8a66597);
}
static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
@@ -1547,41 +1629,55 @@ static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port)
if ((tmp & USBRST) == USBRST) {
r8a66597_mdfy(r8a66597, UACT, USBRST | UACT,
dvstctr_reg);
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(50));
+ r8a66597_root_hub_start_polling(r8a66597);
} else
r8a66597_usb_connect(r8a66597, port);
}
+ if (!(rh->port & (1 << USB_PORT_FEAT_CONNECTION))) {
+ r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+ }
+
if (rh->scount > 0) {
tmp = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
if (tmp == rh->old_syssts) {
rh->scount--;
- if (rh->scount == 0) {
- if (tmp == FS_JSTS) {
- r8a66597_bset(r8a66597, HSE,
- get_syscfg_reg(port));
- r8a66597_usb_preconnect(r8a66597, port);
- } else if (tmp == LS_JSTS) {
- r8a66597_bclr(r8a66597, HSE,
- get_syscfg_reg(port));
- r8a66597_usb_preconnect(r8a66597, port);
- } else if (tmp == SE0)
- r8a66597_bset(r8a66597, ATTCHE,
- get_intenb_reg(port));
- } else {
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(50));
- }
+ if (rh->scount == 0)
+ r8a66597_check_syssts(r8a66597, port, tmp);
+ else
+ r8a66597_root_hub_start_polling(r8a66597);
} else {
rh->scount = R8A66597_MAX_SAMPLING;
rh->old_syssts = tmp;
- mod_timer(&r8a66597->rh_timer,
- jiffies + msecs_to_jiffies(50));
+ r8a66597_root_hub_start_polling(r8a66597);
}
}
}
+static void r8a66597_interval_timer(unsigned long _r8a66597)
+{
+ struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+ unsigned long flags;
+ u16 pipenum;
+ struct r8a66597_td *td;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+
+ for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ if (!(r8a66597->interval_map & (1 << pipenum)))
+ continue;
+ if (timer_pending(&r8a66597->interval_timer[pipenum]))
+ continue;
+
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (td)
+ start_transfer(r8a66597, td);
+ }
+
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
static void r8a66597_td_timer(unsigned long _r8a66597)
{
struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
@@ -1763,10 +1859,17 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
urb->hcpriv = td;
if (request) {
- ret = start_transfer(r8a66597, td);
- if (ret < 0) {
- list_del(&td->queue);
- kfree(td);
+ if (td->pipe->info.timer_interval) {
+ r8a66597->interval_map |= 1 << td->pipenum;
+ mod_timer(&r8a66597->interval_timer[td->pipenum],
+ jiffies + msecs_to_jiffies(
+ td->pipe->info.timer_interval));
+ } else {
+ ret = start_transfer(r8a66597, td);
+ if (ret < 0) {
+ list_del(&td->queue);
+ kfree(td);
+ }
}
} else
set_td_timer(r8a66597, td);
@@ -2028,7 +2131,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case GetPortStatus:
if (wIndex > R8A66597_MAX_ROOT_HUB)
goto error;
- *(u32 *)buf = cpu_to_le32(rh->port);
+ *(__le32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2107,13 +2210,11 @@ static struct hc_driver r8a66597_hc_driver = {
#if defined(CONFIG_PM)
static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
{
- pdev->dev.power.power_state = state;
return 0;
}
static int r8a66597_resume(struct platform_device *pdev)
{
- pdev->dev.power.power_state = PMSG_ON;
return 0;
}
#else /* if defined(CONFIG_PM) */
@@ -2194,6 +2295,9 @@ static int __init r8a66597_probe(struct platform_device *pdev)
init_timer(&r8a66597->td_timer[i]);
r8a66597->td_timer[i].function = r8a66597_td_timer;
r8a66597->td_timer[i].data = (unsigned long)r8a66597;
+ setup_timer(&r8a66597->interval_timer[i],
+ r8a66597_interval_timer,
+ (unsigned long)r8a66597);
}
INIT_LIST_HEAD(&r8a66597->child_device);
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 57388252b693..84ee01417315 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -187,7 +187,11 @@
#define REW 0x4000 /* b14: Buffer rewind */
#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define DREQE 0x1000 /* b12: DREQ output enable */
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#define MBW 0x0800
+#else
#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
+#endif
#define MBW_8 0x0000 /* 8bit */
#define MBW_16 0x0400 /* 16bit */
#define BIGEND 0x0100 /* b8: Big endian mode */
@@ -395,8 +399,13 @@
#define R8A66597_MAX_NUM_PIPE 10
#define R8A66597_BUF_BSIZE 8
#define R8A66597_MAX_DEVICE 10
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#define R8A66597_MAX_ROOT_HUB 1
+#else
#define R8A66597_MAX_ROOT_HUB 2
-#define R8A66597_MAX_SAMPLING 10
+#endif
+#define R8A66597_MAX_SAMPLING 5
+#define R8A66597_RH_POLL_TIME 10
#define R8A66597_MAX_DMA_CHANNEL 2
#define R8A66597_PIPE_NO_DMA R8A66597_MAX_DMA_CHANNEL
#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5))
@@ -404,6 +413,7 @@
#define make_devsel(addr) (addr << 12)
struct r8a66597_pipe_info {
+ unsigned long timer_interval;
u16 pipenum;
u16 address; /* R8A66597 HCD usb address */
u16 epnum;
@@ -478,9 +488,11 @@ struct r8a66597 {
struct timer_list rh_timer;
struct timer_list td_timer[R8A66597_MAX_NUM_PIPE];
+ struct timer_list interval_timer[R8A66597_MAX_NUM_PIPE];
unsigned short address_map;
unsigned short timeout_map;
+ unsigned short interval_map;
unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
unsigned char dma_map;
@@ -526,8 +538,21 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ unsigned long fifoaddr = r8a66597->reg + offset;
+ unsigned long count;
+
+ count = len / 4;
+ insl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ unsigned long tmp = inl(fifoaddr);
+ memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+ }
+#else
len = (len + 1) / 2;
insw(r8a66597->reg + offset, buf, len);
+#endif
}
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
@@ -541,6 +566,24 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
int len)
{
unsigned long fifoaddr = r8a66597->reg + offset;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ unsigned long count;
+ unsigned char *pb;
+ int i;
+
+ count = len / 4;
+ outsl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ pb = (unsigned char *)buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+ outb(pb[i], fifoaddr + i);
+ else
+ outb(pb[i], fifoaddr + 3 - i);
+ }
+ }
+#else
int odd = len & 0x0001;
len = len / 2;
@@ -549,6 +592,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
buf = &buf[len];
outb((unsigned char)*buf, fifoaddr);
}
+#endif
}
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
@@ -581,6 +625,11 @@ static inline unsigned long get_dvstctr_reg(int port)
return port == 0 ? DVSTCTR0 : DVSTCTR1;
}
+static inline unsigned long get_dmacfg_reg(int port)
+{
+ return port == 0 ? DMA0CFG : DMA1CFG;
+}
+
static inline unsigned long get_intenb_reg(int port)
{
return port == 0 ? INTENB1 : INTENB2;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 629bca0ebe8f..3fd7a0c12078 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -94,12 +94,10 @@ static void port_power(struct sl811 *sl811, int is_on)
sl811->port1 = (1 << USB_PORT_FEAT_POWER);
sl811->irq_enable = SL11H_INTMASK_INSRMV;
- hcd->self.controller->power.power_state = PMSG_ON;
} else {
sl811->port1 = 0;
sl811->irq_enable = 0;
hcd->state = HC_STATE_HALT;
- hcd->self.controller->power.power_state = PMSG_SUSPEND;
}
sl811->ctrl1 = 0;
sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
@@ -1102,7 +1100,7 @@ sl811h_hub_descriptor (
/* no overcurrent errors detection/handling */
temp |= 0x0010;
- desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
+ desc->wHubCharacteristics = cpu_to_le16(temp);
/* two bitmaps: ports removable, and legacy PortPwrCtrlMask */
desc->bitmap[0] = 0 << 1;
@@ -1337,7 +1335,7 @@ static int
sl811h_bus_suspend(struct usb_hcd *hcd)
{
// SOFs off
- DBG("%s\n", __FUNCTION__);
+ DBG("%s\n", __func__);
return 0;
}
@@ -1345,7 +1343,7 @@ static int
sl811h_bus_resume(struct usb_hcd *hcd)
{
// SOFs on
- DBG("%s\n", __FUNCTION__);
+ DBG("%s\n", __func__);
return 0;
}
@@ -1772,8 +1770,6 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state)
port_power(sl811, 0);
break;
}
- if (retval == 0)
- dev->dev.power.power_state = state;
return retval;
}
@@ -1786,15 +1782,13 @@ sl811h_resume(struct platform_device *dev)
/* with no "check to see if VBUS is still powered" board hook,
* let's assume it'd only be powered to enable remote wakeup.
*/
- if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND
- || !device_can_wakeup(&hcd->self.root_hub->dev)) {
+ if (!sl811->port1 || !device_can_wakeup(&hcd->self.root_hub->dev)) {
sl811->port1 = 0;
port_power(sl811, 1);
usb_root_hub_lost_power(hcd->self.root_hub);
return 0;
}
- dev->dev.power.power_state = PMSG_ON;
return sl811h_bus_resume(hcd);
}
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 8e117a795e93..f29307405bb3 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -67,7 +67,7 @@
#include "ohci.h"
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
- OHCI_INTR_WDH)
+ OHCI_INTR_WDH)
MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
MODULE_DESCRIPTION("U132 USB Host Controller Driver");
MODULE_LICENSE("GPL");
@@ -77,15 +77,15 @@ INT_MODULE_PARM(testing, 0);
static int distrust_firmware = 1;
module_param(distrust_firmware, bool, 0);
MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
- "t setup");
+ "t setup");
static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
/*
* u132_module_lock exists to protect access to global variables
*
*/
static struct mutex u132_module_lock;
-static int u132_exiting = 0;
-static int u132_instances = 0;
+static int u132_exiting;
+static int u132_instances;
static struct list_head u132_static_list;
/*
* end of the global variables protected by u132_module_lock
@@ -97,115 +97,115 @@ static struct workqueue_struct *workqueue;
#define MAX_U132_ENDPS 100
#define MAX_U132_RINGS 4
static const char *cc_to_text[16] = {
- "No Error ",
- "CRC Error ",
- "Bit Stuff ",
- "Data Togg ",
- "Stall ",
- "DevNotResp ",
- "PIDCheck ",
- "UnExpPID ",
- "DataOver ",
- "DataUnder ",
- "(for hw) ",
- "(for hw) ",
- "BufferOver ",
- "BuffUnder ",
- "(for HCD) ",
- "(for HCD) "
+ "No Error ",
+ "CRC Error ",
+ "Bit Stuff ",
+ "Data Togg ",
+ "Stall ",
+ "DevNotResp ",
+ "PIDCheck ",
+ "UnExpPID ",
+ "DataOver ",
+ "DataUnder ",
+ "(for hw) ",
+ "(for hw) ",
+ "BufferOver ",
+ "BuffUnder ",
+ "(for HCD) ",
+ "(for HCD) "
};
struct u132_port {
- struct u132 *u132;
- int reset;
- int enable;
- int power;
- int Status;
+ struct u132 *u132;
+ int reset;
+ int enable;
+ int power;
+ int Status;
};
struct u132_addr {
- u8 address;
+ u8 address;
};
struct u132_udev {
- struct kref kref;
- struct usb_device *usb_device;
- u8 enumeration;
- u8 udev_number;
- u8 usb_addr;
- u8 portnumber;
- u8 endp_number_in[16];
- u8 endp_number_out[16];
+ struct kref kref;
+ struct usb_device *usb_device;
+ u8 enumeration;
+ u8 udev_number;
+ u8 usb_addr;
+ u8 portnumber;
+ u8 endp_number_in[16];
+ u8 endp_number_out[16];
};
#define ENDP_QUEUE_SHIFT 3
#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
struct u132_urbq {
- struct list_head urb_more;
- struct urb *urb;
+ struct list_head urb_more;
+ struct urb *urb;
};
struct u132_spin {
- spinlock_t slock;
+ spinlock_t slock;
};
struct u132_endp {
- struct kref kref;
- u8 udev_number;
- u8 endp_number;
- u8 usb_addr;
- u8 usb_endp;
- struct u132 *u132;
- struct list_head endp_ring;
- struct u132_ring *ring;
- unsigned toggle_bits:2;
- unsigned active:1;
- unsigned delayed:1;
- unsigned input:1;
- unsigned output:1;
- unsigned pipetype:2;
- unsigned dequeueing:1;
- unsigned edset_flush:1;
- unsigned spare_bits:14;
- unsigned long jiffies;
- struct usb_host_endpoint *hep;
- struct u132_spin queue_lock;
- u16 queue_size;
- u16 queue_last;
- u16 queue_next;
- struct urb *urb_list[ENDP_QUEUE_SIZE];
- struct list_head urb_more;
- struct delayed_work scheduler;
+ struct kref kref;
+ u8 udev_number;
+ u8 endp_number;
+ u8 usb_addr;
+ u8 usb_endp;
+ struct u132 *u132;
+ struct list_head endp_ring;
+ struct u132_ring *ring;
+ unsigned toggle_bits:2;
+ unsigned active:1;
+ unsigned delayed:1;
+ unsigned input:1;
+ unsigned output:1;
+ unsigned pipetype:2;
+ unsigned dequeueing:1;
+ unsigned edset_flush:1;
+ unsigned spare_bits:14;
+ unsigned long jiffies;
+ struct usb_host_endpoint *hep;
+ struct u132_spin queue_lock;
+ u16 queue_size;
+ u16 queue_last;
+ u16 queue_next;
+ struct urb *urb_list[ENDP_QUEUE_SIZE];
+ struct list_head urb_more;
+ struct delayed_work scheduler;
};
struct u132_ring {
- unsigned in_use:1;
- unsigned length:7;
- u8 number;
- struct u132 *u132;
- struct u132_endp *curr_endp;
- struct delayed_work scheduler;
+ unsigned in_use:1;
+ unsigned length:7;
+ u8 number;
+ struct u132 *u132;
+ struct u132_endp *curr_endp;
+ struct delayed_work scheduler;
};
struct u132 {
- struct kref kref;
- struct list_head u132_list;
- struct mutex sw_lock;
- struct semaphore scheduler_lock;
- struct u132_platform_data *board;
- struct platform_device *platform_dev;
- struct u132_ring ring[MAX_U132_RINGS];
- int sequence_num;
- int going;
- int power;
- int reset;
- int num_ports;
- u32 hc_control;
- u32 hc_fminterval;
- u32 hc_roothub_status;
- u32 hc_roothub_a;
- u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
- int flags;
- unsigned long next_statechange;
- struct delayed_work monitor;
- int num_endpoints;
- struct u132_addr addr[MAX_U132_ADDRS];
- struct u132_udev udev[MAX_U132_UDEVS];
- struct u132_port port[MAX_U132_PORTS];
- struct u132_endp *endp[MAX_U132_ENDPS];
+ struct kref kref;
+ struct list_head u132_list;
+ struct mutex sw_lock;
+ struct mutex scheduler_lock;
+ struct u132_platform_data *board;
+ struct platform_device *platform_dev;
+ struct u132_ring ring[MAX_U132_RINGS];
+ int sequence_num;
+ int going;
+ int power;
+ int reset;
+ int num_ports;
+ u32 hc_control;
+ u32 hc_fminterval;
+ u32 hc_roothub_status;
+ u32 hc_roothub_a;
+ u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
+ int flags;
+ unsigned long next_statechange;
+ struct delayed_work monitor;
+ int num_endpoints;
+ struct u132_addr addr[MAX_U132_ADDRS];
+ struct u132_udev udev[MAX_U132_UDEVS];
+ struct u132_port port[MAX_U132_PORTS];
+ struct u132_endp *endp[MAX_U132_ENDPS];
};
/*
@@ -213,34 +213,34 @@ struct u132 {
* Does anyone have a better way?????
*/
#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
- offsetof(struct ohci_regs, member), 0, data);
+ offsetof(struct ohci_regs, member), 0, data);
#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
- offsetof(struct ohci_regs, member), 0, data);
+ offsetof(struct ohci_regs, member), 0, data);
#define u132_read_pcimem(u132, member, data) \
- usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
- ohci_regs, member), 0, data);
+ usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0, data);
#define u132_write_pcimem(u132, member, data) \
- usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
- ohci_regs, member), 0, data);
+ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0, data);
static inline struct u132 *udev_to_u132(struct u132_udev *udev)
{
- u8 udev_number = udev->udev_number;
- return container_of(udev, struct u132, udev[udev_number]);
+ u8 udev_number = udev->udev_number;
+ return container_of(udev, struct u132, udev[udev_number]);
}
static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
{
- return (struct u132 *)(hcd->hcd_priv);
+ return (struct u132 *)(hcd->hcd_priv);
}
static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
{
- return container_of((void *)u132, struct usb_hcd, hcd_priv);
+ return container_of((void *)u132, struct usb_hcd, hcd_priv);
}
static inline void u132_disable(struct u132 *u132)
{
- u132_to_hcd(u132)->state = HC_STATE_HALT;
+ u132_to_hcd(u132)->state = HC_STATE_HALT;
}
@@ -250,147 +250,147 @@ static inline void u132_disable(struct u132 *u132)
#include "../misc/usb_u132.h"
static const char hcd_name[] = "u132_hcd";
#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \
- USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
- USB_PORT_STAT_C_RESET) << 16)
+ USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
+ USB_PORT_STAT_C_RESET) << 16)
static void u132_hcd_delete(struct kref *kref)
{
- struct u132 *u132 = kref_to_u132(kref);
- struct platform_device *pdev = u132->platform_dev;
- struct usb_hcd *hcd = u132_to_hcd(u132);
- u132->going += 1;
- mutex_lock(&u132_module_lock);
- list_del_init(&u132->u132_list);
- u132_instances -= 1;
- mutex_unlock(&u132_module_lock);
- dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
- "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
- usb_put_hcd(hcd);
+ struct u132 *u132 = kref_to_u132(kref);
+ struct platform_device *pdev = u132->platform_dev;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ u132->going += 1;
+ mutex_lock(&u132_module_lock);
+ list_del_init(&u132->u132_list);
+ u132_instances -= 1;
+ mutex_unlock(&u132_module_lock);
+ dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
+ "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
+ usb_put_hcd(hcd);
}
static inline void u132_u132_put_kref(struct u132 *u132)
{
- kref_put(&u132->kref, u132_hcd_delete);
+ kref_put(&u132->kref, u132_hcd_delete);
}
static inline void u132_u132_init_kref(struct u132 *u132)
{
- kref_init(&u132->kref);
+ kref_init(&u132->kref);
}
static void u132_udev_delete(struct kref *kref)
{
- struct u132_udev *udev = kref_to_u132_udev(kref);
- udev->udev_number = 0;
- udev->usb_device = NULL;
- udev->usb_addr = 0;
- udev->enumeration = 0;
+ struct u132_udev *udev = kref_to_u132_udev(kref);
+ udev->udev_number = 0;
+ udev->usb_device = NULL;
+ udev->usb_addr = 0;
+ udev->enumeration = 0;
}
static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
{
- kref_put(&udev->kref, u132_udev_delete);
+ kref_put(&udev->kref, u132_udev_delete);
}
static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
{
- kref_get(&udev->kref);
+ kref_get(&udev->kref);
}
static inline void u132_udev_init_kref(struct u132 *u132,
- struct u132_udev *udev)
+ struct u132_udev *udev)
{
- kref_init(&udev->kref);
+ kref_init(&udev->kref);
}
static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
{
- kref_put(&u132->kref, u132_hcd_delete);
+ kref_put(&u132->kref, u132_hcd_delete);
}
static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
- unsigned int delta)
+ unsigned int delta)
{
- if (delta > 0) {
- if (queue_delayed_work(workqueue, &ring->scheduler, delta))
- return;
- } else if (queue_delayed_work(workqueue, &ring->scheduler, 0))
- return;
- kref_put(&u132->kref, u132_hcd_delete);
- return;
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &ring->scheduler, delta))
+ return;
+ } else if (queue_delayed_work(workqueue, &ring->scheduler, 0))
+ return;
+ kref_put(&u132->kref, u132_hcd_delete);
+ return;
}
static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
- unsigned int delta)
+ unsigned int delta)
{
- kref_get(&u132->kref);
- u132_ring_requeue_work(u132, ring, delta);
- return;
+ kref_get(&u132->kref);
+ u132_ring_requeue_work(u132, ring, delta);
+ return;
}
static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
{
- if (cancel_delayed_work(&ring->scheduler)) {
- kref_put(&u132->kref, u132_hcd_delete);
- }
+ if (cancel_delayed_work(&ring->scheduler))
+ kref_put(&u132->kref, u132_hcd_delete);
}
static void u132_endp_delete(struct kref *kref)
{
- struct u132_endp *endp = kref_to_u132_endp(kref);
- struct u132 *u132 = endp->u132;
- u8 usb_addr = endp->usb_addr;
- u8 usb_endp = endp->usb_endp;
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- u8 endp_number = endp->endp_number;
- struct usb_host_endpoint *hep = endp->hep;
- struct u132_ring *ring = endp->ring;
- struct list_head *head = &endp->endp_ring;
- ring->length -= 1;
- if (endp == ring->curr_endp) {
- if (list_empty(head)) {
- ring->curr_endp = NULL;
- list_del(head);
- } else {
- struct u132_endp *next_endp = list_entry(head->next,
- struct u132_endp, endp_ring);
- ring->curr_endp = next_endp;
- list_del(head);
- }} else
- list_del(head);
- if (endp->input) {
- udev->endp_number_in[usb_endp] = 0;
- u132_udev_put_kref(u132, udev);
- }
- if (endp->output) {
- udev->endp_number_out[usb_endp] = 0;
- u132_udev_put_kref(u132, udev);
- }
- u132->endp[endp_number - 1] = NULL;
- hep->hcpriv = NULL;
- kfree(endp);
- u132_u132_put_kref(u132);
+ struct u132_endp *endp = kref_to_u132_endp(kref);
+ struct u132 *u132 = endp->u132;
+ u8 usb_addr = endp->usb_addr;
+ u8 usb_endp = endp->usb_endp;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ u8 endp_number = endp->endp_number;
+ struct usb_host_endpoint *hep = endp->hep;
+ struct u132_ring *ring = endp->ring;
+ struct list_head *head = &endp->endp_ring;
+ ring->length -= 1;
+ if (endp == ring->curr_endp) {
+ if (list_empty(head)) {
+ ring->curr_endp = NULL;
+ list_del(head);
+ } else {
+ struct u132_endp *next_endp = list_entry(head->next,
+ struct u132_endp, endp_ring);
+ ring->curr_endp = next_endp;
+ list_del(head);
+ }
+ } else
+ list_del(head);
+ if (endp->input) {
+ udev->endp_number_in[usb_endp] = 0;
+ u132_udev_put_kref(u132, udev);
+ }
+ if (endp->output) {
+ udev->endp_number_out[usb_endp] = 0;
+ u132_udev_put_kref(u132, udev);
+ }
+ u132->endp[endp_number - 1] = NULL;
+ hep->hcpriv = NULL;
+ kfree(endp);
+ u132_u132_put_kref(u132);
}
static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
{
- kref_put(&endp->kref, u132_endp_delete);
+ kref_put(&endp->kref, u132_endp_delete);
}
static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
{
- kref_get(&endp->kref);
+ kref_get(&endp->kref);
}
static inline void u132_endp_init_kref(struct u132 *u132,
- struct u132_endp *endp)
+ struct u132_endp *endp)
{
- kref_init(&endp->kref);
- kref_get(&u132->kref);
+ kref_init(&endp->kref);
+ kref_get(&u132->kref);
}
static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
- unsigned int delta)
+ unsigned int delta)
{
if (queue_delayed_work(workqueue, &endp->scheduler, delta))
kref_get(&endp->kref);
@@ -398,13 +398,13 @@ static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
{
- if (cancel_delayed_work(&endp->scheduler))
- kref_put(&endp->kref, u132_endp_delete);
+ if (cancel_delayed_work(&endp->scheduler))
+ kref_put(&endp->kref, u132_endp_delete);
}
static inline void u132_monitor_put_kref(struct u132 *u132)
{
- kref_put(&u132->kref, u132_hcd_delete);
+ kref_put(&u132->kref, u132_hcd_delete);
}
static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
@@ -421,200 +421,201 @@ static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
static void u132_monitor_cancel_work(struct u132 *u132)
{
- if (cancel_delayed_work(&u132->monitor))
- kref_put(&u132->kref, u132_hcd_delete);
+ if (cancel_delayed_work(&u132->monitor))
+ kref_put(&u132->kref, u132_hcd_delete);
}
static int read_roothub_info(struct u132 *u132)
{
- u32 revision;
- int retval;
- retval = u132_read_pcimem(u132, revision, &revision);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device co"
- "ntrol\n", retval);
- return retval;
- } else if ((revision & 0xFF) == 0x10) {
- } else if ((revision & 0xFF) == 0x11) {
- } else {
- dev_err(&u132->platform_dev->dev, "device revision is not valid"
- " %08X\n", revision);
- return -ENODEV;
- }
- retval = u132_read_pcimem(u132, control, &u132->hc_control);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device co"
- "ntrol\n", retval);
- return retval;
- }
- retval = u132_read_pcimem(u132, roothub.status,
- &u132->hc_roothub_status);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device re"
- "g roothub.status\n", retval);
- return retval;
- }
- retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d accessing device re"
- "g roothub.a\n", retval);
- return retval;
- }
- {
- int I = u132->num_ports;
- int i = 0;
- while (I-- > 0) {
- retval = u132_read_pcimem(u132, roothub.portstatus[i],
- &u132->hc_roothub_portstatus[i]);
- if (retval) {
- dev_err(&u132->platform_dev->dev, "error %d acc"
- "essing device roothub.portstatus[%d]\n"
- , retval, i);
- return retval;
- } else
- i += 1;
- }
- }
- return 0;
+ u32 revision;
+ int retval;
+ retval = u132_read_pcimem(u132, revision, &revision);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
+ "ntrol\n", retval);
+ return retval;
+ } else if ((revision & 0xFF) == 0x10) {
+ } else if ((revision & 0xFF) == 0x11) {
+ } else {
+ dev_err(&u132->platform_dev->dev, "device revision is not valid"
+ " %08X\n", revision);
+ return -ENODEV;
+ }
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
+ "ntrol\n", retval);
+ return retval;
+ }
+ retval = u132_read_pcimem(u132, roothub.status,
+ &u132->hc_roothub_status);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
+ "g roothub.status\n", retval);
+ return retval;
+ }
+ retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
+ "g roothub.a\n", retval);
+ return retval;
+ }
+ {
+ int I = u132->num_ports;
+ int i = 0;
+ while (I-- > 0) {
+ retval = u132_read_pcimem(u132, roothub.portstatus[i],
+ &u132->hc_roothub_portstatus[i]);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d acc"
+ "essing device roothub.portstatus[%d]\n"
+ , retval, i);
+ return retval;
+ } else
+ i += 1;
+ }
+ }
+ return 0;
}
static void u132_hcd_monitor_work(struct work_struct *work)
{
- struct u132 *u132 = container_of(work, struct u132, monitor.work);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- u132_monitor_put_kref(u132);
- return;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- u132_monitor_put_kref(u132);
- return;
- } else {
- int retval;
- mutex_lock(&u132->sw_lock);
- retval = read_roothub_info(u132);
- if (retval) {
- struct usb_hcd *hcd = u132_to_hcd(u132);
- u132_disable(u132);
- u132->going = 1;
- mutex_unlock(&u132->sw_lock);
- usb_hc_died(hcd);
- ftdi_elan_gone_away(u132->platform_dev);
- u132_monitor_put_kref(u132);
- return;
- } else {
- u132_monitor_requeue_work(u132, 500);
- mutex_unlock(&u132->sw_lock);
- return;
- }
- }
+ struct u132 *u132 = container_of(work, struct u132, monitor.work);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ u132_monitor_put_kref(u132);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ u132_monitor_put_kref(u132);
+ return;
+ } else {
+ int retval;
+ mutex_lock(&u132->sw_lock);
+ retval = read_roothub_info(u132);
+ if (retval) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ u132_disable(u132);
+ u132->going = 1;
+ mutex_unlock(&u132->sw_lock);
+ usb_hc_died(hcd);
+ ftdi_elan_gone_away(u132->platform_dev);
+ u132_monitor_put_kref(u132);
+ return;
+ } else {
+ u132_monitor_requeue_work(u132, 500);
+ mutex_unlock(&u132->sw_lock);
+ return;
+ }
+ }
}
static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
+ struct urb *urb, int status)
{
- struct u132_ring *ring;
- unsigned long irqs;
- struct usb_hcd *hcd = u132_to_hcd(u132);
- urb->error_count = 0;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ struct u132_ring *ring;
+ unsigned long irqs;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ urb->error_count = 0;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
usb_hcd_unlink_urb_from_ep(hcd, urb);
- endp->queue_next += 1;
- if (ENDP_QUEUE_SIZE > --endp->queue_size) {
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- } else {
- struct list_head *next = endp->urb_more.next;
- struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
- urb_more);
- list_del(next);
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
- urbq->urb;
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(urbq);
- } down(&u132->scheduler_lock);
- ring = endp->ring;
- ring->in_use = 0;
- u132_ring_cancel_work(u132, ring);
- u132_ring_queue_work(u132, ring, 0);
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
+ endp->queue_next += 1;
+ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
+ urb_more);
+ list_del(next);
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urbq->urb;
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(urbq);
+ }
+ mutex_lock(&u132->scheduler_lock);
+ ring = endp->ring;
+ ring->in_use = 0;
+ u132_ring_cancel_work(u132, ring);
+ u132_ring_queue_work(u132, ring, 0);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
usb_hcd_giveback_urb(hcd, urb, status);
- return;
+ return;
}
static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
+ struct urb *urb, int status)
{
- u132_endp_put_kref(u132, endp);
+ u132_endp_put_kref(u132, endp);
}
static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb, int status)
+ struct urb *urb, int status)
{
- unsigned long irqs;
- struct usb_hcd *hcd = u132_to_hcd(u132);
- urb->error_count = 0;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ unsigned long irqs;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ urb->error_count = 0;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
usb_hcd_unlink_urb_from_ep(hcd, urb);
- endp->queue_next += 1;
- if (ENDP_QUEUE_SIZE > --endp->queue_size) {
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- } else {
- struct list_head *next = endp->urb_more.next;
- struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
- urb_more);
- list_del(next);
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
- urbq->urb;
- endp->active = 0;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- kfree(urbq);
+ endp->queue_next += 1;
+ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
+ urb_more);
+ list_del(next);
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urbq->urb;
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(urbq);
} usb_hcd_giveback_urb(hcd, urb, status);
- return;
+ return;
}
static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
{
- return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
- urb, address, endp->usb_endp, toggle_bits, callback);
+ return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
+ urb, address, endp->usb_endp, toggle_bits, callback);
}
static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
{
- return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
- urb, address, endp->usb_endp, toggle_bits, callback);
+ return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
+ urb, address, endp->usb_endp, toggle_bits, callback);
}
static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
{
- return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
- endp, urb, address, endp->usb_endp, toggle_bits, callback);
+ return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
+ endp, urb, address, endp->usb_endp, toggle_bits, callback);
}
static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
- struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
- void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
- int toggle_bits, int error_count, int condition_code, int repeat_number,
- int halted, int skipped, int actual, int non_null))
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
{
- return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
- endp, urb, address, endp->usb_endp, toggle_bits, callback);
+ return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
+ endp, urb, address, endp->usb_endp, toggle_bits, callback);
}
@@ -623,683 +624,678 @@ static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
*
*/
static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer + urb->actual_length;
- u8 *b = buf;
- int L = len;
- while (L-- > 0) {
- *u++ = *b++;
- }
- urb->actual_length += len;
- if ((condition_code == TD_CC_NOERROR) &&
- (urb->transfer_buffer_length > urb->actual_length)) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- if (urb->actual_length > 0) {
- int retval;
- up(&u132->scheduler_lock);
- retval = edset_single(u132, ring, endp, urb,
- address, endp->toggle_bits,
- u132_hcd_interrupt_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb,
- retval);
- } else {
- ring->in_use = 0;
- endp->active = 0;
- endp->jiffies = jiffies +
- msecs_to_jiffies(urb->interval);
- u132_ring_cancel_work(u132, ring);
- u132_ring_queue_work(u132, ring, 0);
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- }
- return;
- } else if ((condition_code == TD_DATAUNDERRUN) &&
- ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
- if (condition_code == TD_CC_NOERROR) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp,
- 0, 1 & toggle_bits);
- } else if (condition_code == TD_CC_STALL) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp,
- 0, 0);
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp,
- 0, 0);
- dev_err(&u132->platform_dev->dev, "urb=%p givin"
- "g back INTERRUPT %s\n", urb,
- cc_to_text[condition_code]);
- }
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- }
- } else {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer + urb->actual_length;
+ u8 *b = buf;
+ int L = len;
+
+ while (L-- > 0)
+ *u++ = *b++;
+
+ urb->actual_length += len;
+ if ((condition_code == TD_CC_NOERROR) &&
+ (urb->transfer_buffer_length > urb->actual_length)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ if (urb->actual_length > 0) {
+ int retval;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_single(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_interrupt_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ } else {
+ ring->in_use = 0;
+ endp->active = 0;
+ endp->jiffies = jiffies +
+ msecs_to_jiffies(urb->interval);
+ u132_ring_cancel_work(u132, ring);
+ u132_ring_queue_work(u132, ring, 0);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ }
+ return;
+ } else if ((condition_code == TD_DATAUNDERRUN) &&
+ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ if (condition_code == TD_CC_NOERROR) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 1 & toggle_bits);
+ } else if (condition_code == TD_CC_STALL) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 0);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 0);
+ dev_err(&u132->platform_dev->dev, "urb=%p givin"
+ "g back INTERRUPT %s\n", urb,
+ cc_to_text[condition_code]);
+ }
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- urb->actual_length += len;
- endp->toggle_bits = toggle_bits;
- if (urb->transfer_buffer_length > urb->actual_length) {
- int retval;
- up(&u132->scheduler_lock);
- retval = edset_output(u132, ring, endp, urb, address,
- endp->toggle_bits, u132_hcd_bulk_output_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
- } else {
+ struct u132_ring *ring = endp->ring;
+ urb->actual_length += len;
+ endp->toggle_bits = toggle_bits;
+ if (urb->transfer_buffer_length > urb->actual_length) {
+ int retval;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_output(u132, ring, endp, urb, address,
+ endp->toggle_bits, u132_hcd_bulk_output_sent);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ }
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer + urb->actual_length;
- u8 *b = buf;
- int L = len;
- while (L-- > 0) {
- *u++ = *b++;
- }
- urb->actual_length += len;
- if ((condition_code == TD_CC_NOERROR) &&
- (urb->transfer_buffer_length > urb->actual_length)) {
- int retval;
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, endp->toggle_bits,
- u132_hcd_bulk_input_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else if (condition_code == TD_CC_NOERROR) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- } else if ((condition_code == TD_DATAUNDERRUN) &&
- ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else if (condition_code == TD_DATAUNDERRUN) {
- endp->toggle_bits = toggle_bits;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0,
- 1 & toggle_bits);
- dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
- ") giving back BULK IN %s\n", urb,
- cc_to_text[condition_code]);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else if (condition_code == TD_CC_STALL) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
- dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
- "ULK IN code=%d %s\n", urb, condition_code,
- cc_to_text[condition_code]);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- }
- } else {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer + urb->actual_length;
+ u8 *b = buf;
+ int L = len;
+
+ while (L-- > 0)
+ *u++ = *b++;
+
+ urb->actual_length += len;
+ if ((condition_code == TD_CC_NOERROR) &&
+ (urb->transfer_buffer_length > urb->actual_length)) {
+ int retval;
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, endp->toggle_bits,
+ u132_hcd_bulk_input_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (condition_code == TD_CC_NOERROR) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else if ((condition_code == TD_DATAUNDERRUN) &&
+ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else if (condition_code == TD_DATAUNDERRUN) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
+ ") giving back BULK IN %s\n", urb,
+ cc_to_text[condition_code]);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else if (condition_code == TD_CC_STALL) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
+ dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
+ "ULK IN code=%d %s\n", urb, condition_code,
+ cc_to_text[condition_code]);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer;
- u8 *b = buf;
- int L = len;
- while (L-- > 0) {
- *u++ = *b++;
- }
- urb->actual_length = len;
- if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
- TD_DATAUNDERRUN) && ((urb->transfer_flags &
- URB_SHORT_NOT_OK) == 0))) {
- int retval;
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, 0x3,
- u132_hcd_configure_empty_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else if (condition_code == TD_CC_STALL) {
- up(&u132->scheduler_lock);
- dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
- "NPUT STALL urb %p\n", urb);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- } else {
- up(&u132->scheduler_lock);
- dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
- "PUT %s urb %p\n", cc_to_text[condition_code],
- urb);
- u132_hcd_giveback_urb(u132, endp, urb,
- cc_to_error[condition_code]);
- return;
- }
- } else {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer;
+ u8 *b = buf;
+ int L = len;
+
+ while (L-- > 0)
+ *u++ = *b++;
+
+ urb->actual_length = len;
+ if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
+ TD_DATAUNDERRUN) && ((urb->transfer_flags &
+ URB_SHORT_NOT_OK) == 0))) {
+ int retval;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0x3,
+ u132_hcd_configure_empty_sent);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (condition_code == TD_CC_STALL) {
+ mutex_unlock(&u132->scheduler_lock);
+ dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
+ "NPUT STALL urb %p\n", urb);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else {
+ mutex_unlock(&u132->scheduler_lock);
+ dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
+ "PUT %s urb %p\n", cc_to_text[condition_code],
+ urb);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- if (usb_pipein(urb->pipe)) {
- int retval;
- struct u132_ring *ring = endp->ring;
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, 0,
- u132_hcd_configure_input_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- int retval;
- struct u132_ring *ring = endp->ring;
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address,
- endp->usb_endp, 0,
- u132_hcd_configure_empty_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- }
- } else {
+ if (usb_pipein(urb->pipe)) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0,
+ u132_hcd_configure_input_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0,
+ u132_hcd_configure_empty_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
- u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- u132->addr[0].address = 0;
- endp->usb_addr = udev->usb_addr;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
+ u132->addr[0].address = 0;
+ endp->usb_addr = udev->usb_addr;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
- u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- int retval;
- struct u132_ring *ring = endp->ring;
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, 0, endp->usb_endp, 0,
- u132_hcd_enumeration_empty_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, 0, endp->usb_endp, 0,
+ u132_hcd_enumeration_empty_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- } else {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- int retval;
- struct u132_ring *ring = endp->ring;
- u8 *u = urb->transfer_buffer;
- u8 *b = buf;
- int L = len;
- while (L-- > 0) {
- *u++ = *b++;
- }
- urb->actual_length = len;
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
- ring->number, endp, urb, address, endp->usb_endp, 0x3,
- u132_hcd_initial_empty_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer;
+ u8 *b = buf;
+ int L = len;
+
+ while (L-- > 0)
+ *u++ = *b++;
+
+ urb->actual_length = len;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
+ ring->number, endp, urb, address, endp->usb_endp, 0x3,
+ u132_hcd_initial_empty_sent);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
- int len, int toggle_bits, int error_count, int condition_code,
- int repeat_number, int halted, int skipped, int actual, int non_null)
-{
- struct u132_endp *endp = data;
- struct u132 *u132 = endp->u132;
- u8 address = u132->addr[endp->usb_addr].address;
- down(&u132->scheduler_lock);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- up(&u132->scheduler_lock);
- u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
- return;
- } else if (endp->dequeueing) {
- endp->dequeueing = 0;
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
- return;
- } else if (u132->going > 0) {
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ mutex_lock(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
- return;
+ mutex_unlock(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
} else if (!urb->unlinked) {
- int retval;
- struct u132_ring *ring = endp->ring;
- up(&u132->scheduler_lock);
- retval = usb_ftdi_elan_edset_input(u132->platform_dev,
- ring->number, endp, urb, address, endp->usb_endp, 0,
- u132_hcd_initial_input_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address, endp->usb_endp, 0,
+ u132_hcd_initial_input_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
- up(&u132->scheduler_lock);
+ mutex_unlock(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
- return;
- }
+ return;
+ }
}
/*
@@ -1308,302 +1304,296 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
*/
static void u132_hcd_ring_work_scheduler(struct work_struct *work)
{
- struct u132_ring *ring =
+ struct u132_ring *ring =
container_of(work, struct u132_ring, scheduler.work);
- struct u132 *u132 = ring->u132;
- down(&u132->scheduler_lock);
- if (ring->in_use) {
- up(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- } else if (ring->curr_endp) {
- struct u132_endp *last_endp = ring->curr_endp;
- struct list_head *scan;
- struct list_head *head = &last_endp->endp_ring;
- unsigned long wakeup = 0;
- list_for_each(scan, head) {
- struct u132_endp *endp = list_entry(scan,
- struct u132_endp, endp_ring);
- if (endp->queue_next == endp->queue_last) {
- } else if ((endp->delayed == 0)
- || time_after_eq(jiffies, endp->jiffies)) {
- ring->curr_endp = endp;
- u132_endp_cancel_work(u132, last_endp);
- u132_endp_queue_work(u132, last_endp, 0);
- up(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- } else {
- unsigned long delta = endp->jiffies - jiffies;
- if (delta > wakeup)
- wakeup = delta;
- }
- }
- if (last_endp->queue_next == last_endp->queue_last) {
- } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
- last_endp->jiffies)) {
- u132_endp_cancel_work(u132, last_endp);
- u132_endp_queue_work(u132, last_endp, 0);
- up(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- } else {
- unsigned long delta = last_endp->jiffies - jiffies;
- if (delta > wakeup)
- wakeup = delta;
- }
- if (wakeup > 0) {
- u132_ring_requeue_work(u132, ring, wakeup);
- up(&u132->scheduler_lock);
- return;
- } else {
- up(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- }
- } else {
- up(&u132->scheduler_lock);
- u132_ring_put_kref(u132, ring);
- return;
- }
+ struct u132 *u132 = ring->u132;
+ mutex_lock(&u132->scheduler_lock);
+ if (ring->in_use) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else if (ring->curr_endp) {
+ struct u132_endp *last_endp = ring->curr_endp;
+ struct list_head *scan;
+ struct list_head *head = &last_endp->endp_ring;
+ unsigned long wakeup = 0;
+ list_for_each(scan, head) {
+ struct u132_endp *endp = list_entry(scan,
+ struct u132_endp, endp_ring);
+ if (endp->queue_next == endp->queue_last) {
+ } else if ((endp->delayed == 0)
+ || time_after_eq(jiffies, endp->jiffies)) {
+ ring->curr_endp = endp;
+ u132_endp_cancel_work(u132, last_endp);
+ u132_endp_queue_work(u132, last_endp, 0);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else {
+ unsigned long delta = endp->jiffies - jiffies;
+ if (delta > wakeup)
+ wakeup = delta;
+ }
+ }
+ if (last_endp->queue_next == last_endp->queue_last) {
+ } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
+ last_endp->jiffies)) {
+ u132_endp_cancel_work(u132, last_endp);
+ u132_endp_queue_work(u132, last_endp, 0);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else {
+ unsigned long delta = last_endp->jiffies - jiffies;
+ if (delta > wakeup)
+ wakeup = delta;
+ }
+ if (wakeup > 0) {
+ u132_ring_requeue_work(u132, ring, wakeup);
+ mutex_unlock(&u132->scheduler_lock);
+ return;
+ } else {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ }
+ } else {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ }
}
static void u132_hcd_endp_work_scheduler(struct work_struct *work)
{
- struct u132_ring *ring;
- struct u132_endp *endp =
+ struct u132_ring *ring;
+ struct u132_endp *endp =
container_of(work, struct u132_endp, scheduler.work);
- struct u132 *u132 = endp->u132;
- down(&u132->scheduler_lock);
- ring = endp->ring;
- if (endp->edset_flush) {
- endp->edset_flush = 0;
- if (endp->dequeueing)
- usb_ftdi_elan_edset_flush(u132->platform_dev,
- ring->number, endp);
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (endp->active) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (ring->in_use) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (endp->queue_next == endp->queue_last) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (endp->pipetype == PIPE_INTERRUPT) {
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- up(&u132->scheduler_lock);
- retval = edset_single(u132, ring, endp, urb, address,
- endp->toggle_bits, u132_hcd_interrupt_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- }
- } else if (endp->pipetype == PIPE_CONTROL) {
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else if (address == 0) {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- up(&u132->scheduler_lock);
- retval = edset_setup(u132, ring, endp, urb, address,
- 0x2, u132_hcd_initial_setup_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else if (endp->usb_addr == 0) {
- int retval;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- up(&u132->scheduler_lock);
- retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
- u132_hcd_enumeration_address_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- } else {
- int retval;
- u8 address = u132->addr[endp->usb_addr].address;
- struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- up(&u132->scheduler_lock);
- retval = edset_setup(u132, ring, endp, urb, address,
- 0x2, u132_hcd_configure_setup_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb, retval);
- return;
- }
- } else {
- if (endp->input) {
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[
- ENDP_QUEUE_MASK & endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- up(&u132->scheduler_lock);
- retval = edset_input(u132, ring, endp, urb,
- address, endp->toggle_bits,
- u132_hcd_bulk_input_recv);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb,
- retval);
- return;
- }
- } else { /* output pipe */
- u8 address = u132->addr[endp->usb_addr].address;
- if (ring->in_use) {
- up(&u132->scheduler_lock);
- u132_endp_put_kref(u132, endp);
- return;
- } else {
- int retval;
- struct urb *urb = endp->urb_list[
- ENDP_QUEUE_MASK & endp->queue_next];
- endp->active = 1;
- ring->curr_endp = endp;
- ring->in_use = 1;
- up(&u132->scheduler_lock);
- retval = edset_output(u132, ring, endp, urb,
- address, endp->toggle_bits,
- u132_hcd_bulk_output_sent);
- if (retval == 0) {
- } else
- u132_hcd_giveback_urb(u132, endp, urb,
- retval);
- return;
- }
- }
- }
+ struct u132 *u132 = endp->u132;
+ mutex_lock(&u132->scheduler_lock);
+ ring = endp->ring;
+ if (endp->edset_flush) {
+ endp->edset_flush = 0;
+ if (endp->dequeueing)
+ usb_ftdi_elan_edset_flush(u132->platform_dev,
+ ring->number, endp);
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->active) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (ring->in_use) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->queue_next == endp->queue_last) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->pipetype == PIPE_INTERRUPT) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_single(u132, ring, endp, urb, address,
+ endp->toggle_bits, u132_hcd_interrupt_recv);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else if (endp->pipetype == PIPE_CONTROL) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (address == 0) {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, address,
+ 0x2, u132_hcd_initial_setup_sent);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (endp->usb_addr == 0) {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
+ u132_hcd_enumeration_address_sent);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ int retval;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, address,
+ 0x2, u132_hcd_configure_setup_sent);
+ if (retval != 0)
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else {
+ if (endp->input) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[
+ ENDP_QUEUE_MASK & endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_input(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_bulk_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ return;
+ }
+ } else { /* output pipe */
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ mutex_unlock(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[
+ ENDP_QUEUE_MASK & endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ mutex_unlock(&u132->scheduler_lock);
+ retval = edset_output(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_bulk_output_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ return;
+ }
+ }
+ }
}
#ifdef CONFIG_PM
static void port_power(struct u132 *u132, int pn, int is_on)
{
- u132->port[pn].power = is_on;
+ u132->port[pn].power = is_on;
}
#endif
static void u132_power(struct u132 *u132, int is_on)
{
- struct usb_hcd *hcd = u132_to_hcd(u132)
- ; /* hub is inactive unless the port is powered */
- if (is_on) {
- if (u132->power)
- return;
- u132->power = 1;
- hcd->self.controller->power.power_state = PMSG_ON;
- } else {
- u132->power = 0;
- hcd->state = HC_STATE_HALT;
- hcd->self.controller->power.power_state = PMSG_SUSPEND;
- }
+ struct usb_hcd *hcd = u132_to_hcd(u132)
+ ; /* hub is inactive unless the port is powered */
+ if (is_on) {
+ if (u132->power)
+ return;
+ u132->power = 1;
+ } else {
+ u132->power = 0;
+ hcd->state = HC_STATE_HALT;
+ }
}
static int u132_periodic_reinit(struct u132 *u132)
{
- int retval;
- u32 fi = u132->hc_fminterval & 0x03fff;
- u32 fit;
- u32 fminterval;
- retval = u132_read_pcimem(u132, fminterval, &fminterval);
- if (retval)
- return retval;
- fit = fminterval & FIT;
- retval = u132_write_pcimem(u132, fminterval,
- (fit ^ FIT) | u132->hc_fminterval);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, periodicstart,
- ((9 *fi) / 10) & 0x3fff);
- if (retval)
- return retval;
- return 0;
+ int retval;
+ u32 fi = u132->hc_fminterval & 0x03fff;
+ u32 fit;
+ u32 fminterval;
+ retval = u132_read_pcimem(u132, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ fit = fminterval & FIT;
+ retval = u132_write_pcimem(u132, fminterval,
+ (fit ^ FIT) | u132->hc_fminterval);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, periodicstart,
+ ((9 * fi) / 10) & 0x3fff);
+ if (retval)
+ return retval;
+ return 0;
}
static char *hcfs2string(int state)
{
- switch (state) {
- case OHCI_USB_RESET:
- return "reset";
- case OHCI_USB_RESUME:
- return "resume";
- case OHCI_USB_OPER:
- return "operational";
- case OHCI_USB_SUSPEND:
- return "suspend";
- }
- return "?";
+ switch (state) {
+ case OHCI_USB_RESET:
+ return "reset";
+ case OHCI_USB_RESUME:
+ return "resume";
+ case OHCI_USB_OPER:
+ return "operational";
+ case OHCI_USB_SUSPEND:
+ return "suspend";
+ }
+ return "?";
}
static int u132_init(struct u132 *u132)
{
- int retval;
- u32 control;
- u132_disable(u132);
- u132->next_statechange = jiffies;
- retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- if (u132->num_ports == 0) {
- u32 rh_a = -1;
- retval = u132_read_pcimem(u132, roothub.a, &rh_a);
- if (retval)
- return retval;
- u132->num_ports = rh_a & RH_A_NDP;
- retval = read_roothub_info(u132);
- if (retval)
- return retval;
- }
- if (u132->num_ports > MAX_U132_PORTS) {
- return -EINVAL;
- }
- return 0;
+ int retval;
+ u32 control;
+ u132_disable(u132);
+ u132->next_statechange = jiffies;
+ retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ if (u132->num_ports == 0) {
+ u32 rh_a = -1;
+ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ u132->num_ports = rh_a & RH_A_NDP;
+ retval = read_roothub_info(u132);
+ if (retval)
+ return retval;
+ }
+ if (u132->num_ports > MAX_U132_PORTS)
+ return -EINVAL;
+
+ return 0;
}
@@ -1613,280 +1603,278 @@ static int u132_init(struct u132 *u132)
*/
static int u132_run(struct u132 *u132)
{
- int retval;
- u32 control;
- u32 status;
- u32 fminterval;
- u32 periodicstart;
- u32 cmdstatus;
- u32 roothub_a;
- int mask = OHCI_INTR_INIT;
- int first = u132->hc_fminterval == 0;
- int sleep_time = 0;
- int reset_timeout = 30; /* ... allow extra time */
- u132_disable(u132);
- if (first) {
- u32 temp;
- retval = u132_read_pcimem(u132, fminterval, &temp);
- if (retval)
- return retval;
- u132->hc_fminterval = temp & 0x3fff;
- if (u132->hc_fminterval != FI) {
- }
- u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
- }
- retval = u132_read_pcimem(u132, control, &u132->hc_control);
- if (retval)
- return retval;
- dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
- "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
- u132->hc_control);
- switch (u132->hc_control & OHCI_CTRL_HCFS) {
- case OHCI_USB_OPER:
- sleep_time = 0;
- break;
- case OHCI_USB_SUSPEND:
- case OHCI_USB_RESUME:
- u132->hc_control &= OHCI_CTRL_RWC;
- u132->hc_control |= OHCI_USB_RESUME;
- sleep_time = 10;
- break;
- default:
- u132->hc_control &= OHCI_CTRL_RWC;
- u132->hc_control |= OHCI_USB_RESET;
- sleep_time = 50;
- break;
- }
- retval = u132_write_pcimem(u132, control, u132->hc_control);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- msleep(sleep_time);
- retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
- if (retval)
- return retval;
- if (!(roothub_a & RH_A_NPS)) {
- int temp; /* power down each port */
- for (temp = 0; temp < u132->num_ports; temp++) {
- retval = u132_write_pcimem(u132,
- roothub.portstatus[temp], RH_PS_LSDA);
- if (retval)
- return retval;
- }
- }
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- retry:retval = u132_read_pcimem(u132, cmdstatus, &status);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
- if (retval)
- return retval;
- extra:{
- retval = u132_read_pcimem(u132, cmdstatus, &status);
- if (retval)
- return retval;
- if (0 != (status & OHCI_HCR)) {
- if (--reset_timeout == 0) {
- dev_err(&u132->platform_dev->dev, "USB HC reset"
- " timed out!\n");
- return -ENODEV;
- } else {
- msleep(5);
- goto extra;
- }
- }
- }
- if (u132->flags & OHCI_QUIRK_INITRESET) {
- retval = u132_write_pcimem(u132, control, u132->hc_control);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- }
- retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, hcca, 0x00000000);
- if (retval)
- return retval;
- retval = u132_periodic_reinit(u132);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, fminterval, &fminterval);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
- if (retval)
- return retval;
- if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
- if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
- u132->flags |= OHCI_QUIRK_INITRESET;
- goto retry;
- } else
- dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
- "\n", fminterval, periodicstart);
- } /* start controller operations */
- u132->hc_control &= OHCI_CTRL_RWC;
- u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
- retval = u132_write_pcimem(u132, control, u132->hc_control);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- u132_to_hcd(u132)->state = HC_STATE_RUNNING;
- retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, intrstatus, mask);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, intrdisable,
- OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
- OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
- OHCI_INTR_SO);
- if (retval)
- return retval; /* handle root hub init quirks ... */
- retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
- if (retval)
- return retval;
- roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
- if (u132->flags & OHCI_QUIRK_SUPERIO) {
- roothub_a |= RH_A_NOCP;
- roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
- retval = u132_write_pcimem(u132, roothub.a, roothub_a);
- if (retval)
- return retval;
- } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
- roothub_a |= RH_A_NPS;
- retval = u132_write_pcimem(u132, roothub.a, roothub_a);
- if (retval)
- return retval;
- }
- retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
- if (retval)
- return retval;
- retval = u132_write_pcimem(u132, roothub.b,
- (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
- if (retval)
- return retval;
- retval = u132_read_pcimem(u132, control, &control);
- if (retval)
- return retval;
- mdelay((roothub_a >> 23) & 0x1fe);
- u132_to_hcd(u132)->state = HC_STATE_RUNNING;
- return 0;
+ int retval;
+ u32 control;
+ u32 status;
+ u32 fminterval;
+ u32 periodicstart;
+ u32 cmdstatus;
+ u32 roothub_a;
+ int mask = OHCI_INTR_INIT;
+ int first = u132->hc_fminterval == 0;
+ int sleep_time = 0;
+ int reset_timeout = 30; /* ... allow extra time */
+ u132_disable(u132);
+ if (first) {
+ u32 temp;
+ retval = u132_read_pcimem(u132, fminterval, &temp);
+ if (retval)
+ return retval;
+ u132->hc_fminterval = temp & 0x3fff;
+ u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
+ }
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval)
+ return retval;
+ dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
+ "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
+ u132->hc_control);
+ switch (u132->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ sleep_time = 0;
+ break;
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_USB_RESUME;
+ sleep_time = 10;
+ break;
+ default:
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_USB_RESET;
+ sleep_time = 50;
+ break;
+ }
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ msleep(sleep_time);
+ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ if (!(roothub_a & RH_A_NPS)) {
+ int temp; /* power down each port */
+ for (temp = 0; temp < u132->num_ports; temp++) {
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[temp], RH_PS_LSDA);
+ if (retval)
+ return retval;
+ }
+ }
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+retry:
+ retval = u132_read_pcimem(u132, cmdstatus, &status);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
+ if (retval)
+ return retval;
+extra: {
+ retval = u132_read_pcimem(u132, cmdstatus, &status);
+ if (retval)
+ return retval;
+ if (0 != (status & OHCI_HCR)) {
+ if (--reset_timeout == 0) {
+ dev_err(&u132->platform_dev->dev, "USB HC reset"
+ " timed out!\n");
+ return -ENODEV;
+ } else {
+ msleep(5);
+ goto extra;
+ }
+ }
+ }
+ if (u132->flags & OHCI_QUIRK_INITRESET) {
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ }
+ retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, hcca, 0x00000000);
+ if (retval)
+ return retval;
+ retval = u132_periodic_reinit(u132);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
+ if (retval)
+ return retval;
+ if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
+ if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
+ u132->flags |= OHCI_QUIRK_INITRESET;
+ goto retry;
+ } else
+ dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
+ "\n", fminterval, periodicstart);
+ } /* start controller operations */
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
+ retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, intrstatus, mask);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, intrdisable,
+ OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
+ OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
+ OHCI_INTR_SO);
+ if (retval)
+ return retval; /* handle root hub init quirks ... */
+ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
+ if (u132->flags & OHCI_QUIRK_SUPERIO) {
+ roothub_a |= RH_A_NOCP;
+ roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
+ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
+ roothub_a |= RH_A_NPS;
+ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ }
+ retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, roothub.b,
+ (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ mdelay((roothub_a >> 23) & 0x1fe);
+ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
+ return 0;
}
static void u132_hcd_stop(struct usb_hcd *hcd)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
- "een removed %d\n", u132, hcd, u132->going);
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
- "ed\n", hcd);
- } else {
- mutex_lock(&u132->sw_lock);
- msleep(100);
- u132_power(u132, 0);
- mutex_unlock(&u132->sw_lock);
- }
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
+ "een removed %d\n", u132, hcd, u132->going);
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
+ "ed\n", hcd);
+ } else {
+ mutex_lock(&u132->sw_lock);
+ msleep(100);
+ u132_power(u132, 0);
+ mutex_unlock(&u132->sw_lock);
+ }
}
static int u132_hcd_start(struct usb_hcd *hcd)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else if (hcd->self.controller) {
- int retval;
- struct platform_device *pdev =
- to_platform_device(hcd->self.controller);
- u16 vendor = ((struct u132_platform_data *)
- (pdev->dev.platform_data))->vendor;
- u16 device = ((struct u132_platform_data *)
- (pdev->dev.platform_data))->device;
- mutex_lock(&u132->sw_lock);
- msleep(10);
- if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
- u132->flags = OHCI_QUIRK_AMD756;
- } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
- dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
- "ounds unavailable\n");
- } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
- u132->flags |= OHCI_QUIRK_ZFMICRO;
- retval = u132_run(u132);
- if (retval) {
- u132_disable(u132);
- u132->going = 1;
- }
- msleep(100);
- mutex_unlock(&u132->sw_lock);
- return retval;
- } else {
- dev_err(&u132->platform_dev->dev, "platform_device missing\n");
- return -ENODEV;
- }
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else if (hcd->self.controller) {
+ int retval;
+ struct platform_device *pdev =
+ to_platform_device(hcd->self.controller);
+ u16 vendor = ((struct u132_platform_data *)
+ (pdev->dev.platform_data))->vendor;
+ u16 device = ((struct u132_platform_data *)
+ (pdev->dev.platform_data))->device;
+ mutex_lock(&u132->sw_lock);
+ msleep(10);
+ if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
+ u132->flags = OHCI_QUIRK_AMD756;
+ } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
+ dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
+ "ounds unavailable\n");
+ } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
+ u132->flags |= OHCI_QUIRK_ZFMICRO;
+ retval = u132_run(u132);
+ if (retval) {
+ u132_disable(u132);
+ u132->going = 1;
+ }
+ msleep(100);
+ mutex_unlock(&u132->sw_lock);
+ return retval;
+ } else {
+ dev_err(&u132->platform_dev->dev, "platform_device missing\n");
+ return -ENODEV;
+ }
}
static int u132_hcd_reset(struct usb_hcd *hcd)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval;
- mutex_lock(&u132->sw_lock);
- retval = u132_init(u132);
- if (retval) {
- u132_disable(u132);
- u132->going = 1;
- }
- mutex_unlock(&u132->sw_lock);
- return retval;
- }
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval;
+ mutex_lock(&u132->sw_lock);
+ retval = u132_init(u132);
+ if (retval) {
+ u132_disable(u132);
+ u132->going = 1;
+ }
+ mutex_unlock(&u132->sw_lock);
+ return retval;
+ }
}
static int create_endpoint_and_queue_int(struct u132 *u132,
struct u132_udev *udev, struct urb *urb,
- struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
- gfp_t mem_flags)
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
+ gfp_t mem_flags)
{
- struct u132_ring *ring;
- unsigned long irqs;
+ struct u132_ring *ring;
+ unsigned long irqs;
int rc;
u8 endp_number;
struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
- if (!endp) {
- return -ENOMEM;
- }
+ if (!endp)
+ return -ENOMEM;
spin_lock_init(&endp->queue_lock.slock);
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
@@ -1899,94 +1887,93 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
endp_number = ++u132->num_endpoints;
urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
- INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- INIT_LIST_HEAD(&endp->urb_more);
- ring = endp->ring = &u132->ring[0];
- if (ring->curr_endp) {
- list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
- } else {
- INIT_LIST_HEAD(&endp->endp_ring);
- ring->curr_endp = endp;
- }
- ring->length += 1;
- endp->dequeueing = 0;
- endp->edset_flush = 0;
- endp->active = 0;
- endp->delayed = 0;
- endp->endp_number = endp_number;
- endp->u132 = u132;
+ INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
+ INIT_LIST_HEAD(&endp->urb_more);
+ ring = endp->ring = &u132->ring[0];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
endp->hep = urb->ep;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_endp_init_kref(u132, endp);
- if (usb_pipein(urb->pipe)) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 0, 0);
- endp->input = 1;
- endp->output = 0;
- udev->endp_number_in[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 1, 0);
- endp->input = 0;
- endp->output = 1;
- udev->endp_number_out[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- }
- urb->hcpriv = u132;
- endp->delayed = 1;
- endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
- return 0;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_endp_init_kref(u132, endp);
+ if (usb_pipein(urb->pipe)) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
+ endp->input = 1;
+ endp->output = 0;
+ udev->endp_number_in[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
+ endp->input = 0;
+ endp->output = 1;
+ udev->endp_number_out[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ }
+ urb->hcpriv = u132;
+ endp->delayed = 1;
+ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
+ return 0;
}
static int queue_int_on_old_endpoint(struct u132 *u132,
struct u132_udev *udev, struct urb *urb,
- struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
- u8 usb_endp, u8 address)
-{
- urb->hcpriv = u132;
- endp->delayed = 1;
- endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more, &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp, u8 address)
+{
+ urb->hcpriv = u132;
+ endp->delayed = 1;
+ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
}
static int create_endpoint_and_queue_bulk(struct u132 *u132,
struct u132_udev *udev, struct urb *urb,
- struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
- gfp_t mem_flags)
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
+ gfp_t mem_flags)
{
- int ring_number;
- struct u132_ring *ring;
- unsigned long irqs;
+ int ring_number;
+ struct u132_ring *ring;
+ unsigned long irqs;
int rc;
u8 endp_number;
struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
- if (!endp) {
- return -ENOMEM;
- }
+ if (!endp)
+ return -ENOMEM;
spin_lock_init(&endp->queue_lock.slock);
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
@@ -1999,91 +1986,90 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
endp_number = ++u132->num_endpoints;
urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
- INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- INIT_LIST_HEAD(&endp->urb_more);
- endp->dequeueing = 0;
- endp->edset_flush = 0;
- endp->active = 0;
- endp->delayed = 0;
- endp->endp_number = endp_number;
- endp->u132 = u132;
+ INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
+ INIT_LIST_HEAD(&endp->urb_more);
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
endp->hep = urb->ep;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_endp_init_kref(u132, endp);
- if (usb_pipein(urb->pipe)) {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 0, 0);
- ring_number = 3;
- endp->input = 1;
- endp->output = 0;
- udev->endp_number_in[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- } else {
- endp->toggle_bits = 0x2;
- usb_settoggle(udev->usb_device, usb_endp, 1, 0);
- ring_number = 2;
- endp->input = 0;
- endp->output = 1;
- udev->endp_number_out[usb_endp] = endp_number;
- u132_udev_get_kref(u132, udev);
- }
- ring = endp->ring = &u132->ring[ring_number - 1];
- if (ring->curr_endp) {
- list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
- } else {
- INIT_LIST_HEAD(&endp->endp_ring);
- ring->curr_endp = endp;
- }
- ring->length += 1;
- urb->hcpriv = u132;
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, 0);
- return 0;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_endp_init_kref(u132, endp);
+ if (usb_pipein(urb->pipe)) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
+ ring_number = 3;
+ endp->input = 1;
+ endp->output = 0;
+ udev->endp_number_in[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
+ ring_number = 2;
+ endp->input = 0;
+ endp->output = 1;
+ udev->endp_number_out[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ }
+ ring = endp->ring = &u132->ring[ring_number - 1];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ urb->hcpriv = u132;
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
}
static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
struct urb *urb,
- struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
- u8 usb_endp, u8 address)
-{
- urb->hcpriv = u132;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more, &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp, u8 address)
+{
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
}
static int create_endpoint_and_queue_control(struct u132 *u132,
struct urb *urb,
- struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
- gfp_t mem_flags)
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
+ gfp_t mem_flags)
{
- struct u132_ring *ring;
+ struct u132_ring *ring;
unsigned long irqs;
int rc;
u8 endp_number;
struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
- if (!endp) {
- return -ENOMEM;
- }
+ if (!endp)
+ return -ENOMEM;
spin_lock_init(&endp->queue_lock.slock);
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
@@ -2096,204 +2082,203 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
endp_number = ++u132->num_endpoints;
urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
- INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- INIT_LIST_HEAD(&endp->urb_more);
- ring = endp->ring = &u132->ring[0];
- if (ring->curr_endp) {
- list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
- } else {
- INIT_LIST_HEAD(&endp->endp_ring);
- ring->curr_endp = endp;
- }
- ring->length += 1;
- endp->dequeueing = 0;
- endp->edset_flush = 0;
- endp->active = 0;
- endp->delayed = 0;
- endp->endp_number = endp_number;
- endp->u132 = u132;
+ INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
+ INIT_LIST_HEAD(&endp->urb_more);
+ ring = endp->ring = &u132->ring[0];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
endp->hep = urb->ep;
- u132_endp_init_kref(u132, endp);
- u132_endp_get_kref(u132, endp);
- if (usb_addr == 0) {
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->input = 1;
- endp->output = 1;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_udev_init_kref(u132, udev);
- u132_udev_get_kref(u132, udev);
- udev->endp_number_in[usb_endp] = endp_number;
- udev->endp_number_out[usb_endp] = endp_number;
- urb->hcpriv = u132;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- } else { /*(usb_addr > 0) */
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- endp->udev_number = address;
- endp->usb_addr = usb_addr;
- endp->usb_endp = usb_endp;
- endp->input = 1;
- endp->output = 1;
- endp->pipetype = usb_pipetype(urb->pipe);
- u132_udev_get_kref(u132, udev);
- udev->enumeration = 2;
- udev->endp_number_in[usb_endp] = endp_number;
- udev->endp_number_out[usb_endp] = endp_number;
- urb->hcpriv = u132;
- endp->queue_size = 1;
- endp->queue_last = 0;
- endp->queue_next = 0;
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- }
+ u132_endp_init_kref(u132, endp);
+ u132_endp_get_kref(u132, endp);
+ if (usb_addr == 0) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->input = 1;
+ endp->output = 1;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_udev_init_kref(u132, udev);
+ u132_udev_get_kref(u132, udev);
+ udev->endp_number_in[usb_endp] = endp_number;
+ udev->endp_number_out[usb_endp] = endp_number;
+ urb->hcpriv = u132;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ } else { /*(usb_addr > 0) */
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->input = 1;
+ endp->output = 1;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_udev_get_kref(u132, udev);
+ udev->enumeration = 2;
+ udev->endp_number_in[usb_endp] = endp_number;
+ udev->endp_number_out[usb_endp] = endp_number;
+ urb->hcpriv = u132;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
}
static int queue_control_on_old_endpoint(struct u132 *u132,
struct urb *urb,
- struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
- u8 usb_endp)
-{
- if (usb_addr == 0) {
- if (usb_pipein(urb->pipe)) {
- urb->hcpriv = u132;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq =
- kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more,
- &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
- } else { /* usb_pipeout(urb->pipe) */
- struct u132_addr *addr = &u132->addr[usb_dev->devnum];
- int I = MAX_U132_UDEVS;
- int i = 0;
- while (--I > 0) {
- struct u132_udev *udev = &u132->udev[++i];
- if (udev->usb_device) {
- continue;
- } else {
- udev->enumeration = 1;
- u132->addr[0].address = i;
- endp->udev_number = i;
- udev->udev_number = i;
- udev->usb_addr = usb_dev->devnum;
- u132_udev_init_kref(u132, udev);
- udev->endp_number_in[usb_endp] =
- endp->endp_number;
- u132_udev_get_kref(u132, udev);
- udev->endp_number_out[usb_endp] =
- endp->endp_number;
- udev->usb_device = usb_dev;
- ((u8 *) (urb->setup_packet))[2] =
- addr->address = i;
- u132_udev_get_kref(u132, udev);
- break;
- }
- }
- if (I == 0) {
- dev_err(&u132->platform_dev->dev, "run out of d"
- "evice space\n");
- return -EINVAL;
- }
- urb->hcpriv = u132;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK &
- endp->queue_last++] = urb;
- } else {
- struct u132_urbq *urbq =
- kmalloc(sizeof(struct u132_urbq),
- GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more,
- &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
- }
- } else { /*(usb_addr > 0) */
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- urb->hcpriv = u132;
- if (udev->enumeration == 2) {
- } else
- udev->enumeration = 2;
- if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
- endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
- urb;
- } else {
- struct u132_urbq *urbq =
- kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
- if (urbq == NULL) {
- endp->queue_size -= 1;
- return -ENOMEM;
- } else {
- list_add_tail(&urbq->urb_more, &endp->urb_more);
- urbq->urb = urb;
- }
- }
- return 0;
- }
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp)
+{
+ if (usb_addr == 0) {
+ if (usb_pipein(urb->pipe)) {
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more,
+ &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ } else { /* usb_pipeout(urb->pipe) */
+ struct u132_addr *addr = &u132->addr[usb_dev->devnum];
+ int I = MAX_U132_UDEVS;
+ int i = 0;
+ while (--I > 0) {
+ struct u132_udev *udev = &u132->udev[++i];
+ if (udev->usb_device) {
+ continue;
+ } else {
+ udev->enumeration = 1;
+ u132->addr[0].address = i;
+ endp->udev_number = i;
+ udev->udev_number = i;
+ udev->usb_addr = usb_dev->devnum;
+ u132_udev_init_kref(u132, udev);
+ udev->endp_number_in[usb_endp] =
+ endp->endp_number;
+ u132_udev_get_kref(u132, udev);
+ udev->endp_number_out[usb_endp] =
+ endp->endp_number;
+ udev->usb_device = usb_dev;
+ ((u8 *) (urb->setup_packet))[2] =
+ addr->address = i;
+ u132_udev_get_kref(u132, udev);
+ break;
+ }
+ }
+ if (I == 0) {
+ dev_err(&u132->platform_dev->dev, "run out of d"
+ "evice space\n");
+ return -EINVAL;
+ }
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more,
+ &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ }
+ } else { /*(usb_addr > 0) */
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ urb->hcpriv = u132;
+ if (udev->enumeration != 2)
+ udev->enumeration = 2;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ }
}
static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (irqs_disabled()) {
- if (__GFP_WAIT & mem_flags) {
- printk(KERN_ERR "invalid context for function that migh"
- "t sleep\n");
- return -EINVAL;
- }
- }
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (irqs_disabled()) {
+ if (__GFP_WAIT & mem_flags) {
+ printk(KERN_ERR "invalid context for function that migh"
+ "t sleep\n");
+ return -EINVAL;
+ }
+ }
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
- return -ESHUTDOWN;
- } else {
- u8 usb_addr = usb_pipedevice(urb->pipe);
- u8 usb_endp = usb_pipeendpoint(urb->pipe);
- struct usb_device *usb_dev = urb->dev;
- if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = urb->ep->hcpriv;
- urb->actual_length = 0;
- if (endp) {
- unsigned long irqs;
- int retval;
- spin_lock_irqsave(&endp->queue_lock.slock,
- irqs);
+ return -ESHUTDOWN;
+ } else {
+ u8 usb_addr = usb_pipedevice(urb->pipe);
+ u8 usb_endp = usb_pipeendpoint(urb->pipe);
+ struct usb_device *usb_dev = urb->dev;
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ struct u132_endp *endp = urb->ep->hcpriv;
+ urb->actual_length = 0;
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval == 0) {
retval = queue_int_on_old_endpoint(
@@ -2303,39 +2288,39 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
address);
if (retval)
usb_hcd_unlink_urb_from_ep(
- hcd, urb);
+ hcd, urb);
}
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- if (retval) {
- return retval;
- } else {
- u132_endp_queue_work(u132, endp,
- msecs_to_jiffies(urb->interval))
- ;
- return 0;
- }
- } else if (u132->num_endpoints == MAX_U132_ENDPS) {
- return -EINVAL;
- } else { /*(endp == NULL) */
- return create_endpoint_and_queue_int(u132, udev,
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp,
+ msecs_to_jiffies(urb->interval))
+ ;
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else { /*(endp == NULL) */
+ return create_endpoint_and_queue_int(u132, udev,
urb, usb_dev, usb_addr,
usb_endp, address, mem_flags);
- }
- } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- dev_err(&u132->platform_dev->dev, "the hardware does no"
- "t support PIPE_ISOCHRONOUS\n");
- return -EINVAL;
- } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = urb->ep->hcpriv;
- urb->actual_length = 0;
- if (endp) {
- unsigned long irqs;
- int retval;
- spin_lock_irqsave(&endp->queue_lock.slock,
- irqs);
+ }
+ } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ dev_err(&u132->platform_dev->dev, "the hardware does no"
+ "t support PIPE_ISOCHRONOUS\n");
+ return -EINVAL;
+ } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ struct u132_endp *endp = urb->ep->hcpriv;
+ urb->actual_length = 0;
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval == 0) {
retval = queue_bulk_on_old_endpoint(
@@ -2345,46 +2330,46 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
address);
if (retval)
usb_hcd_unlink_urb_from_ep(
- hcd, urb);
+ hcd, urb);
+ }
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
}
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- if (retval) {
- return retval;
- } else {
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- }
- } else if (u132->num_endpoints == MAX_U132_ENDPS) {
- return -EINVAL;
- } else
- return create_endpoint_and_queue_bulk(u132,
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else
+ return create_endpoint_and_queue_bulk(u132,
udev, urb, usb_dev, usb_addr,
- usb_endp, address, mem_flags);
- } else {
- struct u132_endp *endp = urb->ep->hcpriv;
- u16 urb_size = 8;
- u8 *b = urb->setup_packet;
- int i = 0;
- char data[30 *3 + 4];
- char *d = data;
- int m = (sizeof(data) - 1) / 3;
- int l = 0;
- data[0] = 0;
- while (urb_size-- > 0) {
- if (i > m) {
- } else if (i++ < m) {
- int w = sprintf(d, " %02X", *b++);
- d += w;
- l += w;
- } else
- d += sprintf(d, " ..");
- }
- if (endp) {
- unsigned long irqs;
- int retval;
- spin_lock_irqsave(&endp->queue_lock.slock,
- irqs);
+ usb_endp, address, mem_flags);
+ } else {
+ struct u132_endp *endp = urb->ep->hcpriv;
+ u16 urb_size = 8;
+ u8 *b = urb->setup_packet;
+ int i = 0;
+ char data[30 * 3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int l = 0;
+ data[0] = 0;
+ while (urb_size-- > 0) {
+ if (i > m) {
+ } else if (i++ < m) {
+ int w = sprintf(d, " %02X", *b++);
+ d += w;
+ l += w;
+ } else
+ d += sprintf(d, " ..");
+ }
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval == 0) {
retval = queue_control_on_old_endpoint(
@@ -2395,267 +2380,267 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
usb_hcd_unlink_urb_from_ep(
hcd, urb);
}
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- if (retval) {
- return retval;
- } else {
- u132_endp_queue_work(u132, endp, 0);
- return 0;
- }
- } else if (u132->num_endpoints == MAX_U132_ENDPS) {
- return -EINVAL;
- } else
- return create_endpoint_and_queue_control(u132,
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else
+ return create_endpoint_and_queue_control(u132,
urb, usb_dev, usb_addr, usb_endp,
- mem_flags);
- }
- }
+ mem_flags);
+ }
+ }
}
static int dequeue_from_overflow_chain(struct u132 *u132,
- struct u132_endp *endp, struct urb *urb)
-{
- struct list_head *scan;
- struct list_head *head = &endp->urb_more;
- list_for_each(scan, head) {
- struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
- urb_more);
- if (urbq->urb == urb) {
- struct usb_hcd *hcd = u132_to_hcd(u132);
- list_del(scan);
- endp->queue_size -= 1;
- urb->error_count = 0;
+ struct u132_endp *endp, struct urb *urb)
+{
+ struct list_head *scan;
+ struct list_head *head = &endp->urb_more;
+ list_for_each(scan, head) {
+ struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
+ urb_more);
+ if (urbq->urb == urb) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ list_del(scan);
+ endp->queue_size -= 1;
+ urb->error_count = 0;
usb_hcd_giveback_urb(hcd, urb, 0);
- return 0;
- } else
- continue;
- }
- dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
- "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
- "\n", urb, endp->endp_number, endp, endp->ring->number,
- endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
- endp->usb_endp, endp->usb_addr, endp->queue_size,
- endp->queue_next, endp->queue_last);
- return -EINVAL;
+ return 0;
+ } else
+ continue;
+ }
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
+ "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
+ "\n", urb, endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
+ endp->usb_endp, endp->usb_addr, endp->queue_size,
+ endp->queue_next, endp->queue_last);
+ return -EINVAL;
}
static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
struct urb *urb, int status)
{
- unsigned long irqs;
+ unsigned long irqs;
int rc;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
if (rc) {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return rc;
}
- if (endp->queue_size == 0) {
- dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
- "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
- endp->endp_number, endp, endp->ring->number,
- endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
- endp->usb_endp, endp->usb_addr);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return -EINVAL;
- }
- if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
- if (endp->active) {
- endp->dequeueing = 1;
- endp->edset_flush = 1;
- u132_endp_queue_work(u132, endp, 0);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return 0;
- } else {
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ if (endp->queue_size == 0) {
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
+ "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
+ endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
+ endp->usb_endp, endp->usb_addr);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return -EINVAL;
+ }
+ if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
+ if (endp->active) {
+ endp->dequeueing = 1;
+ endp->edset_flush = 1;
+ u132_endp_queue_work(u132, endp, 0);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return 0;
+ } else {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
u132_hcd_abandon_urb(u132, endp, urb, status);
- return 0;
- }
- } else {
- u16 queue_list = 0;
- u16 queue_size = endp->queue_size;
- u16 queue_scan = endp->queue_next;
- struct urb **urb_slot = NULL;
- while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
- if (urb == endp->urb_list[ENDP_QUEUE_MASK &
- ++queue_scan]) {
- urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
- queue_scan];
- break;
- } else
- continue;
- }
- while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
- *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
- ++queue_scan];
- urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
- queue_scan];
- }
- if (urb_slot) {
- struct usb_hcd *hcd = u132_to_hcd(u132);
+ return 0;
+ }
+ } else {
+ u16 queue_list = 0;
+ u16 queue_size = endp->queue_size;
+ u16 queue_scan = endp->queue_next;
+ struct urb **urb_slot = NULL;
+ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
+ if (urb == endp->urb_list[ENDP_QUEUE_MASK &
+ ++queue_scan]) {
+ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
+ queue_scan];
+ break;
+ } else
+ continue;
+ }
+ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
+ *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
+ ++queue_scan];
+ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
+ queue_scan];
+ }
+ if (urb_slot) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
usb_hcd_unlink_urb_from_ep(hcd, urb);
- endp->queue_size -= 1;
- if (list_empty(&endp->urb_more)) {
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- } else {
- struct list_head *next = endp->urb_more.next;
- struct u132_urbq *urbq = list_entry(next,
- struct u132_urbq, urb_more);
- list_del(next);
- *urb_slot = urbq->urb;
- spin_unlock_irqrestore(&endp->queue_lock.slock,
- irqs);
- kfree(urbq);
- } urb->error_count = 0;
+ endp->queue_size -= 1;
+ if (list_empty(&endp->urb_more)) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next,
+ struct u132_urbq, urb_more);
+ list_del(next);
+ *urb_slot = urbq->urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ kfree(urbq);
+ } urb->error_count = 0;
usb_hcd_giveback_urb(hcd, urb, status);
- return 0;
- } else if (list_empty(&endp->urb_more)) {
- dev_err(&u132->platform_dev->dev, "urb=%p not found in "
- "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
- "=%d size=%d next=%04X last=%04X\n", urb,
- endp->endp_number, endp, endp->ring->number,
- endp->input ? 'I' : ' ',
- endp->output ? 'O' : ' ', endp->usb_endp,
- endp->usb_addr, endp->queue_size,
- endp->queue_next, endp->queue_last);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return -EINVAL;
- } else {
+ return 0;
+ } else if (list_empty(&endp->urb_more)) {
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in "
+ "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
+ "=%d size=%d next=%04X last=%04X\n", urb,
+ endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ',
+ endp->output ? 'O' : ' ', endp->usb_endp,
+ endp->usb_addr, endp->queue_size,
+ endp->queue_next, endp->queue_last);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return -EINVAL;
+ } else {
int retval;
usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
retval = dequeue_from_overflow_chain(u132, endp,
- urb);
- spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- return retval;
- }
- }
+ urb);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return retval;
+ }
+ }
}
static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 2) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else {
- u8 usb_addr = usb_pipedevice(urb->pipe);
- u8 usb_endp = usb_pipeendpoint(urb->pipe);
- u8 address = u132->addr[usb_addr].address;
- struct u132_udev *udev = &u132->udev[address];
- if (usb_pipein(urb->pipe)) {
- u8 endp_number = udev->endp_number_in[usb_endp];
- struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb, status);
- } else {
- u8 endp_number = udev->endp_number_out[usb_endp];
- struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb, status);
- }
- }
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 2) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else {
+ u8 usb_addr = usb_pipedevice(urb->pipe);
+ u8 usb_endp = usb_pipeendpoint(urb->pipe);
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ if (usb_pipein(urb->pipe)) {
+ u8 endp_number = udev->endp_number_in[usb_endp];
+ struct u132_endp *endp = u132->endp[endp_number - 1];
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
+ } else {
+ u8 endp_number = udev->endp_number_out[usb_endp];
+ struct u132_endp *endp = u132->endp[endp_number - 1];
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
+ }
+ }
}
static void u132_endpoint_disable(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 2) {
- dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
- ") has been removed %d\n", u132, hcd, hep,
- u132->going);
- } else {
- struct u132_endp *endp = hep->hcpriv;
- if (endp)
- u132_endp_put_kref(u132, endp);
- }
+ struct usb_host_endpoint *hep)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 2) {
+ dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
+ ") has been removed %d\n", u132, hcd, hep,
+ u132->going);
+ } else {
+ struct u132_endp *endp = hep->hcpriv;
+ if (endp)
+ u132_endp_put_kref(u132, endp);
+ }
}
static int u132_get_frame(struct usb_hcd *hcd)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int frame = 0;
- dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
- msleep(100);
- return frame;
- }
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int frame = 0;
+ dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
+ msleep(100);
+ return frame;
+ }
}
static int u132_roothub_descriptor(struct u132 *u132,
- struct usb_hub_descriptor *desc)
-{
- int retval;
- u16 temp;
- u32 rh_a = -1;
- u32 rh_b = -1;
- retval = u132_read_pcimem(u132, roothub.a, &rh_a);
- if (retval)
- return retval;
- desc->bDescriptorType = 0x29;
- desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
- desc->bHubContrCurrent = 0;
- desc->bNbrPorts = u132->num_ports;
- temp = 1 + (u132->num_ports / 8);
- desc->bDescLength = 7 + 2 *temp;
- temp = 0;
- if (rh_a & RH_A_NPS)
- temp |= 0x0002;
- if (rh_a & RH_A_PSM)
- temp |= 0x0001;
- if (rh_a & RH_A_NOCP) {
- temp |= 0x0010;
- } else if (rh_a & RH_A_OCPM)
- temp |= 0x0008;
- desc->wHubCharacteristics = cpu_to_le16(temp);
- retval = u132_read_pcimem(u132, roothub.b, &rh_b);
- if (retval)
- return retval;
- memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
- desc->bitmap[0] = rh_b & RH_B_DR;
- if (u132->num_ports > 7) {
- desc->bitmap[1] = (rh_b & RH_B_DR) >> 8;
- desc->bitmap[2] = 0xff;
- } else
- desc->bitmap[1] = 0xff;
- return 0;
+ struct usb_hub_descriptor *desc)
+{
+ int retval;
+ u16 temp;
+ u32 rh_a = -1;
+ u32 rh_b = -1;
+ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
+ desc->bHubContrCurrent = 0;
+ desc->bNbrPorts = u132->num_ports;
+ temp = 1 + (u132->num_ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+ temp = 0;
+ if (rh_a & RH_A_NPS)
+ temp |= 0x0002;
+ if (rh_a & RH_A_PSM)
+ temp |= 0x0001;
+ if (rh_a & RH_A_NOCP)
+ temp |= 0x0010;
+ else if (rh_a & RH_A_OCPM)
+ temp |= 0x0008;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+ retval = u132_read_pcimem(u132, roothub.b, &rh_b);
+ if (retval)
+ return retval;
+ memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
+ desc->bitmap[0] = rh_b & RH_B_DR;
+ if (u132->num_ports > 7) {
+ desc->bitmap[1] = (rh_b & RH_B_DR) >> 8;
+ desc->bitmap[2] = 0xff;
+ } else
+ desc->bitmap[1] = 0xff;
+ return 0;
}
static int u132_roothub_status(struct u132 *u132, __le32 *desc)
{
- u32 rh_status = -1;
- int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
- *desc = cpu_to_le32(rh_status);
- return ret_status;
+ u32 rh_status = -1;
+ int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
+ *desc = cpu_to_le32(rh_status);
+ return ret_status;
}
static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
{
- if (wIndex == 0 || wIndex > u132->num_ports) {
- return -EINVAL;
- } else {
- int port = wIndex - 1;
- u32 rh_portstatus = -1;
- int ret_portstatus = u132_read_pcimem(u132,
- roothub.portstatus[port], &rh_portstatus);
- *desc = cpu_to_le32(rh_portstatus);
- if (*(u16 *) (desc + 2)) {
- dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
- "ge = %08X\n", port, *desc);
- }
- return ret_portstatus;
- }
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int port = wIndex - 1;
+ u32 rh_portstatus = -1;
+ int ret_portstatus = u132_read_pcimem(u132,
+ roothub.portstatus[port], &rh_portstatus);
+ *desc = cpu_to_le32(rh_portstatus);
+ if (*(u16 *) (desc + 2)) {
+ dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
+ "ge = %08X\n", port, *desc);
+ }
+ return ret_portstatus;
+ }
}
@@ -2666,381 +2651,340 @@ static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
static int u132_roothub_portreset(struct u132 *u132, int port_index)
{
- int retval;
- u32 fmnumber;
- u16 now;
- u16 reset_done;
- retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
- if (retval)
- return retval;
- now = fmnumber;
- reset_done = now + PORT_RESET_MSEC;
- do {
- u32 portstat;
- do {
- retval = u132_read_pcimem(u132,
- roothub.portstatus[port_index], &portstat);
- if (retval)
- return retval;
- if (RH_PS_PRS & portstat) {
- continue;
- } else
- break;
- } while (tick_before(now, reset_done));
- if (RH_PS_PRS & portstat)
- return -ENODEV;
- if (RH_PS_CCS & portstat) {
- if (RH_PS_PRSC & portstat) {
- retval = u132_write_pcimem(u132,
- roothub.portstatus[port_index],
- RH_PS_PRSC);
- if (retval)
- return retval;
- }
- } else
- break; /* start the next reset,
- sleep till it's probably done */
- retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
- RH_PS_PRS);
- if (retval)
- return retval;
- msleep(PORT_RESET_HW_MSEC);
- retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
- if (retval)
- return retval;
- now = fmnumber;
- } while (tick_before(now, reset_done));
- return 0;
+ int retval;
+ u32 fmnumber;
+ u16 now;
+ u16 reset_done;
+ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
+ if (retval)
+ return retval;
+ now = fmnumber;
+ reset_done = now + PORT_RESET_MSEC;
+ do {
+ u32 portstat;
+ do {
+ retval = u132_read_pcimem(u132,
+ roothub.portstatus[port_index], &portstat);
+ if (retval)
+ return retval;
+ if (RH_PS_PRS & portstat)
+ continue;
+ else
+ break;
+ } while (tick_before(now, reset_done));
+ if (RH_PS_PRS & portstat)
+ return -ENODEV;
+ if (RH_PS_CCS & portstat) {
+ if (RH_PS_PRSC & portstat) {
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index],
+ RH_PS_PRSC);
+ if (retval)
+ return retval;
+ }
+ } else
+ break; /* start the next reset,
+ sleep till it's probably done */
+ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
+ RH_PS_PRS);
+ if (retval)
+ return retval;
+ msleep(PORT_RESET_HW_MSEC);
+ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
+ if (retval)
+ return retval;
+ now = fmnumber;
+ } while (tick_before(now, reset_done));
+ return 0;
}
static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
- u16 wIndex)
-{
- if (wIndex == 0 || wIndex > u132->num_ports) {
- return -EINVAL;
- } else {
- int retval;
- int port_index = wIndex - 1;
- struct u132_port *port = &u132->port[port_index];
- port->Status &= ~(1 << wValue);
- switch (wValue) {
- case USB_PORT_FEAT_SUSPEND:
- retval = u132_write_pcimem(u132,
- roothub.portstatus[port_index], RH_PS_PSS);
- if (retval)
- return retval;
- return 0;
- case USB_PORT_FEAT_POWER:
- retval = u132_write_pcimem(u132,
- roothub.portstatus[port_index], RH_PS_PPS);
- if (retval)
- return retval;
- return 0;
- case USB_PORT_FEAT_RESET:
- retval = u132_roothub_portreset(u132, port_index);
- if (retval)
- return retval;
- return 0;
- default:
- return -EPIPE;
- }
- }
+ u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int retval;
+ int port_index = wIndex - 1;
+ struct u132_port *port = &u132->port[port_index];
+ port->Status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index], RH_PS_PSS);
+ if (retval)
+ return retval;
+ return 0;
+ case USB_PORT_FEAT_POWER:
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index], RH_PS_PPS);
+ if (retval)
+ return retval;
+ return 0;
+ case USB_PORT_FEAT_RESET:
+ retval = u132_roothub_portreset(u132, port_index);
+ if (retval)
+ return retval;
+ return 0;
+ default:
+ return -EPIPE;
+ }
+ }
}
static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
- u16 wIndex)
-{
- if (wIndex == 0 || wIndex > u132->num_ports) {
- return -EINVAL;
- } else {
- int port_index = wIndex - 1;
- u32 temp;
- int retval;
- struct u132_port *port = &u132->port[port_index];
- port->Status &= ~(1 << wValue);
- switch (wValue) {
- case USB_PORT_FEAT_ENABLE:
- temp = RH_PS_CCS;
- break;
- case USB_PORT_FEAT_C_ENABLE:
- temp = RH_PS_PESC;
- break;
- case USB_PORT_FEAT_SUSPEND:
- temp = RH_PS_POCI;
- if ((u132->hc_control & OHCI_CTRL_HCFS)
- != OHCI_USB_OPER) {
- dev_err(&u132->platform_dev->dev, "TODO resume_"
- "root_hub\n");
- }
- break;
- case USB_PORT_FEAT_C_SUSPEND:
- temp = RH_PS_PSSC;
- break;
- case USB_PORT_FEAT_POWER:
- temp = RH_PS_LSDA;
- break;
- case USB_PORT_FEAT_C_CONNECTION:
- temp = RH_PS_CSC;
- break;
- case USB_PORT_FEAT_C_OVER_CURRENT:
- temp = RH_PS_OCIC;
- break;
- case USB_PORT_FEAT_C_RESET:
- temp = RH_PS_PRSC;
- break;
- default:
- return -EPIPE;
- }
- retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
- temp);
- if (retval)
- return retval;
- return 0;
- }
+ u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int port_index = wIndex - 1;
+ u32 temp;
+ int retval;
+ struct u132_port *port = &u132->port[port_index];
+ port->Status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ temp = RH_PS_CCS;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ temp = RH_PS_PESC;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ temp = RH_PS_POCI;
+ if ((u132->hc_control & OHCI_CTRL_HCFS)
+ != OHCI_USB_OPER) {
+ dev_err(&u132->platform_dev->dev, "TODO resume_"
+ "root_hub\n");
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ temp = RH_PS_PSSC;
+ break;
+ case USB_PORT_FEAT_POWER:
+ temp = RH_PS_LSDA;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ temp = RH_PS_CSC;
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ temp = RH_PS_OCIC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ temp = RH_PS_PRSC;
+ break;
+ default:
+ return -EPIPE;
+ }
+ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
+ temp);
+ if (retval)
+ return retval;
+ return 0;
+ }
}
/* the virtual root hub timer IRQ checks for hub status*/
static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
- "ed %d\n", hcd, u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
- "ed\n", hcd);
- return -ESHUTDOWN;
- } else {
- int i, changed = 0, length = 1;
- if (u132->flags & OHCI_QUIRK_AMD756) {
- if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
- dev_err(&u132->platform_dev->dev, "bogus NDP, r"
- "ereads as NDP=%d\n",
- u132->hc_roothub_a & RH_A_NDP);
- goto done;
- }
- }
- if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) {
- buf[0] = changed = 1;
- } else
- buf[0] = 0;
- if (u132->num_ports > 7) {
- buf[1] = 0;
- length++;
- }
- for (i = 0; i < u132->num_ports; i++) {
- if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
- RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
- RH_PS_PRSC)) {
- changed = 1;
- if (i < 7) {
- buf[0] |= 1 << (i + 1);
- } else
- buf[1] |= 1 << (i - 7);
- continue;
- }
- if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) {
- continue;
- }
- if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) {
- continue;
- }
- }
- done:return changed ? length : 0;
- }
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
+ "ed %d\n", hcd, u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
+ "ed\n", hcd);
+ return -ESHUTDOWN;
+ } else {
+ int i, changed = 0, length = 1;
+ if (u132->flags & OHCI_QUIRK_AMD756) {
+ if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
+ dev_err(&u132->platform_dev->dev, "bogus NDP, r"
+ "ereads as NDP=%d\n",
+ u132->hc_roothub_a & RH_A_NDP);
+ goto done;
+ }
+ }
+ if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC))
+ buf[0] = changed = 1;
+ else
+ buf[0] = 0;
+ if (u132->num_ports > 7) {
+ buf[1] = 0;
+ length++;
+ }
+ for (i = 0; i < u132->num_ports; i++) {
+ if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
+ RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
+ RH_PS_PRSC)) {
+ changed = 1;
+ if (i < 7)
+ buf[0] |= 1 << (i + 1);
+ else
+ buf[1] |= 1 << (i - 7);
+ continue;
+ }
+ if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS))
+ continue;
+
+ if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS))
+ continue;
+ }
+done:
+ return changed ? length : 0;
+ }
}
static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
- u16 wIndex, char *buf, u16 wLength)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval = 0;
- mutex_lock(&u132->sw_lock);
- switch (typeReq) {
- case ClearHubFeature:
- switch (wValue) {
- case C_HUB_OVER_CURRENT:
- case C_HUB_LOCAL_POWER:
- break;
- default:
- goto stall;
- }
- break;
- case SetHubFeature:
- switch (wValue) {
- case C_HUB_OVER_CURRENT:
- case C_HUB_LOCAL_POWER:
- break;
- default:
- goto stall;
- }
- break;
- case ClearPortFeature:{
- retval = u132_roothub_clearportfeature(u132,
- wValue, wIndex);
- if (retval)
- goto error;
- break;
- }
- case GetHubDescriptor:{
- retval = u132_roothub_descriptor(u132,
- (struct usb_hub_descriptor *)buf);
- if (retval)
- goto error;
- break;
- }
- case GetHubStatus:{
- retval = u132_roothub_status(u132,
- (__le32 *) buf);
- if (retval)
- goto error;
- break;
- }
- case GetPortStatus:{
- retval = u132_roothub_portstatus(u132,
- (__le32 *) buf, wIndex);
- if (retval)
- goto error;
- break;
- }
- case SetPortFeature:{
- retval = u132_roothub_setportfeature(u132,
- wValue, wIndex);
- if (retval)
- goto error;
- break;
- }
- default:
- goto stall;
- error:u132_disable(u132);
- u132->going = 1;
- break;
- stall:retval = -EPIPE;
- break;
- }
- mutex_unlock(&u132->sw_lock);
- return retval;
- }
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ mutex_lock(&u132->sw_lock);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto stall;
+ }
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto stall;
+ }
+ break;
+ case ClearPortFeature:{
+ retval = u132_roothub_clearportfeature(u132,
+ wValue, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetHubDescriptor:{
+ retval = u132_roothub_descriptor(u132,
+ (struct usb_hub_descriptor *)buf);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetHubStatus:{
+ retval = u132_roothub_status(u132,
+ (__le32 *) buf);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetPortStatus:{
+ retval = u132_roothub_portstatus(u132,
+ (__le32 *) buf, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ case SetPortFeature:{
+ retval = u132_roothub_setportfeature(u132,
+ wValue, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ default:
+ goto stall;
+ error:
+ u132_disable(u132);
+ u132->going = 1;
+ break;
+ stall:
+ retval = -EPIPE;
+ break;
+ }
+ mutex_unlock(&u132->sw_lock);
+ return retval;
+ }
}
static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
-}
-
-static void u132_hub_irq_enable(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- } else if (u132->going > 0)
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
}
#ifdef CONFIG_PM
-static int u132_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
-}
-
-static int u132_hcd_resume(struct usb_hcd *hcd)
-{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
-}
-
static int u132_bus_suspend(struct usb_hcd *hcd)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
}
static int u132_bus_resume(struct usb_hcd *hcd)
{
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else
- return 0;
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
}
#else
-#define u132_hcd_suspend NULL
-#define u132_hcd_resume NULL
#define u132_bus_suspend NULL
#define u132_bus_resume NULL
#endif
static struct hc_driver u132_hc_driver = {
- .description = hcd_name,
- .hcd_priv_size = sizeof(struct u132),
- .irq = NULL,
- .flags = HCD_USB11 | HCD_MEMORY,
- .reset = u132_hcd_reset,
- .start = u132_hcd_start,
- .suspend = u132_hcd_suspend,
- .resume = u132_hcd_resume,
- .stop = u132_hcd_stop,
- .urb_enqueue = u132_urb_enqueue,
- .urb_dequeue = u132_urb_dequeue,
- .endpoint_disable = u132_endpoint_disable,
- .get_frame_number = u132_get_frame,
- .hub_status_data = u132_hub_status_data,
- .hub_control = u132_hub_control,
- .bus_suspend = u132_bus_suspend,
- .bus_resume = u132_bus_resume,
- .start_port_reset = u132_start_port_reset,
- .hub_irq_enable = u132_hub_irq_enable,
+ .description = hcd_name,
+ .hcd_priv_size = sizeof(struct u132),
+ .irq = NULL,
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .reset = u132_hcd_reset,
+ .start = u132_hcd_start,
+ .stop = u132_hcd_stop,
+ .urb_enqueue = u132_urb_enqueue,
+ .urb_dequeue = u132_urb_dequeue,
+ .endpoint_disable = u132_endpoint_disable,
+ .get_frame_number = u132_get_frame,
+ .hub_status_data = u132_hub_status_data,
+ .hub_control = u132_hub_control,
+ .bus_suspend = u132_bus_suspend,
+ .bus_resume = u132_bus_resume,
+ .start_port_reset = u132_start_port_reset,
};
/*
@@ -3051,148 +2995,152 @@ static struct hc_driver u132_hc_driver = {
*/
static int __devexit u132_remove(struct platform_device *pdev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- if (hcd) {
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going++ > 1) {
- dev_err(&u132->platform_dev->dev, "already being remove"
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ if (hcd) {
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going++ > 1) {
+ dev_err(&u132->platform_dev->dev, "already being remove"
"d\n");
- return -ENODEV;
- } else {
- int rings = MAX_U132_RINGS;
- int endps = MAX_U132_ENDPS;
- dev_err(&u132->platform_dev->dev, "removing device u132"
+ return -ENODEV;
+ } else {
+ int rings = MAX_U132_RINGS;
+ int endps = MAX_U132_ENDPS;
+ dev_err(&u132->platform_dev->dev, "removing device u132"
".%d\n", u132->sequence_num);
- msleep(100);
- mutex_lock(&u132->sw_lock);
- u132_monitor_cancel_work(u132);
- while (rings-- > 0) {
- struct u132_ring *ring = &u132->ring[rings];
- u132_ring_cancel_work(u132, ring);
- } while (endps-- > 0) {
- struct u132_endp *endp = u132->endp[endps];
- if (endp)
- u132_endp_cancel_work(u132, endp);
- }
- u132->going += 1;
- printk(KERN_INFO "removing device u132.%d\n",
- u132->sequence_num);
- mutex_unlock(&u132->sw_lock);
- usb_remove_hcd(hcd);
- u132_u132_put_kref(u132);
- return 0;
- }
- } else
- return 0;
+ msleep(100);
+ mutex_lock(&u132->sw_lock);
+ u132_monitor_cancel_work(u132);
+ while (rings-- > 0) {
+ struct u132_ring *ring = &u132->ring[rings];
+ u132_ring_cancel_work(u132, ring);
+ } while (endps-- > 0) {
+ struct u132_endp *endp = u132->endp[endps];
+ if (endp)
+ u132_endp_cancel_work(u132, endp);
+ }
+ u132->going += 1;
+ printk(KERN_INFO "removing device u132.%d\n",
+ u132->sequence_num);
+ mutex_unlock(&u132->sw_lock);
+ usb_remove_hcd(hcd);
+ u132_u132_put_kref(u132);
+ return 0;
+ }
+ } else
+ return 0;
}
static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
{
- int rings = MAX_U132_RINGS;
- int ports = MAX_U132_PORTS;
- int addrs = MAX_U132_ADDRS;
- int udevs = MAX_U132_UDEVS;
- int endps = MAX_U132_ENDPS;
- u132->board = pdev->dev.platform_data;
- u132->platform_dev = pdev;
- u132->power = 0;
- u132->reset = 0;
- mutex_init(&u132->sw_lock);
- init_MUTEX(&u132->scheduler_lock);
- while (rings-- > 0) {
- struct u132_ring *ring = &u132->ring[rings];
- ring->u132 = u132;
- ring->number = rings + 1;
- ring->length = 0;
- ring->curr_endp = NULL;
- INIT_DELAYED_WORK(&ring->scheduler,
+ int rings = MAX_U132_RINGS;
+ int ports = MAX_U132_PORTS;
+ int addrs = MAX_U132_ADDRS;
+ int udevs = MAX_U132_UDEVS;
+ int endps = MAX_U132_ENDPS;
+ u132->board = pdev->dev.platform_data;
+ u132->platform_dev = pdev;
+ u132->power = 0;
+ u132->reset = 0;
+ mutex_init(&u132->sw_lock);
+ mutex_init(&u132->scheduler_lock);
+ while (rings-- > 0) {
+ struct u132_ring *ring = &u132->ring[rings];
+ ring->u132 = u132;
+ ring->number = rings + 1;
+ ring->length = 0;
+ ring->curr_endp = NULL;
+ INIT_DELAYED_WORK(&ring->scheduler,
u132_hcd_ring_work_scheduler);
- } mutex_lock(&u132->sw_lock);
- INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
- while (ports-- > 0) {
- struct u132_port *port = &u132->port[ports];
- port->u132 = u132;
- port->reset = 0;
- port->enable = 0;
- port->power = 0;
- port->Status = 0;
- } while (addrs-- > 0) {
- struct u132_addr *addr = &u132->addr[addrs];
- addr->address = 0;
- } while (udevs-- > 0) {
- struct u132_udev *udev = &u132->udev[udevs];
- int i = ARRAY_SIZE(udev->endp_number_in);
- int o = ARRAY_SIZE(udev->endp_number_out);
- udev->usb_device = NULL;
- udev->udev_number = 0;
- udev->usb_addr = 0;
- udev->portnumber = 0;
- while (i-- > 0) {
- udev->endp_number_in[i] = 0;
- }
- while (o-- > 0) {
- udev->endp_number_out[o] = 0;
- }
- }
- while (endps-- > 0) {
- u132->endp[endps] = NULL;
- }
- mutex_unlock(&u132->sw_lock);
- return;
+ }
+ mutex_lock(&u132->sw_lock);
+ INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
+ while (ports-- > 0) {
+ struct u132_port *port = &u132->port[ports];
+ port->u132 = u132;
+ port->reset = 0;
+ port->enable = 0;
+ port->power = 0;
+ port->Status = 0;
+ }
+ while (addrs-- > 0) {
+ struct u132_addr *addr = &u132->addr[addrs];
+ addr->address = 0;
+ }
+ while (udevs-- > 0) {
+ struct u132_udev *udev = &u132->udev[udevs];
+ int i = ARRAY_SIZE(udev->endp_number_in);
+ int o = ARRAY_SIZE(udev->endp_number_out);
+ udev->usb_device = NULL;
+ udev->udev_number = 0;
+ udev->usb_addr = 0;
+ udev->portnumber = 0;
+ while (i-- > 0)
+ udev->endp_number_in[i] = 0;
+
+ while (o-- > 0)
+ udev->endp_number_out[o] = 0;
+
+ }
+ while (endps-- > 0)
+ u132->endp[endps] = NULL;
+
+ mutex_unlock(&u132->sw_lock);
+ return;
}
static int __devinit u132_probe(struct platform_device *pdev)
{
- struct usb_hcd *hcd;
- int retval;
- u32 control;
- u32 rh_a = -1;
- u32 num_ports;
- msleep(100);
- if (u132_exiting > 0) {
- return -ENODEV;
- }
- retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(pdev, control, &control);
- if (retval)
- return retval;
- retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
- if (retval)
- return retval;
- num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
- if (pdev->dev.dma_mask) {
- return -EINVAL;
- }
- hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id);
- if (!hcd) {
- printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
- );
- ftdi_elan_gone_away(pdev);
- return -ENOMEM;
- } else {
- int retval = 0;
- struct u132 *u132 = hcd_to_u132(hcd);
- hcd->rsrc_start = 0;
- mutex_lock(&u132_module_lock);
- list_add_tail(&u132->u132_list, &u132_static_list);
- u132->sequence_num = ++u132_instances;
- mutex_unlock(&u132_module_lock);
- u132_u132_init_kref(u132);
- u132_initialise(u132, pdev);
- hcd->product_desc = "ELAN U132 Host Controller";
- retval = usb_add_hcd(hcd, 0, 0);
- if (retval != 0) {
- dev_err(&u132->platform_dev->dev, "init error %d\n",
- retval);
- u132_u132_put_kref(u132);
- return retval;
- } else {
- u132_monitor_queue_work(u132, 100);
- return 0;
- }
- }
+ struct usb_hcd *hcd;
+ int retval;
+ u32 control;
+ u32 rh_a = -1;
+ u32 num_ports;
+
+ msleep(100);
+ if (u132_exiting > 0)
+ return -ENODEV;
+
+ retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(pdev, control, &control);
+ if (retval)
+ return retval;
+ retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
+ if (pdev->dev.dma_mask)
+ return -EINVAL;
+
+ hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
+ );
+ ftdi_elan_gone_away(pdev);
+ return -ENOMEM;
+ } else {
+ int retval = 0;
+ struct u132 *u132 = hcd_to_u132(hcd);
+ hcd->rsrc_start = 0;
+ mutex_lock(&u132_module_lock);
+ list_add_tail(&u132->u132_list, &u132_static_list);
+ u132->sequence_num = ++u132_instances;
+ mutex_unlock(&u132_module_lock);
+ u132_u132_init_kref(u132);
+ u132_initialise(u132, pdev);
+ hcd->product_desc = "ELAN U132 Host Controller";
+ retval = usb_add_hcd(hcd, 0, 0);
+ if (retval != 0) {
+ dev_err(&u132->platform_dev->dev, "init error %d\n",
+ retval);
+ u132_u132_put_kref(u132);
+ return retval;
+ } else {
+ u132_monitor_queue_work(u132, 100);
+ return 0;
+ }
+ }
}
@@ -3203,61 +3151,58 @@ static int __devinit u132_probe(struct platform_device *pdev)
*/
static int u132_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
int retval = 0, ports;
switch (state.event) {
case PM_EVENT_FREEZE:
- retval = u132_bus_suspend(hcd);
+ retval = u132_bus_suspend(hcd);
break;
case PM_EVENT_SUSPEND:
case PM_EVENT_HIBERNATE:
ports = MAX_U132_PORTS;
- while (ports-- > 0) {
- port_power(u132, ports, 0);
- }
+ while (ports-- > 0) {
+ port_power(u132, ports, 0);
+ }
break;
}
- if (retval == 0)
- pdev->dev.power.power_state = state;
- return retval;
- }
+ return retval;
+ }
}
static int u132_resume(struct platform_device *pdev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct u132 *u132 = hcd_to_u132(hcd);
- if (u132->going > 1) {
- dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
- , u132->going);
- return -ENODEV;
- } else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed\n");
- return -ESHUTDOWN;
- } else {
- int retval = 0;
- if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- int ports = MAX_U132_PORTS;
- while (ports-- > 0) {
- port_power(u132, ports, 1);
- }
- retval = 0;
- } else {
- pdev->dev.power.power_state = PMSG_ON;
- retval = u132_bus_resume(hcd);
- }
- return retval;
- }
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ if (!u132->port[0].power) {
+ int ports = MAX_U132_PORTS;
+ while (ports-- > 0) {
+ port_power(u132, ports, 1);
+ }
+ retval = 0;
+ } else {
+ retval = u132_bus_resume(hcd);
+ }
+ return retval;
+ }
}
#else
@@ -3270,47 +3215,48 @@ static int u132_resume(struct platform_device *pdev)
* the platform_driver struct is static because it is per type of module
*/
static struct platform_driver u132_platform_driver = {
- .probe = u132_probe,
- .remove = __devexit_p(u132_remove),
- .suspend = u132_suspend,
- .resume = u132_resume,
- .driver = {
- .name = (char *)hcd_name,
- .owner = THIS_MODULE,
- },
+ .probe = u132_probe,
+ .remove = __devexit_p(u132_remove),
+ .suspend = u132_suspend,
+ .resume = u132_resume,
+ .driver = {
+ .name = (char *)hcd_name,
+ .owner = THIS_MODULE,
+ },
};
static int __init u132_hcd_init(void)
{
- int retval;
- INIT_LIST_HEAD(&u132_static_list);
- u132_instances = 0;
- u132_exiting = 0;
- mutex_init(&u132_module_lock);
- if (usb_disabled())
- return -ENODEV;
- printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
- __DATE__);
- workqueue = create_singlethread_workqueue("u132");
- retval = platform_driver_register(&u132_platform_driver);
- return retval;
+ int retval;
+ INIT_LIST_HEAD(&u132_static_list);
+ u132_instances = 0;
+ u132_exiting = 0;
+ mutex_init(&u132_module_lock);
+ if (usb_disabled())
+ return -ENODEV;
+ printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
+ __DATE__);
+ workqueue = create_singlethread_workqueue("u132");
+ retval = platform_driver_register(&u132_platform_driver);
+ return retval;
}
module_init(u132_hcd_init);
static void __exit u132_hcd_exit(void)
{
- struct u132 *u132;
- struct u132 *temp;
- mutex_lock(&u132_module_lock);
- u132_exiting += 1;
- mutex_unlock(&u132_module_lock);
- list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
- platform_device_unregister(u132->platform_dev);
- } platform_driver_unregister(&u132_platform_driver);
- printk(KERN_INFO "u132-hcd driver deregistered\n");
- wait_event(u132_hcd_wait, u132_instances == 0);
- flush_workqueue(workqueue);
- destroy_workqueue(workqueue);
+ struct u132 *u132;
+ struct u132 *temp;
+ mutex_lock(&u132_module_lock);
+ u132_exiting += 1;
+ mutex_unlock(&u132_module_lock);
+ list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
+ platform_device_unregister(u132->platform_dev);
+ }
+ platform_driver_unregister(&u132_platform_driver);
+ printk(KERN_INFO "u132-hcd driver deregistered\n");
+ wait_event(u132_hcd_wait, u132_instances == 0);
+ flush_workqueue(workqueue);
+ destroy_workqueue(workqueue);
}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index ec987897b8ed..d3e0d8aa3980 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -262,20 +262,12 @@ __acquires(uhci->lock)
{
int auto_stop;
int int_enable, egsm_enable;
+ struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
- dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
- "%s%s\n", __FUNCTION__,
+ dev_dbg(&rhdev->dev, "%s%s\n", __func__,
(auto_stop ? " (auto-stop)" : ""));
- /* If we get a suspend request when we're already auto-stopped
- * then there's nothing to do.
- */
- if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
- uhci->rh_state = new_state;
- return;
- }
-
/* Enable resume-detect interrupts if they work.
* Then enter Global Suspend mode if _it_ works, still configured.
*/
@@ -285,8 +277,10 @@ __acquires(uhci->lock)
if (remote_wakeup_is_broken(uhci))
egsm_enable = 0;
if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
- !device_may_wakeup(
- &uhci_to_hcd(uhci)->self.root_hub->dev))
+#ifdef CONFIG_PM
+ (!auto_stop && !rhdev->do_remote_wakeup) ||
+#endif
+ (auto_stop && !device_may_wakeup(&rhdev->dev)))
uhci->working_RD = int_enable = 0;
outw(int_enable, uhci->io_addr + USBINTR);
@@ -308,8 +302,7 @@ __acquires(uhci->lock)
return;
}
if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
- dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev,
- "Controller not stopped yet!\n");
+ dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
uhci_get_current_frame_number(uhci);
@@ -342,7 +335,7 @@ __releases(uhci->lock)
__acquires(uhci->lock)
{
dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
- "%s%s\n", __FUNCTION__,
+ "%s%s\n", __func__,
uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
" (auto-start)" : "");
@@ -737,12 +730,12 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
return rc;
}
-static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
+static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int rc = 0;
- dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+ dev_dbg(uhci_dev(uhci), "%s\n", __func__);
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
@@ -774,11 +767,11 @@ done:
return rc;
}
-static int uhci_resume(struct usb_hcd *hcd)
+static int uhci_pci_resume(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+ dev_dbg(uhci_dev(uhci), "%s\n", __func__);
/* Since we aren't in D3 any more, it's safe to set this flag
* even if the controller was dead.
@@ -872,8 +865,8 @@ static const struct hc_driver uhci_driver = {
.reset = uhci_init,
.start = uhci_start,
#ifdef CONFIG_PM
- .suspend = uhci_suspend,
- .resume = uhci_resume,
+ .pci_suspend = uhci_pci_suspend,
+ .pci_resume = uhci_pci_resume,
.bus_suspend = uhci_rh_suspend,
.bus_resume = uhci_rh_resume,
#endif
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 60379b17bbc1..db645936eedd 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1171,7 +1171,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
/* Some debugging code */
dev_dbg(&urb->dev->dev,
"%s: failed with status %x\n",
- __FUNCTION__, status);
+ __func__, status);
if (debug > 1 && errbuf) {
/* Print the chain for debugging */
diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig
index 7595dfb38e3b..33350f9dd34f 100644
--- a/drivers/usb/image/Kconfig
+++ b/drivers/usb/image/Kconfig
@@ -5,8 +5,8 @@ comment "USB Imaging devices"
depends on USB
config USB_MDC800
- tristate "USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "USB Mustek MDC800 Digital Camera support"
+ depends on USB
---help---
Say Y here if you want to connect this type of still camera to
your computer's USB port. This driver can be used with gphoto 0.4.3
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index bc207e3c21f5..885867a86de8 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -185,7 +185,7 @@ static struct usb_driver mts_usb_driver = {
printk( KERN_DEBUG MTS_NAME x )
#define MTS_DEBUG_GOT_HERE() \
- MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ )
+ MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __func__ )
#define MTS_DEBUG_INT() \
do { MTS_DEBUG_GOT_HERE(); \
MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
@@ -794,7 +794,6 @@ static int mts_usb_probe(struct usb_interface *intf,
new_desc->usb_dev = dev;
new_desc->usb_intf = intf;
- init_MUTEX(&new_desc->lock);
/* endpoints */
new_desc->ep_out = ep_out;
diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
index d5d62a939058..ccce318f20a0 100644
--- a/drivers/usb/image/microtek.h
+++ b/drivers/usb/image/microtek.h
@@ -39,7 +39,6 @@ struct mts_desc {
u8 ep_image;
struct Scsi_Host * host;
- struct semaphore lock;
struct urb *urb;
struct mts_transfer_context context;
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 9c7eb6144d02..a53db1d4e07a 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -33,8 +33,8 @@ config USB_EMI26
module will be called emi26.
config USB_ADUTUX
- tristate "ADU devices from Ontrak Control Systems (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "ADU devices from Ontrak Control Systems"
+ depends on USB
help
Say Y if you want to use an ADU device from Ontrak Control
Systems.
@@ -43,8 +43,8 @@ config USB_ADUTUX
will be called adutux.
config USB_AUERSWALD
- tristate "USB Auerswald ISDN support (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "USB Auerswald ISDN support"
+ depends on USB
help
Say Y here if you want to connect an Auerswald USB ISDN Device
to your computer's USB port.
@@ -53,8 +53,8 @@ config USB_AUERSWALD
module will be called auerswald.
config USB_RIO500
- tristate "USB Diamond Rio500 support (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "USB Diamond Rio500 support"
+ depends on USB
help
Say Y here if you want to connect a USB Rio500 mp3 player to your
computer's USB port. Please read <file:Documentation/usb/rio.txt>
@@ -64,8 +64,8 @@ config USB_RIO500
module will be called rio500.
config USB_LEGOTOWER
- tristate "USB Lego Infrared Tower support (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "USB Lego Infrared Tower support"
+ depends on USB
help
Say Y here if you want to connect a USB Lego Infrared Tower to your
computer's USB port.
@@ -259,8 +259,8 @@ config USB_IOWARRIOR
module will be called iowarrior.
config USB_TEST
- tristate "USB testing driver (DEVELOPMENT)"
- depends on USB && USB_DEVICEFS && EXPERIMENTAL
+ tristate "USB testing driver"
+ depends on USB && USB_DEVICEFS
help
This driver is for testing host controller software. It is used
with specialized device firmware for regression and stress testing,
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 5a2c44e4c1f7..965f6eaea6a0 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -147,10 +147,10 @@ static void adu_abort_transfers(struct adu_device *dev)
{
unsigned long flags;
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
if (dev->udev == NULL) {
- dbg(1," %s : udev is null", __FUNCTION__);
+ dbg(1," %s : udev is null", __func__);
goto exit;
}
@@ -172,12 +172,12 @@ static void adu_abort_transfers(struct adu_device *dev)
spin_unlock_irqrestore(&dev->buflock, flags);
exit:
- dbg(2," %s : leave", __FUNCTION__);
+ dbg(2," %s : leave", __func__);
}
static void adu_delete(struct adu_device *dev)
{
- dbg(2, "%s enter", __FUNCTION__);
+ dbg(2, "%s enter", __func__);
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
@@ -188,7 +188,7 @@ static void adu_delete(struct adu_device *dev)
kfree(dev->interrupt_out_buffer);
kfree(dev);
- dbg(2, "%s : leave", __FUNCTION__);
+ dbg(2, "%s : leave", __func__);
}
static void adu_interrupt_in_callback(struct urb *urb)
@@ -196,8 +196,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
struct adu_device *dev = urb->context;
int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, status);
- adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ dbg(4," %s : enter, status %d", __func__, status);
+ adu_debug_data(5, __func__, urb->actual_length,
urb->transfer_buffer);
spin_lock(&dev->buflock);
@@ -206,7 +206,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
if ((status != -ENOENT) && (status != -ECONNRESET) &&
(status != -ESHUTDOWN)) {
dbg(1," %s : nonzero status received: %d",
- __FUNCTION__, status);
+ __func__, status);
}
goto exit;
}
@@ -220,10 +220,10 @@ static void adu_interrupt_in_callback(struct urb *urb)
dev->interrupt_in_buffer, urb->actual_length);
dev->read_buffer_length += urb->actual_length;
- dbg(2," %s reading %d ", __FUNCTION__,
+ dbg(2," %s reading %d ", __func__,
urb->actual_length);
} else {
- dbg(1," %s : read_buffer overflow", __FUNCTION__);
+ dbg(1," %s : read_buffer overflow", __func__);
}
}
@@ -232,9 +232,9 @@ exit:
spin_unlock(&dev->buflock);
/* always wake up so we recover from errors */
wake_up_interruptible(&dev->read_wait);
- adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ adu_debug_data(5, __func__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, status);
+ dbg(4," %s : leave, status %d", __func__, status);
}
static void adu_interrupt_out_callback(struct urb *urb)
@@ -242,14 +242,14 @@ static void adu_interrupt_out_callback(struct urb *urb)
struct adu_device *dev = urb->context;
int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, status);
- adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ dbg(4," %s : enter, status %d", __func__, status);
+ adu_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer);
if (status != 0) {
if ((status != -ENOENT) &&
(status != -ECONNRESET)) {
dbg(1, " %s :nonzero status received: %d",
- __FUNCTION__, status);
+ __func__, status);
}
goto exit;
}
@@ -260,9 +260,9 @@ static void adu_interrupt_out_callback(struct urb *urb)
spin_unlock(&dev->buflock);
exit:
- adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ adu_debug_data(5, __func__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, status);
+ dbg(4," %s : leave, status %d", __func__, status);
}
static int adu_open(struct inode *inode, struct file *file)
@@ -272,19 +272,19 @@ static int adu_open(struct inode *inode, struct file *file)
int subminor;
int retval;
- dbg(2,"%s : enter", __FUNCTION__);
+ dbg(2,"%s : enter", __func__);
subminor = iminor(inode);
if ((retval = mutex_lock_interruptible(&adutux_mutex))) {
- dbg(2, "%s : mutex lock failed", __FUNCTION__);
+ dbg(2, "%s : mutex lock failed", __func__);
goto exit_no_lock;
}
interface = usb_find_interface(&adu_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d",
- __FUNCTION__, subminor);
+ __func__, subminor);
retval = -ENODEV;
goto exit_no_device;
}
@@ -302,7 +302,7 @@ static int adu_open(struct inode *inode, struct file *file)
}
++dev->open_count;
- dbg(2,"%s : open count %d", __FUNCTION__, dev->open_count);
+ dbg(2,"%s : open count %d", __func__, dev->open_count);
/* save device in the file's private structure */
file->private_data = dev;
@@ -332,23 +332,23 @@ static int adu_open(struct inode *inode, struct file *file)
exit_no_device:
mutex_unlock(&adutux_mutex);
exit_no_lock:
- dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
+ dbg(2,"%s : leave, return value %d ", __func__, retval);
return retval;
}
static void adu_release_internal(struct adu_device *dev)
{
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
/* decrement our usage count for the device */
--dev->open_count;
- dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
+ dbg(2," %s : open count %d", __func__, dev->open_count);
if (dev->open_count <= 0) {
adu_abort_transfers(dev);
dev->open_count = 0;
}
- dbg(2," %s : leave", __FUNCTION__);
+ dbg(2," %s : leave", __func__);
}
static int adu_release(struct inode *inode, struct file *file)
@@ -356,17 +356,17 @@ static int adu_release(struct inode *inode, struct file *file)
struct adu_device *dev;
int retval = 0;
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
if (file == NULL) {
- dbg(1," %s : file is NULL", __FUNCTION__);
+ dbg(1," %s : file is NULL", __func__);
retval = -ENODEV;
goto exit;
}
dev = file->private_data;
if (dev == NULL) {
- dbg(1," %s : object is NULL", __FUNCTION__);
+ dbg(1," %s : object is NULL", __func__);
retval = -ENODEV;
goto exit;
}
@@ -374,7 +374,7 @@ static int adu_release(struct inode *inode, struct file *file)
mutex_lock(&adutux_mutex); /* not interruptible */
if (dev->open_count <= 0) {
- dbg(1," %s : device not opened", __FUNCTION__);
+ dbg(1," %s : device not opened", __func__);
retval = -ENODEV;
goto exit;
}
@@ -388,7 +388,7 @@ static int adu_release(struct inode *inode, struct file *file)
exit:
mutex_unlock(&adutux_mutex);
- dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ dbg(2," %s : leave, return value %d", __func__, retval);
return retval;
}
@@ -405,10 +405,10 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
- dbg(2," %s : enter, count = %Zd, file=%p", __FUNCTION__, count, file);
+ dbg(2," %s : enter, count = %Zd, file=%p", __func__, count, file);
dev = file->private_data;
- dbg(2," %s : dev=%p", __FUNCTION__, dev);
+ dbg(2," %s : dev=%p", __func__, dev);
if (mutex_lock_interruptible(&dev->mtx))
return -ERESTARTSYS;
@@ -422,16 +422,16 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
/* verify that some data was requested */
if (count == 0) {
- dbg(1," %s : read request of 0 bytes", __FUNCTION__);
+ dbg(1," %s : read request of 0 bytes", __func__);
goto exit;
}
timeout = COMMAND_TIMEOUT;
- dbg(2," %s : about to start looping", __FUNCTION__);
+ dbg(2," %s : about to start looping", __func__);
while (bytes_to_read) {
int data_in_secondary = dev->secondary_tail - dev->secondary_head;
dbg(2," %s : while, data_in_secondary=%d, status=%d",
- __FUNCTION__, data_in_secondary,
+ __func__, data_in_secondary,
dev->interrupt_in_urb->status);
if (data_in_secondary) {
@@ -456,7 +456,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
/* we secure access to the primary */
char *tmp;
dbg(2," %s : swap, read_buffer_length = %d",
- __FUNCTION__, dev->read_buffer_length);
+ __func__, dev->read_buffer_length);
tmp = dev->read_buffer_secondary;
dev->read_buffer_secondary = dev->read_buffer_primary;
dev->read_buffer_primary = tmp;
@@ -471,10 +471,10 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
if (!dev->read_urb_finished) {
/* somebody is doing IO */
spin_unlock_irqrestore(&dev->buflock, flags);
- dbg(2," %s : submitted already", __FUNCTION__);
+ dbg(2," %s : submitted already", __func__);
} else {
/* we must initiate input */
- dbg(2," %s : initiate input", __FUNCTION__);
+ dbg(2," %s : initiate input", __func__);
dev->read_urb_finished = 0;
spin_unlock_irqrestore(&dev->buflock, flags);
@@ -492,7 +492,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
if (retval == -ENOMEM) {
retval = bytes_read ? bytes_read : -ENOMEM;
}
- dbg(2," %s : submit failed", __FUNCTION__);
+ dbg(2," %s : submit failed", __func__);
goto exit;
}
}
@@ -511,13 +511,13 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
remove_wait_queue(&dev->read_wait, &wait);
if (timeout <= 0) {
- dbg(2," %s : timeout", __FUNCTION__);
+ dbg(2," %s : timeout", __func__);
retval = bytes_read ? bytes_read : -ETIMEDOUT;
goto exit;
}
if (signal_pending(current)) {
- dbg(2," %s : signal pending", __FUNCTION__);
+ dbg(2," %s : signal pending", __func__);
retval = bytes_read ? bytes_read : -EINTR;
goto exit;
}
@@ -550,7 +550,7 @@ exit:
/* unlock the device */
mutex_unlock(&dev->mtx);
- dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ dbg(2," %s : leave, return value %d", __func__, retval);
return retval;
}
@@ -565,7 +565,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
unsigned long flags;
int retval;
- dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);
+ dbg(2," %s : enter, count = %Zd", __func__, count);
dev = file->private_data;
@@ -582,7 +582,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
/* verify that we actually have some data to write */
if (count == 0) {
- dbg(1," %s : write request of 0 bytes", __FUNCTION__);
+ dbg(1," %s : write request of 0 bytes", __func__);
goto exit;
}
@@ -595,13 +595,13 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
mutex_unlock(&dev->mtx);
if (signal_pending(current)) {
- dbg(1," %s : interrupted", __FUNCTION__);
+ dbg(1," %s : interrupted", __func__);
set_current_state(TASK_RUNNING);
retval = -EINTR;
goto exit_onqueue;
}
if (schedule_timeout(COMMAND_TIMEOUT) == 0) {
- dbg(1, "%s - command timed out.", __FUNCTION__);
+ dbg(1, "%s - command timed out.", __func__);
retval = -ETIMEDOUT;
goto exit_onqueue;
}
@@ -612,18 +612,18 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
goto exit_nolock;
}
- dbg(4," %s : in progress, count = %Zd", __FUNCTION__, count);
+ dbg(4," %s : in progress, count = %Zd", __func__, count);
} else {
spin_unlock_irqrestore(&dev->buflock, flags);
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->write_wait, &waita);
- dbg(4," %s : sending, count = %Zd", __FUNCTION__, count);
+ dbg(4," %s : sending, count = %Zd", __func__, count);
/* write the data into interrupt_out_buffer from userspace */
buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
bytes_to_write = count > buffer_size ? buffer_size : count;
dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
- __FUNCTION__, buffer_size, count, bytes_to_write);
+ __func__, buffer_size, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
retval = -EFAULT;
@@ -661,7 +661,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
exit:
mutex_unlock(&dev->mtx);
exit_nolock:
- dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ dbg(2," %s : leave, return value %d", __func__, retval);
return retval;
exit_onqueue:
@@ -706,7 +706,7 @@ static int adu_probe(struct usb_interface *interface,
int out_end_size;
int i;
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
if (udev == NULL) {
dev_err(&interface->dev, "udev is NULL.\n");
@@ -807,7 +807,7 @@ static int adu_probe(struct usb_interface *interface,
dev_err(&interface->dev, "Could not retrieve serial number\n");
goto error;
}
- dbg(2," %s : serial_number=%s", __FUNCTION__, dev->serial_number);
+ dbg(2," %s : serial_number=%s", __func__, dev->serial_number);
/* we can register the device now, as it is ready */
usb_set_intfdata(interface, dev);
@@ -828,7 +828,7 @@ static int adu_probe(struct usb_interface *interface,
udev->descriptor.idProduct, dev->serial_number,
(dev->minor - ADU_MINOR_BASE));
exit:
- dbg(2," %s : leave, return value %p (dev)", __FUNCTION__, dev);
+ dbg(2," %s : leave, return value %p (dev)", __func__, dev);
return retval;
@@ -847,7 +847,7 @@ static void adu_disconnect(struct usb_interface *interface)
struct adu_device *dev;
int minor;
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
dev = usb_get_intfdata(interface);
@@ -861,7 +861,7 @@ static void adu_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
/* if the device is not opened, then we clean up right now */
- dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
+ dbg(2," %s : open count %d", __func__, dev->open_count);
if (!dev->open_count)
adu_delete(dev);
@@ -870,7 +870,7 @@ static void adu_disconnect(struct usb_interface *interface)
dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",
(minor - ADU_MINOR_BASE));
- dbg(2," %s : leave", __FUNCTION__);
+ dbg(2," %s : leave", __func__);
}
/* usb specific object needed to register this driver with the usb subsystem */
@@ -885,7 +885,7 @@ static int __init adu_init(void)
{
int result;
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
/* register this driver with the USB subsystem */
result = usb_register(&adu_driver);
@@ -899,17 +899,17 @@ static int __init adu_init(void)
info("adutux is an experimental driver. Use at your own risk");
exit:
- dbg(2," %s : leave, return value %d", __FUNCTION__, result);
+ dbg(2," %s : leave, return value %d", __func__, result);
return result;
}
static void __exit adu_exit(void)
{
- dbg(2," %s : enter", __FUNCTION__);
+ dbg(2," %s : enter", __func__);
/* deregister this driver with the USB subsystem */
usb_deregister(&adu_driver);
- dbg(2," %s : leave", __FUNCTION__);
+ dbg(2," %s : leave", __func__);
}
module_init(adu_init);
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index a5e4c3545c72..a076c24a312a 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -103,11 +103,11 @@ static void appledisplay_complete(struct urb *urb)
case -ESHUTDOWN:
/* This urb is terminated, clean up */
dbg("%s - urb shuttingdown with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
@@ -131,7 +131,7 @@ exit:
retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
if (retval) {
err("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __func__, retval);
}
}
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index df7e1ecc810a..093938697426 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/usb.h>
+#include <linux/mutex.h>
/*-------------------------------------------------------------------*/
/* Debug support */
@@ -232,7 +233,7 @@ typedef struct auerscon
/* USB device context */
typedef struct
{
- struct semaphore mutex; /* protection in user context */
+ struct mutex mutex; /* protection in user context */
char name[20]; /* name of the /dev/usb entry */
unsigned int dtindex; /* index in the device table */
struct usb_device * usbdev; /* USB device handle */
@@ -253,12 +254,12 @@ typedef struct
/* character device context */
typedef struct
{
- struct semaphore mutex; /* protection in user context */
+ struct mutex mutex; /* protection in user context */
pauerswald_t auerdev; /* context pointer of assigned device */
auerbufctl_t bufctl; /* controls the buffer chain */
auerscon_t scontext; /* service context */
wait_queue_head_t readwait; /* for synchronous reading */
- struct semaphore readmutex; /* protection against multiple reads */
+ struct mutex readmutex; /* protection against multiple reads */
pauerbuf_t readbuf; /* buffer held for partial reading */
unsigned int readoffset; /* current offset in readbuf */
unsigned int removed; /* is != 0 if device is removed */
@@ -283,7 +284,7 @@ static void auerchain_complete (struct urb * urb)
int result;
/* get pointer to element and to chain */
- pauerchainelement_t acep = (pauerchainelement_t) urb->context;
+ pauerchainelement_t acep = urb->context;
pauerchain_t acp = acep->chain;
/* restore original entries in urb */
@@ -593,7 +594,7 @@ ac_fail:/* free the elements */
/* completion handler for synchronous chained URBs */
static void auerchain_blocking_completion (struct urb *urb)
{
- pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
+ pauerchain_chs_t pchs = urb->context;
pchs->done = 1;
wmb();
wake_up (&pchs->wqh);
@@ -846,7 +847,7 @@ static int auerswald_status_retry (int status)
/* Completion of asynchronous write block */
static void auerchar_ctrlwrite_complete (struct urb * urb)
{
- pauerbuf_t bp = (pauerbuf_t) urb->context;
+ pauerbuf_t bp = urb->context;
pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
dbg ("auerchar_ctrlwrite_complete called");
@@ -859,7 +860,7 @@ static void auerchar_ctrlwrite_complete (struct urb * urb)
/* Completion handler for dummy retry packet */
static void auerswald_ctrlread_wretcomplete (struct urb * urb)
{
- pauerbuf_t bp = (pauerbuf_t) urb->context;
+ pauerbuf_t bp = urb->context;
pauerswald_t cp;
int ret;
int status = urb->status;
@@ -903,7 +904,7 @@ static void auerswald_ctrlread_complete (struct urb * urb)
unsigned int serviceid;
pauerswald_t cp;
pauerscon_t scp;
- pauerbuf_t bp = (pauerbuf_t) urb->context;
+ pauerbuf_t bp = urb->context;
int status = urb->status;
int ret;
@@ -980,9 +981,9 @@ static void auerswald_int_complete (struct urb * urb)
int ret;
int status = urb->status;
pauerbuf_t bp = NULL;
- pauerswald_t cp = (pauerswald_t) urb->context;
+ pauerswald_t cp = urb->context;
- dbg ("%s called", __FUNCTION__);
+ dbg ("%s called", __func__);
switch (status) {
case 0:
@@ -992,10 +993,10 @@ static void auerswald_int_complete (struct urb * urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
+ dbg("%s - urb shutting down with status: %d", __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
+ dbg("%s - nonzero urb status received: %d", __func__, status);
goto exit;
}
@@ -1080,7 +1081,7 @@ exit:
ret = usb_submit_urb (urb, GFP_ATOMIC);
if (ret)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, ret);
+ __func__, ret);
}
/* int memory deallocation
@@ -1376,7 +1377,7 @@ static int auerchar_open (struct inode *inode, struct file *file)
if (cp == NULL) {
return -ENODEV;
}
- if (down_interruptible (&cp->mutex)) {
+ if (mutex_lock_interruptible(&cp->mutex)) {
return -ERESTARTSYS;
}
@@ -1389,8 +1390,8 @@ static int auerchar_open (struct inode *inode, struct file *file)
}
/* Initialize device descriptor */
- init_MUTEX( &ccp->mutex);
- init_MUTEX( &ccp->readmutex);
+ mutex_init(&ccp->mutex);
+ mutex_init(&ccp->readmutex);
auerbuf_init (&ccp->bufctl);
ccp->scontext.id = AUH_UNASSIGNED;
ccp->scontext.dispatch = auerchar_ctrlread_dispatch;
@@ -1405,7 +1406,7 @@ static int auerchar_open (struct inode *inode, struct file *file)
cp->open_count++;
ccp->auerdev = cp;
dbg("open %s as /dev/%s", cp->dev_desc, cp->name);
- up (&cp->mutex);
+ mutex_unlock(&cp->mutex);
/* file IO stuff */
file->f_pos = 0;
@@ -1413,7 +1414,7 @@ static int auerchar_open (struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
/* Error exit */
-ofail: up (&cp->mutex);
+ofail: mutex_unlock(&cp->mutex);
auerchar_delete (ccp);
return ret;
}
@@ -1432,23 +1433,23 @@ static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int
dbg ("ioctl");
/* get the mutexes */
- if (down_interruptible (&ccp->mutex)) {
+ if (mutex_lock_interruptible(&ccp->mutex)) {
return -ERESTARTSYS;
}
cp = ccp->auerdev;
if (!cp) {
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
return -ENODEV;
}
- if (down_interruptible (&cp->mutex)) {
- up(&ccp->mutex);
+ if (mutex_lock_interruptible(&cp->mutex)) {
+ mutex_unlock(&ccp->mutex);
return -ERESTARTSYS;
}
/* Check for removal */
if (!cp->usbdev) {
- up(&cp->mutex);
- up(&ccp->mutex);
+ mutex_unlock(&cp->mutex);
+ mutex_unlock(&ccp->mutex);
return -ENODEV;
}
@@ -1550,8 +1551,8 @@ static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int
break;
}
/* release the mutexes */
- up(&cp->mutex);
- up(&ccp->mutex);
+ mutex_unlock(&cp->mutex);
+ mutex_unlock(&ccp->mutex);
return ret;
}
@@ -1574,18 +1575,18 @@ static ssize_t auerchar_read (struct file *file, char __user *buf, size_t count,
return 0;
/* get the mutex */
- if (down_interruptible (&ccp->mutex))
+ if (mutex_lock_interruptible(&ccp->mutex))
return -ERESTARTSYS;
/* Can we expect to read something? */
if (ccp->scontext.id == AUH_UNASSIGNED) {
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
return -EIO;
}
/* only one reader per device allowed */
- if (down_interruptible (&ccp->readmutex)) {
- up (&ccp->mutex);
+ if (mutex_lock_interruptible(&ccp->readmutex)) {
+ mutex_unlock(&ccp->mutex);
return -ERESTARTSYS;
}
@@ -1602,8 +1603,8 @@ doreadbuf:
if (count) {
if (copy_to_user (buf, bp->bufp+ccp->readoffset, count)) {
dbg ("auerswald_read: copy_to_user failed");
- up (&ccp->readmutex);
- up (&ccp->mutex);
+ mutex_unlock(&ccp->readmutex);
+ mutex_unlock(&ccp->mutex);
return -EFAULT;
}
}
@@ -1617,8 +1618,8 @@ doreadbuf:
}
/* return with number of bytes read */
if (count) {
- up (&ccp->readmutex);
- up (&ccp->mutex);
+ mutex_unlock(&ccp->readmutex);
+ mutex_unlock(&ccp->mutex);
return count;
}
}
@@ -1654,29 +1655,29 @@ doreadlist:
dbg ("No read buffer available, returning -EAGAIN");
set_current_state (TASK_RUNNING);
remove_wait_queue (&ccp->readwait, &wait);
- up (&ccp->readmutex);
- up (&ccp->mutex);
+ mutex_unlock(&ccp->readmutex);
+ mutex_unlock(&ccp->mutex);
return -EAGAIN; /* nonblocking, no data available */
}
/* yes, we should wait! */
- up (&ccp->mutex); /* allow other operations while we wait */
+ mutex_unlock(&ccp->mutex); /* allow other operations while we wait */
schedule();
remove_wait_queue (&ccp->readwait, &wait);
if (signal_pending (current)) {
/* waked up by a signal */
- up (&ccp->readmutex);
+ mutex_unlock(&ccp->readmutex);
return -ERESTARTSYS;
}
/* Anything left to read? */
if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) {
- up (&ccp->readmutex);
+ mutex_unlock(&ccp->readmutex);
return -EIO;
}
- if (down_interruptible (&ccp->mutex)) {
- up (&ccp->readmutex);
+ if (mutex_lock_interruptible(&ccp->mutex)) {
+ mutex_unlock(&ccp->readmutex);
return -ERESTARTSYS;
}
@@ -1707,27 +1708,27 @@ static ssize_t auerchar_write (struct file *file, const char __user *buf, size_t
write_again:
/* get the mutex */
- if (down_interruptible (&ccp->mutex))
+ if (mutex_lock_interruptible(&ccp->mutex))
return -ERESTARTSYS;
/* Can we expect to write something? */
if (ccp->scontext.id == AUH_UNASSIGNED) {
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
return -EIO;
}
cp = ccp->auerdev;
if (!cp) {
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
return -ERESTARTSYS;
}
- if (down_interruptible (&cp->mutex)) {
- up (&ccp->mutex);
+ if (mutex_lock_interruptible(&cp->mutex)) {
+ mutex_unlock(&ccp->mutex);
return -ERESTARTSYS;
}
if (!cp->usbdev) {
- up (&cp->mutex);
- up (&ccp->mutex);
+ mutex_unlock(&cp->mutex);
+ mutex_unlock(&ccp->mutex);
return -EIO;
}
/* Prepare for sleep */
@@ -1750,8 +1751,8 @@ write_again:
/* are there any buffers left? */
if (!bp) {
- up (&cp->mutex);
- up (&ccp->mutex);
+ mutex_unlock(&cp->mutex);
+ mutex_unlock(&ccp->mutex);
/* NONBLOCK: don't wait */
if (file->f_flags & O_NONBLOCK) {
@@ -1783,8 +1784,8 @@ write_again:
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
- up (&cp->mutex);
- up (&ccp->mutex);
+ mutex_unlock(&cp->mutex);
+ mutex_unlock(&ccp->mutex);
return -EFAULT;
}
@@ -1803,18 +1804,18 @@ write_again:
auerchar_ctrlwrite_complete, bp);
/* up we go */
ret = auerchain_submit_urb (&cp->controlchain, bp->urbp);
- up (&cp->mutex);
+ mutex_unlock(&cp->mutex);
if (ret) {
dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
return -EIO;
}
else {
dbg ("auerchar_write: Write OK");
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
return len;
}
}
@@ -1827,24 +1828,24 @@ static int auerchar_release (struct inode *inode, struct file *file)
pauerswald_t cp;
dbg("release");
- down(&ccp->mutex);
+ mutex_lock(&ccp->mutex);
cp = ccp->auerdev;
if (cp) {
- down(&cp->mutex);
+ mutex_lock(&cp->mutex);
/* remove an open service */
auerswald_removeservice (cp, &ccp->scontext);
/* detach from device */
if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) {
/* usb device waits for removal */
- up (&cp->mutex);
+ mutex_unlock(&cp->mutex);
auerswald_delete (cp);
} else {
- up (&cp->mutex);
+ mutex_unlock(&cp->mutex);
}
cp = NULL;
ccp->auerdev = NULL;
}
- up (&ccp->mutex);
+ mutex_unlock(&ccp->mutex);
auerchar_delete (ccp);
return 0;
@@ -1917,7 +1918,7 @@ static int auerswald_probe (struct usb_interface *intf,
}
/* Initialize device descriptor */
- init_MUTEX (&cp->mutex);
+ mutex_init(&cp->mutex);
cp->usbdev = usbdev;
auerchain_init (&cp->controlchain);
auerbuf_init (&cp->bufctl);
@@ -2042,7 +2043,7 @@ static void auerswald_disconnect (struct usb_interface *intf)
/* give back our USB minor number */
usb_deregister_dev(intf, &auerswald_class);
- down (&cp->mutex);
+ mutex_lock(&cp->mutex);
info ("device /dev/%s now disconnecting", cp->name);
/* Stop the interrupt endpoint */
@@ -2057,16 +2058,18 @@ static void auerswald_disconnect (struct usb_interface *intf)
if (cp->open_count == 0) {
/* nobody is using this device. So we can clean up now */
- up (&cp->mutex);/* up() is possible here because no other task
- can open the device (see above). I don't want
- to kfree() a locked mutex. */
+ mutex_unlock(&cp->mutex);
+ /* mutex_unlock() is possible here because no other task
+ can open the device (see above). I don't want
+ to kfree() a locked mutex. */
+
auerswald_delete (cp);
} else {
/* device is used. Remove the pointer to the
usb device (it's not valid any more). The last
release() will do the clean up */
cp->usbdev = NULL;
- up (&cp->mutex);
+ mutex_unlock(&cp->mutex);
/* Terminate waiting writers */
wake_up (&cp->bufferwait);
/* Inform all waiting readers */
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index 4a09b87bdd28..4b9dc81b8453 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -70,8 +70,8 @@ static int emi26_writememory (struct usb_device *dev, int address, unsigned char
static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit)
{
int response;
- info("%s - %d", __FUNCTION__, reset_bit);
- /* printk(KERN_DEBUG "%s - %d", __FUNCTION__, reset_bit); */
+ info("%s - %d", __func__, reset_bit);
+ /* printk(KERN_DEBUG "%s - %d", __func__, reset_bit); */
response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0) {
err("emi26: set_reset (%d) failed", reset_bit);
@@ -91,7 +91,7 @@ static int emi26_load_firmware (struct usb_device *dev)
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
if (!buf) {
- err( "%s - error loading firmware: error = %d", __FUNCTION__, -ENOMEM);
+ err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
err = -ENOMEM;
goto wraperr;
}
@@ -99,7 +99,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
if (err < 0) {
- err( "%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err( "%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -107,7 +107,7 @@ static int emi26_load_firmware (struct usb_device *dev)
for (i=0; g_Loader[i].type == 0; i++) {
err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -115,7 +115,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
msleep(250); /* let device settle */
@@ -135,7 +135,7 @@ static int emi26_load_firmware (struct usb_device *dev)
}
err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
} while (i > 0);
@@ -143,7 +143,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -151,7 +151,7 @@ static int emi26_load_firmware (struct usb_device *dev)
for (i=0; g_Loader[i].type == 0; i++) {
err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -160,7 +160,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -169,7 +169,7 @@ static int emi26_load_firmware (struct usb_device *dev)
if (!INTERNAL_RAM(g_Firmware[i].address)) {
err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_EXTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -178,7 +178,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -186,7 +186,7 @@ static int emi26_load_firmware (struct usb_device *dev)
if (INTERNAL_RAM(g_Firmware[i].address)) {
err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -195,7 +195,7 @@ static int emi26_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
msleep(250); /* let device settle */
@@ -221,7 +221,7 @@ static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *i
{
struct usb_device *dev = interface_to_usbdev(intf);
- info("%s start", __FUNCTION__);
+ info("%s start", __func__);
emi26_load_firmware(dev);
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index d1362415922c..1a2b79ac5e10 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -78,7 +78,7 @@ static int emi62_writememory (struct usb_device *dev, int address, unsigned char
static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit)
{
int response;
- info("%s - %d", __FUNCTION__, reset_bit);
+ info("%s - %d", __func__, reset_bit);
response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0) {
@@ -100,7 +100,7 @@ static int emi62_load_firmware (struct usb_device *dev)
dev_dbg(&dev->dev, "load_firmware\n");
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
if (!buf) {
- err( "%s - error loading firmware: error = %d", __FUNCTION__, -ENOMEM);
+ err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
err = -ENOMEM;
goto wraperr;
}
@@ -108,7 +108,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -116,7 +116,7 @@ static int emi62_load_firmware (struct usb_device *dev)
for (i=0; g_emi62_loader[i].type == 0; i++) {
err = emi62_writememory(dev, g_emi62_loader[i].address, g_emi62_loader[i].data, g_emi62_loader[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -124,7 +124,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
msleep(250); /* let device settle */
@@ -144,7 +144,7 @@ static int emi62_load_firmware (struct usb_device *dev)
}
err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
} while (i > 0);
@@ -152,7 +152,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -160,7 +160,7 @@ static int emi62_load_firmware (struct usb_device *dev)
for (i=0; g_emi62_loader[i].type == 0; i++) {
err = emi62_writememory(dev, g_emi62_loader[i].address, g_emi62_loader[i].data, g_emi62_loader[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -168,7 +168,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
msleep(250); /* let device settle */
@@ -181,7 +181,7 @@ static int emi62_load_firmware (struct usb_device *dev)
if (!INTERNAL_RAM(g_HexSpdifFw62[i].address)) {
err = emi62_writememory(dev, g_HexSpdifFw62[i].address, g_HexSpdifFw62[i].data, g_HexSpdifFw62[i].length, ANCHOR_LOAD_EXTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -191,7 +191,7 @@ static int emi62_load_firmware (struct usb_device *dev)
if (!INTERNAL_RAM(g_HexMidiFw62[i].address)) {
err = emi62_writememory(dev, g_HexMidiFw62[i].address, g_HexMidiFw62[i].data, g_HexMidiFw62[i].length, ANCHOR_LOAD_EXTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d\n", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d\n", __func__, err);
goto wraperr;
return err;
}
@@ -201,7 +201,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
@@ -211,7 +211,7 @@ static int emi62_load_firmware (struct usb_device *dev)
if (INTERNAL_RAM(g_HexSpdifFw62[i].address)) {
err = emi62_writememory(dev, g_HexSpdifFw62[i].address, g_HexSpdifFw62[i].data, g_HexSpdifFw62[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
}
@@ -221,7 +221,7 @@ static int emi62_load_firmware (struct usb_device *dev)
if (INTERNAL_RAM(g_HexMidiFw62[i].address)) {
err = emi62_writememory(dev, g_HexMidiFw62[i].address, g_HexMidiFw62[i].data, g_HexMidiFw62[i].length, ANCHOR_LOAD_INTERNAL);
if (err < 0) {
- err("%s - error loading firmware: error = %d\n", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d\n", __func__, err);
goto wraperr;
}
}
@@ -231,7 +231,7 @@ static int emi62_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
if (err < 0) {
- err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
msleep(250); /* let device settle */
@@ -260,7 +260,7 @@ static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *i
struct usb_device *dev = interface_to_usbdev(intf);
dev_dbg(&intf->dev, "emi62_probe\n");
- info("%s start", __FUNCTION__);
+ info("%s start", __func__);
emi62_load_firmware(dev);
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 148b7fe639b2..ec88b3bfee46 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -746,7 +746,7 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
static void ftdi_elan_write_bulk_callback(struct urb *urb)
{
- struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
+ struct usb_ftdi *ftdi = urb->context;
int status = urb->status;
if (status && !(status == -ENOENT || status == -ECONNRESET ||
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 801070502cc1..1cb54a28347f 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -154,7 +154,7 @@ MODULE_DEVICE_TABLE(usb, iowarrior_ids);
*/
static void iowarrior_callback(struct urb *urb)
{
- struct iowarrior *dev = (struct iowarrior *)urb->context;
+ struct iowarrior *dev = urb->context;
int intr_idx;
int read_idx;
int aux_idx;
@@ -218,7 +218,7 @@ exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
@@ -230,7 +230,7 @@ static void iowarrior_write_callback(struct urb *urb)
struct iowarrior *dev;
int status = urb->status;
- dev = (struct iowarrior *)urb->context;
+ dev = urb->context;
/* sync/async unlink faults aren't errors */
if (status &&
!(status == -ENOENT ||
@@ -453,7 +453,7 @@ static ssize_t iowarrior_write(struct file *file,
default:
/* what do we have here ? An unsupported Product-ID ? */
dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n",
- __FUNCTION__, dev->product_id);
+ __func__, dev->product_id);
retval = -EFAULT;
goto exit;
break;
@@ -604,7 +604,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d", __FUNCTION__,
+ err("%s - error, can't find device for minor %d", __func__,
subminor);
return -ENODEV;
}
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index c730d20eec66..11580e81e2c6 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -231,7 +231,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
goto exit;
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __FUNCTION__, status);
+ __func__, status);
spin_lock(&dev->rbsl);
goto resubmit; /* maybe we can recover */
}
@@ -247,7 +247,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length);
dev->ring_head = next_ring_head;
dbg_info(&dev->intf->dev, "%s: received %d bytes\n",
- __FUNCTION__, urb->actual_length);
+ __func__, urb->actual_length);
} else {
dev_warn(&dev->intf->dev,
"Ring buffer overflow, %d bytes dropped\n",
@@ -286,7 +286,7 @@ static void ld_usb_interrupt_out_callback(struct urb *urb)
status == -ESHUTDOWN))
dbg_info(&dev->intf->dev,
"%s - nonzero write interrupt status received: %d\n",
- __FUNCTION__, status);
+ __func__, status);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
@@ -309,7 +309,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
if (!interface) {
err("%s - error, can't find device for minor %d\n",
- __FUNCTION__, subminor);
+ __func__, subminor);
return -ENODEV;
}
@@ -556,7 +556,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
if (bytes_to_write < count)
dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
- dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
+ dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 6664043f4645..9370326a5940 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -31,7 +31,7 @@
* - imported into lejos project
* - changed wake_up to wake_up_interruptible
* - changed to use lego0 rather than tower0
- * - changed dbg() to use __func__ rather than deprecated __FUNCTION__
+ * - changed dbg() to use __func__ rather than deprecated __func__
* 2003-01-12 - 0.53 david (david@csse.uwa.edu.au)
* - changed read and write to write everything or
* timeout (from a patch by Chris Riesen and Brett Thaeler driver)
@@ -49,7 +49,7 @@
* - added poll
* - forbid seeking
* - added nonblocking I/O
- * - changed back __func__ to __FUNCTION__
+ * - changed back __func__ to __func__
* - read and log tower firmware version
* - reset tower on probe, avoids failure of first write
* 2004-03-09 - 0.7 Juergen Stuber <starblue@users.sourceforge.net>
@@ -309,7 +309,7 @@ static inline void lego_usb_tower_debug_data (int level, const char *function, i
*/
static inline void tower_delete (struct lego_usb_tower *dev)
{
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
tower_abort_transfers (dev);
@@ -321,7 +321,7 @@ static inline void tower_delete (struct lego_usb_tower *dev)
kfree (dev->interrupt_out_buffer);
kfree (dev);
- dbg(2, "%s: leave", __FUNCTION__);
+ dbg(2, "%s: leave", __func__);
}
@@ -337,7 +337,7 @@ static int tower_open (struct inode *inode, struct file *file)
struct tower_reset_reply reset_reply;
int result;
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
nonseekable_open(inode, file);
subminor = iminor(inode);
@@ -346,7 +346,7 @@ static int tower_open (struct inode *inode, struct file *file)
if (!interface) {
err ("%s - error, can't find device for minor %d",
- __FUNCTION__, subminor);
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -424,7 +424,7 @@ unlock_exit:
mutex_unlock(&dev->lock);
exit:
- dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
+ dbg(2, "%s: leave, return value %d ", __func__, retval);
return retval;
}
@@ -437,12 +437,12 @@ static int tower_release (struct inode *inode, struct file *file)
struct lego_usb_tower *dev;
int retval = 0;
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
dev = (struct lego_usb_tower *)file->private_data;
if (dev == NULL) {
- dbg(1, "%s: object is NULL", __FUNCTION__);
+ dbg(1, "%s: object is NULL", __func__);
retval = -ENODEV;
goto exit_nolock;
}
@@ -454,7 +454,7 @@ static int tower_release (struct inode *inode, struct file *file)
}
if (dev->open_count != 1) {
- dbg(1, "%s: device not opened exactly once", __FUNCTION__);
+ dbg(1, "%s: device not opened exactly once", __func__);
retval = -ENODEV;
goto unlock_exit;
}
@@ -480,7 +480,7 @@ unlock_exit:
exit:
mutex_unlock(&open_disc_mutex);
exit_nolock:
- dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
+ dbg(2, "%s: leave, return value %d", __func__, retval);
return retval;
}
@@ -491,10 +491,10 @@ exit_nolock:
*/
static void tower_abort_transfers (struct lego_usb_tower *dev)
{
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
if (dev == NULL) {
- dbg(1, "%s: dev is null", __FUNCTION__);
+ dbg(1, "%s: dev is null", __func__);
goto exit;
}
@@ -509,7 +509,7 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
usb_kill_urb(dev->interrupt_out_urb);
exit:
- dbg(2, "%s: leave", __FUNCTION__);
+ dbg(2, "%s: leave", __func__);
}
@@ -542,7 +542,7 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
struct lego_usb_tower *dev;
unsigned int mask = 0;
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
dev = file->private_data;
@@ -557,7 +557,7 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
mask |= POLLOUT | POLLWRNORM;
}
- dbg(2, "%s: leave, mask = %d", __FUNCTION__, mask);
+ dbg(2, "%s: leave, mask = %d", __func__, mask);
return mask;
}
@@ -583,7 +583,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
int retval = 0;
unsigned long timeout = 0;
- dbg(2, "%s: enter, count = %Zd", __FUNCTION__, count);
+ dbg(2, "%s: enter, count = %Zd", __func__, count);
dev = (struct lego_usb_tower *)file->private_data;
@@ -602,7 +602,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
/* verify that we actually have some data to read */
if (count == 0) {
- dbg(1, "%s: read request of 0 bytes", __FUNCTION__);
+ dbg(1, "%s: read request of 0 bytes", __func__);
goto unlock_exit;
}
@@ -658,7 +658,7 @@ unlock_exit:
mutex_unlock(&dev->lock);
exit:
- dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
+ dbg(2, "%s: leave, return value %d", __func__, retval);
return retval;
}
@@ -672,7 +672,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
size_t bytes_to_write;
int retval = 0;
- dbg(2, "%s: enter, count = %Zd", __FUNCTION__, count);
+ dbg(2, "%s: enter, count = %Zd", __func__, count);
dev = (struct lego_usb_tower *)file->private_data;
@@ -691,7 +691,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
/* verify that we actually have some data to write */
if (count == 0) {
- dbg(1, "%s: write request of 0 bytes", __FUNCTION__);
+ dbg(1, "%s: write request of 0 bytes", __func__);
goto unlock_exit;
}
@@ -709,7 +709,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
/* write the data into interrupt_out_buffer from userspace */
bytes_to_write = min_t(int, count, write_buffer_size);
- dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __FUNCTION__, count, bytes_to_write);
+ dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __func__, count, bytes_to_write);
if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;
@@ -742,7 +742,7 @@ unlock_exit:
mutex_unlock(&dev->lock);
exit:
- dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
+ dbg(2, "%s: leave, return value %d", __func__, retval);
return retval;
}
@@ -753,13 +753,13 @@ exit:
*/
static void tower_interrupt_in_callback (struct urb *urb)
{
- struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ struct lego_usb_tower *dev = urb->context;
int status = urb->status;
int retval;
- dbg(4, "%s: enter, status %d", __FUNCTION__, status);
+ dbg(4, "%s: enter, status %d", __func__, status);
- lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
if (status) {
if (status == -ENOENT ||
@@ -767,7 +767,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
status == -ESHUTDOWN) {
goto exit;
} else {
- dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
+ dbg(1, "%s: nonzero status received: %d", __func__, status);
goto resubmit; /* maybe we can recover */
}
}
@@ -780,9 +780,9 @@ static void tower_interrupt_in_callback (struct urb *urb)
urb->actual_length);
dev->read_buffer_length += urb->actual_length;
dev->read_last_arrival = jiffies;
- dbg(3, "%s: received %d bytes", __FUNCTION__, urb->actual_length);
+ dbg(3, "%s: received %d bytes", __func__, urb->actual_length);
} else {
- printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __FUNCTION__, urb->actual_length);
+ printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length);
}
spin_unlock (&dev->read_buffer_lock);
}
@@ -792,7 +792,7 @@ resubmit:
if (dev->interrupt_in_running && dev->udev) {
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
if (retval) {
- err("%s: usb_submit_urb failed (%d)", __FUNCTION__, retval);
+ err("%s: usb_submit_urb failed (%d)", __func__, retval);
}
}
@@ -800,8 +800,8 @@ exit:
dev->interrupt_in_done = 1;
wake_up_interruptible (&dev->read_wait);
- lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, status);
+ lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+ dbg(4, "%s: leave, status %d", __func__, status);
}
@@ -810,25 +810,25 @@ exit:
*/
static void tower_interrupt_out_callback (struct urb *urb)
{
- struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ struct lego_usb_tower *dev = urb->context;
int status = urb->status;
- dbg(4, "%s: enter, status %d", __FUNCTION__, status);
- lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ dbg(4, "%s: enter, status %d", __func__, status);
+ lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
/* sync/async unlink faults aren't errors */
if (status && !(status == -ENOENT ||
status == -ECONNRESET ||
status == -ESHUTDOWN)) {
dbg(1, "%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
}
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
- lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, status);
+ lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+ dbg(4, "%s: leave, status %d", __func__, status);
}
@@ -849,7 +849,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
int retval = -ENOMEM;
int result;
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
if (udev == NULL) {
info ("udev is NULL.");
@@ -978,7 +978,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
exit:
- dbg(2, "%s: leave, return value 0x%.8lx (dev)", __FUNCTION__, (long) dev);
+ dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev);
return retval;
@@ -998,7 +998,7 @@ static void tower_disconnect (struct usb_interface *interface)
struct lego_usb_tower *dev;
int minor;
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
dev = usb_get_intfdata (interface);
mutex_lock(&open_disc_mutex);
@@ -1023,7 +1023,7 @@ static void tower_disconnect (struct usb_interface *interface)
info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
- dbg(2, "%s: leave", __FUNCTION__);
+ dbg(2, "%s: leave", __func__);
}
@@ -1036,7 +1036,7 @@ static int __init lego_usb_tower_init(void)
int result;
int retval = 0;
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
/* register this driver with the USB subsystem */
result = usb_register(&tower_driver);
@@ -1049,7 +1049,7 @@ static int __init lego_usb_tower_init(void)
info(DRIVER_DESC " " DRIVER_VERSION);
exit:
- dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
+ dbg(2, "%s: leave, return value %d", __func__, retval);
return retval;
}
@@ -1060,12 +1060,12 @@ exit:
*/
static void __exit lego_usb_tower_exit(void)
{
- dbg(2, "%s: enter", __FUNCTION__);
+ dbg(2, "%s: enter", __func__);
/* deregister this driver with the USB subsystem */
usb_deregister (&tower_driver);
- dbg(2, "%s: leave", __FUNCTION__);
+ dbg(2, "%s: leave", __func__);
}
module_init (lego_usb_tower_init);
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index aa9bcceabe74..24230c638b8e 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -113,7 +113,7 @@ static int set_outputs(struct interfacekit *kit)
buffer = kzalloc(4, GFP_KERNEL);
if (!buffer) {
- dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&kit->udev->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
buffer[0] = (u8)kit->outputs;
@@ -146,7 +146,7 @@ static int change_string(struct interfacekit *kit, const char *display, unsigned
buffer = kmalloc(8, GFP_KERNEL);
form_buffer = kmalloc(30, GFP_KERNEL);
if ((!buffer) || (!form_buffer)) {
- dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&kit->udev->dev, "%s - out of memory\n", __func__);
goto exit;
}
@@ -216,7 +216,7 @@ static ssize_t set_backlight(struct device *dev, struct device_attribute *attr,
buffer = kzalloc(8, GFP_KERNEL);
if (!buffer) {
- dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&kit->udev->dev, "%s - out of memory\n", __func__);
goto exit;
}
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index 2ad09b1f4848..f0113c17cc5a 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -61,7 +61,7 @@ static int set_motor(struct motorcontrol *mc, int motor)
buffer = kzalloc(8, GFP_KERNEL);
if (!buffer) {
- dev_err(&mc->intf->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&mc->intf->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index 0d9de2f73930..7d590c09434a 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -89,7 +89,7 @@ change_position_v30(struct phidget_servo *servo, int servo_no, int degrees,
buffer = kmalloc(6, GFP_KERNEL);
if (!buffer) {
dev_err(&servo->udev->dev, "%s - out of memory\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -162,7 +162,7 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
buffer = kmalloc(2, GFP_KERNEL);
if (!buffer) {
dev_err(&servo->udev->dev, "%s - out of memory\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -259,7 +259,7 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
if (dev == NULL) {
- dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&interface->dev, "%s - out of memory\n", __func__);
rc = -ENOMEM;
goto out;
}
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 20777d01db62..7f7021ee4189 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -78,7 +78,7 @@ static int lcd_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
err ("USBLCD: %s - error, can't find device for minor %d",
- __FUNCTION__, subminor);
+ __func__, subminor);
return -ENODEV;
}
@@ -185,7 +185,7 @@ static void lcd_write_bulk_callback(struct urb *urb)
struct usb_lcd *dev;
int status = urb->status;
- dev = (struct usb_lcd *)urb->context;
+ dev = urb->context;
/* sync/async unlink faults aren't errors */
if (status &&
@@ -193,7 +193,7 @@ static void lcd_write_bulk_callback(struct urb *urb)
status == -ECONNRESET ||
status == -ESHUTDOWN)) {
dbg("USBLCD: %s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
}
/* free up our allocated buffer */
@@ -248,7 +248,7 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
- err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
+ err("USBLCD: %s - failed submitting write urb, error %d", __func__, retval);
goto error_unanchor;
}
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index b6b5b2affad1..a51983854ca0 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -201,7 +201,7 @@ found:
static void simple_callback (struct urb *urb)
{
- complete ((struct completion *) urb->context);
+ complete(urb->context);
}
static struct urb *simple_alloc_urb (
@@ -1046,7 +1046,7 @@ static void unlink1_callback (struct urb *urb)
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status) {
urb->status = status;
- complete ((struct completion *) urb->context);
+ complete(urb->context);
}
}
@@ -1136,7 +1136,7 @@ static int verify_not_halted (int ep, struct urb *urb)
dbg ("ep %02x bogus status: %04x != 0", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, 0, __FUNCTION__);
+ retval = simple_io (urb, 1, 0, 0, __func__);
if (retval != 0)
return -EINVAL;
return 0;
@@ -1158,7 +1158,7 @@ static int verify_halted (int ep, struct urb *urb)
dbg ("ep %02x bogus status: %04x != 1", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, -EPIPE, __FUNCTION__);
+ retval = simple_io (urb, 1, 0, -EPIPE, __func__);
if (retval != -EPIPE)
return -EINVAL;
retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
@@ -1404,7 +1404,7 @@ static struct urb *iso_alloc_urb (
return NULL;
maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11));
- packets = (bytes + maxp - 1) / maxp;
+ packets = DIV_ROUND_UP(bytes, maxp);
urb = usb_alloc_urb (packets, GFP_KERNEL);
if (!urb)
@@ -1564,7 +1564,8 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
- if (intf->dev.power.power_state.event != PM_EVENT_ON) {
+ /* FIXME: What if a system sleep starts while a test is running? */
+ if (!intf->is_active) {
mutex_unlock(&dev->lock);
return -EHOSTUNREACH;
}
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 90c59535778d..0f76ed5e1617 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile for USB Core files and filesystem
+# Makefile for USB monitor
#
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 1774ba5c4c3b..49145534e06e 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1026,8 +1026,6 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait)
return mask;
}
-#if 0
-
/*
* open and close: just keep track of how many times the device is
* mapped, to use the proper memory allocation function.
@@ -1063,13 +1061,13 @@ static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return 0;
}
-struct vm_operations_struct mon_bin_vm_ops = {
+static struct vm_operations_struct mon_bin_vm_ops = {
.open = mon_bin_vma_open,
.close = mon_bin_vma_close,
.fault = mon_bin_vma_fault,
};
-int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
{
/* don't do anything here: "fault" will set up page table entries */
vma->vm_ops = &mon_bin_vm_ops;
@@ -1079,8 +1077,6 @@ int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-#endif /* 0 */
-
static const struct file_operations mon_fops_binary = {
.owner = THIS_MODULE,
.open = mon_bin_open,
@@ -1090,6 +1086,7 @@ static const struct file_operations mon_fops_binary = {
.poll = mon_bin_poll,
.ioctl = mon_bin_ioctl,
.release = mon_bin_release,
+ .mmap = mon_bin_mmap,
};
static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index b371ffd39d36..442d8076b201 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -129,8 +129,7 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
/*
*/
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
- int status)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, int status)
{
unsigned long flags;
struct list_head *pos;
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
index f6d1491256c4..c7a595cd648a 100644
--- a/drivers/usb/mon/mon_stat.c
+++ b/drivers/usb/mon/mon_stat.c
@@ -59,6 +59,9 @@ static ssize_t mon_stat_read(struct file *file, char __user *buf,
static int mon_stat_release(struct inode *inode, struct file *file)
{
+ struct snap *sp = file->private_data;
+ file->private_data = NULL;
+ kfree(sp);
return 0;
}
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index c1e65dfd9353..2cffec85ee7e 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -20,8 +20,8 @@ menuconfig USB_SERIAL
if USB_SERIAL
config USB_SERIAL_CONSOLE
- bool "USB Serial Console device support (EXPERIMENTAL)"
- depends on USB_SERIAL=y && EXPERIMENTAL
+ bool "USB Serial Console device support"
+ depends on USB_SERIAL=y
---help---
If you say Y here, it will be possible to use a USB to serial
converter port as the system console (the system console is the
@@ -44,13 +44,11 @@ config USB_SERIAL_CONSOLE
config USB_EZUSB
bool "Functions for loading firmware on EZUSB chips"
- depends on USB_SERIAL
help
Say Y here if you need EZUSB device support.
config USB_SERIAL_GENERIC
bool "USB Generic Serial Driver"
- depends on USB_SERIAL
help
Say Y here if you want to use the generic USB serial driver. Please
read <file:Documentation/usb/usb-serial.txt> for more information on
@@ -59,8 +57,7 @@ config USB_SERIAL_GENERIC
properly.
config USB_SERIAL_AIRCABLE
- tristate "USB AIRcable Bluetooth Dongle Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB AIRcable Bluetooth Dongle Driver"
help
Say Y here if you want to use USB AIRcable Bluetooth Dongle.
@@ -69,7 +66,6 @@ config USB_SERIAL_AIRCABLE
config USB_SERIAL_AIRPRIME
tristate "USB AirPrime CDMA Wireless Driver"
- depends on USB_SERIAL
help
Say Y here if you want to use a AirPrime CDMA Wireless PC card.
@@ -77,8 +73,7 @@ config USB_SERIAL_AIRPRIME
module will be called airprime.
config USB_SERIAL_ARK3116
- tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB ARK Micro 3116 USB Serial Driver"
help
Say Y here if you want to use a ARK Micro 3116 USB to Serial
device.
@@ -88,7 +83,6 @@ config USB_SERIAL_ARK3116
config USB_SERIAL_BELKIN
tristate "USB Belkin and Peracom Single Port Serial Driver"
- depends on USB_SERIAL
help
Say Y here if you want to use a Belkin USB Serial single port
adaptor (F5U103 is one of the model numbers) or the Peracom single
@@ -99,7 +93,6 @@ config USB_SERIAL_BELKIN
config USB_SERIAL_CH341
tristate "USB Winchiphead CH341 Single Port Serial Driver"
- depends on USB_SERIAL
help
Say Y here if you want to use a Winchiphead CH341 single port
USB to serial adapter.
@@ -109,7 +102,6 @@ config USB_SERIAL_CH341
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
- depends on USB_SERIAL
select USB_EZUSB
help
Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
@@ -120,7 +112,6 @@ config USB_SERIAL_WHITEHEAT
config USB_SERIAL_DIGI_ACCELEPORT
tristate "USB Digi International AccelePort USB Serial Driver"
- depends on USB_SERIAL
---help---
Say Y here if you want to use Digi AccelePort USB 2 or 4 devices,
2 port (plus parallel port) and 4 port USB serial converters. The
@@ -135,7 +126,6 @@ config USB_SERIAL_DIGI_ACCELEPORT
config USB_SERIAL_CP2101
tristate "USB CP2101 UART Bridge Controller"
- depends on USB_SERIAL && EXPERIMENTAL
help
Say Y here if you want to use a CP2101/CP2102 based USB to RS232
converter.
@@ -145,7 +135,6 @@ config USB_SERIAL_CP2101
config USB_SERIAL_CYPRESS_M8
tristate "USB Cypress M8 USB Serial Driver"
- depends on USB_SERIAL && EXPERIMENTAL
help
Say Y here if you want to use a device that contains the Cypress
USB to Serial microcontroller, such as the DeLorme Earthmate GPS.
@@ -160,7 +149,6 @@ config USB_SERIAL_CYPRESS_M8
config USB_SERIAL_EMPEG
tristate "USB Empeg empeg-car Mark I/II Driver"
- depends on USB_SERIAL
help
Say Y here if you want to connect to your Empeg empeg-car Mark I/II
mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...}
@@ -171,8 +159,7 @@ config USB_SERIAL_EMPEG
module will be called empeg.
config USB_SERIAL_FTDI_SIO
- tristate "USB FTDI Single Port Serial Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB FTDI Single Port Serial Driver"
---help---
Say Y here if you want to use a FTDI SIO single port USB to serial
converter device. The implementation I have is called the USC-1000.
@@ -186,7 +173,6 @@ config USB_SERIAL_FTDI_SIO
config USB_SERIAL_FUNSOFT
tristate "USB Fundamental Software Dongle Driver"
- depends on USB_SERIAL
---help---
Say Y here if you want to use the Fundamental Software dongle.
@@ -195,7 +181,6 @@ config USB_SERIAL_FUNSOFT
config USB_SERIAL_VISOR
tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
- depends on USB_SERIAL
help
Say Y here if you want to connect to your HandSpring Visor, Palm
m500 or m505 through its USB docking station. See
@@ -207,7 +192,6 @@ config USB_SERIAL_VISOR
config USB_SERIAL_IPAQ
tristate "USB PocketPC PDA Driver"
- depends on USB_SERIAL
help
Say Y here if you want to connect to your Compaq iPAQ, HP Jornada
or any other PDA running Windows CE 3.0 or PocketPC 2002
@@ -218,8 +202,7 @@ config USB_SERIAL_IPAQ
module will be called ipaq.
config USB_SERIAL_IR
- tristate "USB IR Dongle Serial Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB IR Dongle Serial Driver"
help
Say Y here if you want to enable simple serial support for USB IrDA
devices. This is useful if you do not want to use the full IrDA
@@ -230,7 +213,6 @@ config USB_SERIAL_IR
config USB_SERIAL_EDGEPORT
tristate "USB Inside Out Edgeport Serial Driver"
- depends on USB_SERIAL
---help---
Say Y here if you want to use any of the following devices from
Inside Out Networks (Digi):
@@ -256,7 +238,6 @@ config USB_SERIAL_EDGEPORT
config USB_SERIAL_EDGEPORT_TI
tristate "USB Inside Out Edgeport Serial Driver (TI devices)"
- depends on USB_SERIAL
help
Say Y here if you want to use any of the devices from Inside Out
Networks (Digi) that are not supported by the io_edgeport driver.
@@ -267,7 +248,6 @@ config USB_SERIAL_EDGEPORT_TI
config USB_SERIAL_GARMIN
tristate "USB Garmin GPS driver"
- depends on USB_SERIAL
help
Say Y here if you want to connect to your Garmin GPS.
Should work with most Garmin GPS devices which have a native USB port.
@@ -279,8 +259,7 @@ config USB_SERIAL_GARMIN
module will be called garmin_gps.
config USB_SERIAL_IPW
- tristate "USB IPWireless (3G UMTS TDD) Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB IPWireless (3G UMTS TDD) Driver"
help
Say Y here if you want to use a IPWireless USB modem such as
the ones supplied by Axity3G/Sentech South Africa.
@@ -289,8 +268,7 @@ config USB_SERIAL_IPW
module will be called ipw.
config USB_SERIAL_IUU
- tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB Infinity USB Unlimited Phoenix Driver"
help
Say Y here if you want to use a IUU in phoenix mode and get
an extra ttyUSBx device. More information available on
@@ -301,7 +279,6 @@ config USB_SERIAL_IUU
config USB_SERIAL_KEYSPAN_PDA
tristate "USB Keyspan PDA Single Port Serial Driver"
- depends on USB_SERIAL
select USB_EZUSB
help
Say Y here if you want to use a Keyspan PDA single port USB to
@@ -313,7 +290,6 @@ config USB_SERIAL_KEYSPAN_PDA
config USB_SERIAL_KEYSPAN
tristate "USB Keyspan USA-xxx Serial Driver"
- depends on USB_SERIAL
select USB_EZUSB
---help---
Say Y here if you want to use Keyspan USB to serial converter
@@ -405,8 +381,7 @@ config USB_SERIAL_KEYSPAN_USA49WLC
Say Y here to include firmware for the USA-49WLC converter.
config USB_SERIAL_KLSI
- tristate "USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB KL5KUSB105 (Palmconnect) Driver"
---help---
Say Y here if you want to use a KL5KUSB105 - based single port
serial adapter. The most widely known -- and currently the only
@@ -422,7 +397,6 @@ config USB_SERIAL_KLSI
config USB_SERIAL_KOBIL_SCT
tristate "USB KOBIL chipcard reader"
- depends on USB_SERIAL
---help---
Say Y here if you want to use one of the following KOBIL USB chipcard
readers:
@@ -440,7 +414,6 @@ config USB_SERIAL_KOBIL_SCT
config USB_SERIAL_MCT_U232
tristate "USB MCT Single Port Serial Driver"
- depends on USB_SERIAL
---help---
Say Y here if you want to use a USB Serial single port adapter from
Magic Control Technology Corp. (U232 is one of the model numbers).
@@ -453,7 +426,6 @@ config USB_SERIAL_MCT_U232
config USB_SERIAL_MOS7720
tristate "USB Moschip 7720 Serial Driver"
- depends on USB_SERIAL
---help---
Say Y here if you want to use USB Serial single and double
port adapters from Moschip Semiconductor Tech.
@@ -463,7 +435,6 @@ config USB_SERIAL_MOS7720
config USB_SERIAL_MOS7840
tristate "USB Moschip 7840/7820 USB Serial Driver"
- depends on USB_SERIAL
---help---
Say Y here if you want to use a MCS7840 Quad-Serial or MCS7820
Dual-Serial port device from MosChip Semiconductor.
@@ -478,14 +449,12 @@ config USB_SERIAL_MOS7840
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
- depends on USB_SERIAL
help
To compile this driver as a module, choose M here: the
module will be called navman.
config USB_SERIAL_PL2303
tristate "USB Prolific 2303 Single Port Serial Driver"
- depends on USB_SERIAL
help
Say Y here if you want to use the PL2303 USB Serial single port
adapter from Prolific.
@@ -494,8 +463,7 @@ config USB_SERIAL_PL2303
module will be called pl2303.
config USB_SERIAL_OTI6858
- tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller (EXPERIMENTAL)"
- depends on USB_SERIAL
+ tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller"
help
Say Y here if you want to use the OTi-6858 single port USB to serial
converter device.
@@ -503,9 +471,17 @@ config USB_SERIAL_OTI6858
To compile this driver as a module, choose M here: the
module will be called oti6858.
+config USB_SERIAL_SPCP8X5
+ tristate "USB SPCP8x5 USB To Serial Driver"
+ help
+ Say Y here if you want to use the spcp8x5 converter chip. This is
+ commonly found in some Z-Wave USB devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called spcp8x5.
+
config USB_SERIAL_HP4X
tristate "USB HP4x Calculators support"
- depends on USB_SERIAL
help
Say Y here if you want to use an Hewlett-Packard 4x Calculator.
@@ -513,8 +489,7 @@ config USB_SERIAL_HP4X
module will be called hp4x.
config USB_SERIAL_SAFE
- tristate "USB Safe Serial (Encapsulated) Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB Safe Serial (Encapsulated) Driver"
config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
@@ -522,7 +497,6 @@ config USB_SERIAL_SAFE_PADDED
config USB_SERIAL_SIERRAWIRELESS
tristate "USB Sierra Wireless Driver"
- depends on USB_SERIAL
help
Say M here if you want to use a Sierra Wireless device (if
using an PC 5220 or AC580 please use the Airprime driver
@@ -533,7 +507,6 @@ config USB_SERIAL_SIERRAWIRELESS
config USB_SERIAL_TI
tristate "USB TI 3410/5052 Serial Driver"
- depends on USB_SERIAL
help
Say Y here if you want to use the TI USB 3410 or 5052
serial devices.
@@ -542,8 +515,7 @@ config USB_SERIAL_TI
module will be called ti_usb_3410_5052.
config USB_SERIAL_CYBERJACK
- tristate "USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB REINER SCT cyberJack pinpad/e-com chipcard reader"
---help---
Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
reader. This is an interface to ISO 7816 compatible contact-based
@@ -556,7 +528,6 @@ config USB_SERIAL_CYBERJACK
config USB_SERIAL_XIRCOM
tristate "USB Xircom / Entregra Single Port Serial Driver"
- depends on USB_SERIAL
select USB_EZUSB
help
Say Y here if you want to use a Xircom or Entregra single port USB to
@@ -568,7 +539,6 @@ config USB_SERIAL_XIRCOM
config USB_SERIAL_OPTION
tristate "USB driver for GSM and CDMA modems"
- depends on USB_SERIAL
help
Say Y here if you have a GSM or CDMA modem that's connected to USB.
@@ -586,8 +556,7 @@ config USB_SERIAL_OPTION
it might be accessible via the FTDI_SIO driver.
config USB_SERIAL_OMNINET
- tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
- depends on USB_SERIAL && EXPERIMENTAL
+ tristate "USB ZyXEL omni.net LCD Plus Driver"
help
Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA.
@@ -596,7 +565,6 @@ config USB_SERIAL_OMNINET
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
- depends on USB_SERIAL
help
Say Y here if you have a USB debugging device used to receive
debugging data from another machine. The most common of these
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 0db109a54d10..756859510d8c 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -30,8 +30,8 @@ obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o
obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o
-obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
+obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
@@ -46,6 +46,7 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
+obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 1cd29cd6bd00..9b1bb347dc2d 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -209,8 +209,8 @@ static void aircable_send(struct usb_serial_port *port)
int count, result;
struct aircable_private *priv = usb_get_serial_port_data(port);
unsigned char* buf;
- u16 *dbuf;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ __le16 *dbuf;
+ dbg("%s - port %d", __func__, port->number);
if (port->write_urb_busy)
return;
@@ -220,14 +220,14 @@ static void aircable_send(struct usb_serial_port *port)
buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC);
if (!buf) {
- err("%s- kzalloc(%d) failed.", __FUNCTION__,
+ err("%s- kzalloc(%d) failed.", __func__,
count + HCI_HEADER_LENGTH);
return;
}
buf[0] = TX_HEADER_0;
buf[1] = TX_HEADER_1;
- dbuf = (u16 *)&buf[2];
+ dbuf = (__le16 *)&buf[2];
*dbuf = cpu_to_le16((u16)count);
serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
@@ -236,7 +236,7 @@ static void aircable_send(struct usb_serial_port *port)
kfree(buf);
port->write_urb_busy = 1;
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
count + HCI_HEADER_LENGTH,
port->write_urb->transfer_buffer);
port->write_urb->transfer_buffer_length = count + HCI_HEADER_LENGTH;
@@ -246,7 +246,7 @@ static void aircable_send(struct usb_serial_port *port)
if (result) {
dev_err(&port->dev,
"%s - failed submitting write urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
port->write_urb_busy = 0;
}
@@ -275,7 +275,7 @@ static void aircable_read(struct work_struct *work)
if (!tty) {
schedule_work(&priv->rx_work);
- err("%s - No tty available", __FUNCTION__);
+ err("%s - No tty available", __func__);
return ;
}
@@ -286,7 +286,7 @@ static void aircable_read(struct work_struct *work)
tty_prepare_flip_string(tty, &data, count);
if (!data){
- err("%s- kzalloc(%d) failed.", __FUNCTION__, count);
+ err("%s- kzalloc(%d) failed.", __func__, count);
return;
}
@@ -332,7 +332,7 @@ static int aircable_attach (struct usb_serial *serial)
priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
if (!priv){
- err("%s- kmalloc(%Zd) failed.", __FUNCTION__,
+ err("%s- kmalloc(%Zd) failed.", __func__,
sizeof(struct aircable_private));
return -ENOMEM;
}
@@ -366,7 +366,7 @@ static void aircable_shutdown(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct aircable_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (priv) {
serial_buf_free(priv->tx_buf);
@@ -388,12 +388,12 @@ static int aircable_write(struct usb_serial_port *port,
struct aircable_private *priv = usb_get_serial_port_data(port);
int temp;
- dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+ dbg("%s - port %d, %d bytes", __func__, port->number, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, source);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, source);
if (!count){
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return count;
}
@@ -414,7 +414,7 @@ static void aircable_write_bulk_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s - urb status: %d", __FUNCTION__ , status);
+ dbg("%s - urb status: %d", __func__ , status);
/* This has been taken from cypress_m8.c cypress_write_int_callback */
switch (status) {
@@ -426,21 +426,21 @@ static void aircable_write_bulk_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
port->write_urb_busy = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __FUNCTION__);
+ dbg("%s - Overflow in write", __func__);
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev,
"%s - failed resubmitting write urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
else
return;
}
@@ -460,17 +460,17 @@ static void aircable_read_bulk_callback(struct urb *urb)
unsigned char *temp;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
- dbg("%s - urb status = %d", __FUNCTION__, status);
+ dbg("%s - urb status = %d", __func__, status);
if (!port->open_count) {
- dbg("%s - port is closed, exiting.", __FUNCTION__);
+ dbg("%s - port is closed, exiting.", __func__);
return;
}
if (status == -EPROTO) {
dbg("%s - caught -EPROTO, resubmitting the urb",
- __FUNCTION__);
+ __func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
port->bulk_in_endpointAddress),
@@ -482,14 +482,14 @@ static void aircable_read_bulk_callback(struct urb *urb)
if (result)
dev_err(&urb->dev->dev,
"%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
return;
}
- dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
+ dbg("%s - unable to handle the error, exiting.", __func__);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length,urb->transfer_buffer);
tty = port->tty;
@@ -538,7 +538,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
if (result)
dev_err(&urb->dev->dev,
"%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
}
return;
@@ -550,7 +550,7 @@ static void aircable_throttle(struct usb_serial_port *port)
struct aircable_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags |= THROTTLED;
@@ -564,7 +564,7 @@ static void aircable_unthrottle(struct usb_serial_port *port)
int actually_throttled;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->rx_lock, flags);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index f156dba0300f..725b6b94c274 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -53,7 +53,7 @@ static int airprime_send_setup(struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
struct airprime_private *priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (port->number != 0)
return 0;
@@ -83,14 +83,14 @@ static void airprime_read_bulk_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -101,7 +101,7 @@ static void airprime_read_bulk_callback(struct urb *urb)
result = usb_submit_urb (urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
return;
}
@@ -112,14 +112,14 @@ static void airprime_write_bulk_callback(struct urb *urb)
int status = urb->status;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
if (status)
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
spin_lock_irqsave(&priv->lock, flags);
--priv->outstanding_urbs;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -136,7 +136,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
int i;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* initialize our private data structure if it isn't already created */
if (!priv) {
@@ -157,7 +157,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!buffer) {
dev_err(&port->dev, "%s - out of memory.\n",
- __FUNCTION__);
+ __func__);
result = -ENOMEM;
goto errout;
}
@@ -165,7 +165,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
if (!urb) {
kfree(buffer);
dev_err(&port->dev, "%s - no more urbs?\n",
- __FUNCTION__);
+ __func__);
result = -ENOMEM;
goto errout;
}
@@ -180,7 +180,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
kfree(buffer);
dev_err(&port->dev,
"%s - failed submitting read urb %d for port %d, error %d\n",
- __FUNCTION__, i, port->number, result);
+ __func__, i, port->number, result);
goto errout;
}
/* remember this urb so we can kill it when the port is closed */
@@ -212,7 +212,7 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
struct airprime_private *priv = usb_get_serial_port_data(port);
int i;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
priv->rts_state = 0;
priv->dtr_state = 0;
@@ -242,12 +242,12 @@ static int airprime_write(struct usb_serial_port *port,
unsigned char *buffer;
unsigned long flags;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > NUM_WRITE_URBS) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __FUNCTION__);
+ dbg("%s - write limit hit\n", __func__);
return 0;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -264,7 +264,7 @@ static int airprime_write(struct usb_serial_port *port,
}
memcpy (buffer, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev,
@@ -277,7 +277,7 @@ static int airprime_write(struct usb_serial_port *port,
if (status) {
dev_err(&port->dev,
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
- __FUNCTION__, status);
+ __func__, status);
count = status;
kfree (buffer);
} else {
@@ -306,9 +306,6 @@ static struct usb_serial_driver airprime_device = {
},
.usb_driver = &airprime_driver,
.id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.open = airprime_open,
.close = airprime_close,
.write = airprime_write,
@@ -331,7 +328,7 @@ static int __init airprime_init(void)
static void __exit airprime_exit(void)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
usb_deregister(&airprime_driver);
usb_serial_deregister(&airprime_device);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index fe2bfd67ba8e..599ab2e548a7 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -173,7 +173,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
config = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
@@ -192,6 +192,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
dbg("error kmalloc");
+ *port->tty->termios = *old_termios;
return;
}
@@ -323,7 +324,7 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
char *buf;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
@@ -395,7 +396,7 @@ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
return -EFAULT;
return 0;
default:
- dbg("%s cmd 0x%04x not supported", __FUNCTION__, cmd);
+ dbg("%s cmd 0x%04x not supported", __func__, cmd);
break;
}
@@ -447,9 +448,6 @@ static struct usb_serial_driver ark3116_device = {
},
.id_table = id_table,
.usb_driver = &ark3116_driver,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.attach = ark3116_attach,
.set_termios = ark3116_set_termios,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index df0a2b3b0294..0a322fc53d6e 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -128,9 +128,6 @@ static struct usb_serial_driver belkin_device = {
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
.usb_driver = &belkin_driver,
.id_table = id_table_combined,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = belkin_sa_open,
.close = belkin_sa_close,
@@ -198,7 +195,7 @@ static void belkin_sa_shutdown (struct usb_serial *serial)
struct belkin_sa_private *priv;
int i;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
@@ -213,7 +210,7 @@ static int belkin_sa_open (struct usb_serial_port *port, struct file *filp)
{
int retval = 0;
- dbg("%s port %d", __FUNCTION__, port->number);
+ dbg("%s port %d", __func__, port->number);
/*Start reading from the device*/
/* TODO: Look at possibility of submitting multiple URBs to device to
@@ -240,7 +237,7 @@ exit:
static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
{
- dbg("%s port %d", __FUNCTION__, port->number);
+ dbg("%s port %d", __func__, port->number);
/* shutdown our bulk reads and writes */
usb_kill_urb(port->write_urb);
@@ -251,7 +248,7 @@ static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
static void belkin_sa_read_int_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct belkin_sa_private *priv;
unsigned char *data = urb->transfer_buffer;
int retval;
@@ -267,15 +264,15 @@ static void belkin_sa_read_int_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
/* Handle known interrupt data */
/* ignore data[0] and data[1] */
@@ -334,7 +331,7 @@ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __func__, retval);
}
static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
@@ -481,7 +478,7 @@ static int belkin_sa_tiocmget (struct usb_serial_port *port, struct file *file)
unsigned long control_state;
unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -502,7 +499,7 @@ static int belkin_sa_tiocmset (struct usb_serial_port *port, struct file *file,
int rts = 0;
int dtr = 0;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 42582d49b69c..d947d955bceb 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -318,9 +318,6 @@ static struct usb_serial_driver ch341_device = {
},
.id_table = id_table,
.usb_driver = &ch341_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = ch341_open,
.set_termios = ch341_set_termios,
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 66ce30c1b75b..201184c3fb87 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -67,7 +67,7 @@ static int usb_console_setup(struct console *co, char *options)
struct tty_struct *tty = NULL;
struct ktermios *termios = NULL, dummy;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
if (options) {
baud = simple_strtoul(options, NULL, 10);
@@ -225,10 +225,10 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
if (count == 0)
return;
- dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
+ dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
if (!port->open_count) {
- dbg ("%s - port not opened", __FUNCTION__);
+ dbg ("%s - port not opened", __func__);
return;
}
@@ -248,7 +248,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
retval = serial->type->write(port, buf, i);
else
retval = usb_serial_generic_write(port, buf, i);
- dbg("%s - return value : %d", __FUNCTION__, retval);
+ dbg("%s - return value : %d", __func__, retval);
if (lf) {
/* append CR after LF */
unsigned char cr = 13;
@@ -256,7 +256,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
retval = serial->type->write(port, &cr, 1);
else
retval = usb_serial_generic_write(port, &cr, 1);
- dbg("%s - return value : %d", __FUNCTION__, retval);
+ dbg("%s - return value : %d", __func__, retval);
}
buf += i;
count -= i;
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 324bb61d68ff..dc0ea08ed231 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -53,9 +53,11 @@ static void cp2101_shutdown(struct usb_serial*);
static int debug;
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
+ { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
@@ -71,6 +73,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
+ { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
@@ -106,9 +109,6 @@ static struct usb_serial_driver cp2101_device = {
},
.usb_driver = &cp2101_driver,
.id_table = id_table,
- .num_interrupt_in = 0,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.open = cp2101_open,
.close = cp2101_close,
@@ -193,7 +193,7 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request,
buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
if (!buf) {
- dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - out of memory.\n", __func__);
return -ENOMEM;
}
@@ -214,7 +214,7 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request,
if (result != size) {
dev_err(&port->dev, "%s - Unable to send config request, "
"request=0x%x size=%d result=%d\n",
- __FUNCTION__, request, size, result);
+ __func__, request, size, result);
return -EPROTO;
}
@@ -240,7 +240,7 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request,
buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -265,7 +265,7 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request,
if ((size > 2 && result != size) || result < 0) {
dev_err(&port->dev, "%s - Unable to send request, "
"request=0x%x size=%d result=%d\n",
- __FUNCTION__, request, size, result);
+ __func__, request, size, result);
return -EPROTO;
}
@@ -293,11 +293,11 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
dev_err(&port->dev, "%s - Unable to enable UART\n",
- __FUNCTION__);
+ __func__);
return -EPROTO;
}
@@ -312,7 +312,7 @@ static int cp2101_open (struct usb_serial_port *port, struct file *filp)
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed resubmitting read urb, "
- "error %d\n", __FUNCTION__, result);
+ "error %d\n", __func__, result);
return result;
}
@@ -329,7 +329,7 @@ static void cp2101_cleanup (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (serial->dev) {
/* shutdown any bulk reads that might be going on */
@@ -342,10 +342,10 @@ static void cp2101_cleanup (struct usb_serial_port *port)
static void cp2101_close (struct usb_serial_port *port, struct file * filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* shutdown our urbs */
- dbg("%s - shutting down urbs", __FUNCTION__);
+ dbg("%s - shutting down urbs", __func__);
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
@@ -367,10 +367,10 @@ static void cp2101_get_termios (struct usb_serial_port *port)
int baud;
int bits;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty structures", __FUNCTION__);
+ dbg("%s - no tty structures", __func__);
return;
}
@@ -379,7 +379,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
if (baud)
baud = BAUD_RATE_GEN_FREQ / baud;
- dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ dbg("%s - baud rate = %d", __func__, baud);
tty_encode_baud_rate(port->tty, baud, baud);
cflag = port->tty->termios->c_cflag;
@@ -388,24 +388,24 @@ static void cp2101_get_termios (struct usb_serial_port *port)
cflag &= ~CSIZE;
switch(bits & BITS_DATA_MASK) {
case BITS_DATA_5:
- dbg("%s - data bits = 5", __FUNCTION__);
+ dbg("%s - data bits = 5", __func__);
cflag |= CS5;
break;
case BITS_DATA_6:
- dbg("%s - data bits = 6", __FUNCTION__);
+ dbg("%s - data bits = 6", __func__);
cflag |= CS6;
break;
case BITS_DATA_7:
- dbg("%s - data bits = 7", __FUNCTION__);
+ dbg("%s - data bits = 7", __func__);
cflag |= CS7;
break;
case BITS_DATA_8:
- dbg("%s - data bits = 8", __FUNCTION__);
+ dbg("%s - data bits = 8", __func__);
cflag |= CS8;
break;
case BITS_DATA_9:
dbg("%s - data bits = 9 (not supported, "
- "using 8 data bits)", __FUNCTION__);
+ "using 8 data bits)", __func__);
cflag |= CS8;
bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8;
@@ -413,7 +413,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
break;
default:
dbg("%s - Unknown number of data bits, "
- "using 8", __FUNCTION__);
+ "using 8", __func__);
cflag |= CS8;
bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8;
@@ -423,35 +423,35 @@ static void cp2101_get_termios (struct usb_serial_port *port)
switch(bits & BITS_PARITY_MASK) {
case BITS_PARITY_NONE:
- dbg("%s - parity = NONE", __FUNCTION__);
+ dbg("%s - parity = NONE", __func__);
cflag &= ~PARENB;
break;
case BITS_PARITY_ODD:
- dbg("%s - parity = ODD", __FUNCTION__);
+ dbg("%s - parity = ODD", __func__);
cflag |= (PARENB|PARODD);
break;
case BITS_PARITY_EVEN:
- dbg("%s - parity = EVEN", __FUNCTION__);
+ dbg("%s - parity = EVEN", __func__);
cflag &= ~PARODD;
cflag |= PARENB;
break;
case BITS_PARITY_MARK:
dbg("%s - parity = MARK (not supported, "
- "disabling parity)", __FUNCTION__);
+ "disabling parity)", __func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
break;
case BITS_PARITY_SPACE:
dbg("%s - parity = SPACE (not supported, "
- "disabling parity)", __FUNCTION__);
+ "disabling parity)", __func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
break;
default:
dbg("%s - Unknown parity mode, "
- "disabling parity", __FUNCTION__);
+ "disabling parity", __func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
@@ -461,21 +461,21 @@ static void cp2101_get_termios (struct usb_serial_port *port)
cflag &= ~CSTOPB;
switch(bits & BITS_STOP_MASK) {
case BITS_STOP_1:
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
break;
case BITS_STOP_1_5:
dbg("%s - stop bits = 1.5 (not supported, "
- "using 1 stop bit)", __FUNCTION__);
+ "using 1 stop bit)", __func__);
bits &= ~BITS_STOP_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
break;
case BITS_STOP_2:
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
cflag |= CSTOPB;
break;
default:
dbg("%s - Unknown number of stop bits, "
- "using 1 stop bit", __FUNCTION__);
+ "using 1 stop bit", __func__);
bits &= ~BITS_STOP_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
break;
@@ -483,10 +483,10 @@ static void cp2101_get_termios (struct usb_serial_port *port)
cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
if (modem_ctl[0] & 0x0008) {
- dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+ dbg("%s - flow control = CRTSCTS", __func__);
cflag |= CRTSCTS;
} else {
- dbg("%s - flow control = NONE", __FUNCTION__);
+ dbg("%s - flow control = NONE", __func__);
cflag &= ~CRTSCTS;
}
@@ -500,10 +500,10 @@ static void cp2101_set_termios (struct usb_serial_port *port,
int baud=0, bits;
unsigned int modem_ctl[4];
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty structures", __FUNCTION__);
+ dbg("%s - no tty structures", __func__);
return;
}
port->tty->termios->c_cflag &= ~CMSPAR;
@@ -542,7 +542,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
}
if (baud) {
- dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
+ dbg("%s - Setting baud rate to %d baud", __func__,
baud);
if (cp2101_set_config_single(port, CP2101_BAUDRATE,
(BAUD_RATE_GEN_FREQ / baud))) {
@@ -562,23 +562,23 @@ static void cp2101_set_termios (struct usb_serial_port *port,
switch (cflag & CSIZE) {
case CS5:
bits |= BITS_DATA_5;
- dbg("%s - data bits = 5", __FUNCTION__);
+ dbg("%s - data bits = 5", __func__);
break;
case CS6:
bits |= BITS_DATA_6;
- dbg("%s - data bits = 6", __FUNCTION__);
+ dbg("%s - data bits = 6", __func__);
break;
case CS7:
bits |= BITS_DATA_7;
- dbg("%s - data bits = 7", __FUNCTION__);
+ dbg("%s - data bits = 7", __func__);
break;
case CS8:
bits |= BITS_DATA_8;
- dbg("%s - data bits = 8", __FUNCTION__);
+ dbg("%s - data bits = 8", __func__);
break;
/*case CS9:
bits |= BITS_DATA_9;
- dbg("%s - data bits = 9", __FUNCTION__);
+ dbg("%s - data bits = 9", __func__);
break;*/
default:
dev_err(&port->dev, "cp2101 driver does not "
@@ -598,10 +598,10 @@ static void cp2101_set_termios (struct usb_serial_port *port,
if (cflag & PARENB) {
if (cflag & PARODD) {
bits |= BITS_PARITY_ODD;
- dbg("%s - parity = ODD", __FUNCTION__);
+ dbg("%s - parity = ODD", __func__);
} else {
bits |= BITS_PARITY_EVEN;
- dbg("%s - parity = EVEN", __FUNCTION__);
+ dbg("%s - parity = EVEN", __func__);
}
}
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
@@ -614,10 +614,10 @@ static void cp2101_set_termios (struct usb_serial_port *port,
bits &= ~BITS_STOP_MASK;
if (cflag & CSTOPB) {
bits |= BITS_STOP_2;
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
} else {
bits |= BITS_STOP_1;
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
}
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
dev_err(&port->dev, "Number of stop bits requested "
@@ -627,23 +627,23 @@ static void cp2101_set_termios (struct usb_serial_port *port,
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
- __FUNCTION__, modem_ctl[0], modem_ctl[1],
+ __func__, modem_ctl[0], modem_ctl[1],
modem_ctl[2], modem_ctl[3]);
if (cflag & CRTSCTS) {
modem_ctl[0] &= ~0x7B;
modem_ctl[0] |= 0x09;
modem_ctl[1] = 0x80;
- dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+ dbg("%s - flow control = CRTSCTS", __func__);
} else {
modem_ctl[0] &= ~0x7B;
modem_ctl[0] |= 0x01;
modem_ctl[1] |= 0x40;
- dbg("%s - flow control = NONE", __FUNCTION__);
+ dbg("%s - flow control = NONE", __func__);
}
dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
- __FUNCTION__, modem_ctl[0], modem_ctl[1],
+ __func__, modem_ctl[0], modem_ctl[1],
modem_ctl[2], modem_ctl[3]);
cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
}
@@ -655,7 +655,7 @@ static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
{
int control = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (set & TIOCM_RTS) {
control |= CONTROL_RTS;
@@ -674,7 +674,7 @@ static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
control |= CONTROL_WRITE_DTR;
}
- dbg("%s - control = 0x%.4x", __FUNCTION__, control);
+ dbg("%s - control = 0x%.4x", __func__, control);
return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
@@ -684,7 +684,7 @@ static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
{
int control, result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
cp2101_get_config(port, CP2101_CONTROL, &control, 1);
@@ -695,7 +695,7 @@ static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
|((control & CONTROL_RING)? TIOCM_RI : 0)
|((control & CONTROL_DCD) ? TIOCM_CD : 0);
- dbg("%s - control = 0x%.2x", __FUNCTION__, control);
+ dbg("%s - control = 0x%.2x", __func__, control);
return result;
}
@@ -704,12 +704,12 @@ static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
{
int state;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (break_state == 0)
state = BREAK_OFF;
else
state = BREAK_ON;
- dbg("%s - turning break %s", __FUNCTION__,
+ dbg("%s - turning break %s", __func__,
state==BREAK_OFF ? "off" : "on");
cp2101_set_config(port, CP2101_BREAK, &state, 2);
}
@@ -725,7 +725,7 @@ static void cp2101_shutdown (struct usb_serial *serial)
{
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 8d9b045aa7e8..c164e2cf2752 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -90,9 +90,6 @@ static struct usb_serial_driver cyberjack_device = {
.description = "Reiner SCT Cyberjack USB card reader",
.usb_driver = &cyberjack_driver,
.id_table = id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.attach = cyberjack_startup,
.shutdown = cyberjack_shutdown,
@@ -119,7 +116,7 @@ static int cyberjack_startup (struct usb_serial *serial)
struct cyberjack_private *priv;
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* allocate the private data structure */
priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
@@ -142,7 +139,7 @@ static int cyberjack_startup (struct usb_serial *serial)
GFP_KERNEL);
if (result)
err(" usb_submit_urb(read int) failed");
- dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
+ dbg("%s - usb_submit_urb(int urb)", __func__);
}
return( 0 );
@@ -152,9 +149,9 @@ static void cyberjack_shutdown (struct usb_serial *serial)
{
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
- for (i=0; i < serial->num_ports; ++i) {
+ for (i = 0; i < serial->num_ports; ++i) {
usb_kill_urb(serial->port[i]->interrupt_in_urb);
/* My special items, the standard routines free my urbs */
kfree(usb_get_serial_port_data(serial->port[i]));
@@ -168,9 +165,9 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
- dbg("%s - usb_clear_halt", __FUNCTION__ );
+ dbg("%s - usb_clear_halt", __func__ );
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
/* force low_latency on so that our tty_push actually forces
@@ -191,7 +188,7 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp)
static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (port->serial->dev) {
/* shutdown any bulk reads that might be going on */
@@ -208,17 +205,17 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
int result;
int wrexpected;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
- return (0);
+ dbg("%s - write request of 0 bytes", __func__);
+ return 0;
}
spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
spin_unlock_bh(&port->lock);
- dbg("%s - already writing", __FUNCTION__);
+ dbg("%s - already writing", __func__);
return 0;
}
port->write_urb_busy = 1;
@@ -226,24 +223,24 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
spin_lock_irqsave(&priv->lock, flags);
- if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
+ if( (count+priv->wrfilled) > sizeof(priv->wrbuf) ) {
/* To much data for buffer. Reset buffer. */
- priv->wrfilled=0;
- spin_unlock_irqrestore(&priv->lock, flags);
+ priv->wrfilled = 0;
port->write_urb_busy = 0;
- return (0);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
}
/* Copy data */
memcpy (priv->wrbuf+priv->wrfilled, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
+ usb_serial_debug_data(debug, &port->dev, __func__, count,
priv->wrbuf+priv->wrfilled);
priv->wrfilled += count;
if( priv->wrfilled >= 3 ) {
wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
- dbg("%s - expected data: %d", __FUNCTION__, wrexpected);
+ dbg("%s - expected data: %d", __func__, wrexpected);
} else {
wrexpected = sizeof(priv->wrbuf);
}
@@ -252,7 +249,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
/* We have enough data to begin transmission */
int length;
- dbg("%s - transmitting data (frame 1)", __FUNCTION__);
+ dbg("%s - transmitting data (frame 1)", __func__);
length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected;
memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length );
@@ -270,23 +267,23 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
/* Throw away data. No better idea what to do with it. */
- priv->wrfilled=0;
- priv->wrsent=0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
spin_unlock_irqrestore(&priv->lock, flags);
port->write_urb_busy = 0;
return 0;
}
- dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent);
- dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled);
+ dbg("%s - priv->wrsent=%d", __func__,priv->wrsent);
+ dbg("%s - priv->wrfilled=%d", __func__,priv->wrfilled);
if( priv->wrsent>=priv->wrfilled ) {
- dbg("%s - buffer cleaned", __FUNCTION__);
+ dbg("%s - buffer cleaned", __func__);
memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
- priv->wrfilled=0;
- priv->wrsent=0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
}
}
@@ -297,27 +294,28 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
static int cyberjack_write_room( struct usb_serial_port *port )
{
+ /* FIXME: .... */
return CYBERJACK_LOCAL_BUF_SIZE;
}
static void cyberjack_read_int_callback( struct urb *urb )
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* the urb might have been killed. */
if (status)
return;
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
/* React only to interrupts signaling a bulk_in transfer */
- if( (urb->actual_length==4) && (data[0]==0x01) ) {
+ if( (urb->actual_length == 4) && (data[0] == 0x01) ) {
short old_rdtodo;
/* This is a announcement of coming bulk_ins. */
@@ -336,7 +334,7 @@ static void cyberjack_read_int_callback( struct urb *urb )
/* "+=" is probably more fault tollerant than "=" */
priv->rdtodo += size;
- dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo);
+ dbg("%s - rdtodo: %d", __func__, priv->rdtodo);
spin_unlock(&priv->lock);
@@ -344,8 +342,8 @@ static void cyberjack_read_int_callback( struct urb *urb )
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if( result )
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
- dbg("%s - usb_submit_urb(read urb)", __FUNCTION__);
+ err("%s - failed resubmitting read urb, error %d", __func__, result);
+ dbg("%s - usb_submit_urb(read urb)", __func__);
}
}
@@ -354,12 +352,12 @@ resubmit:
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
err(" usb_submit_urb(read int) failed");
- dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
+ dbg("%s - usb_submit_urb(int urb)", __func__);
}
static void cyberjack_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
@@ -367,18 +365,18 @@ static void cyberjack_read_bulk_callback (struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
tty = port->tty;
if (!tty) {
- dbg("%s - ignoring since device not open\n", __FUNCTION__);
+ dbg("%s - ignoring since device not open\n", __func__);
return;
}
if (urb->actual_length) {
@@ -397,30 +395,30 @@ static void cyberjack_read_bulk_callback (struct urb *urb)
spin_unlock(&priv->lock);
- dbg("%s - rdtodo: %d", __FUNCTION__, todo);
+ dbg("%s - rdtodo: %d", __func__, todo);
/* Continue to read if we have still urbs to do. */
if( todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
- dbg("%s - usb_submit_urb(read urb)", __FUNCTION__);
+ err("%s - failed resubmitting read urb, error %d", __func__, result);
+ dbg("%s - usb_submit_urb(read urb)", __func__);
}
}
static void cyberjack_write_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
port->write_urb_busy = 0;
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -430,7 +428,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb)
if( priv->wrfilled ) {
int length, blksize, result;
- dbg("%s - transmitting data (frame n)", __FUNCTION__);
+ dbg("%s - transmitting data (frame n)", __func__);
length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
port->bulk_out_size : (priv->wrfilled - priv->wrsent);
@@ -451,23 +449,23 @@ static void cyberjack_write_bulk_callback (struct urb *urb)
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
/* Throw away data. No better idea what to do with it. */
- priv->wrfilled=0;
- priv->wrsent=0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
goto exit;
}
- dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent);
- dbg("%s - priv->wrfilled=%d", __FUNCTION__,priv->wrfilled);
+ dbg("%s - priv->wrsent=%d", __func__,priv->wrsent);
+ dbg("%s - priv->wrfilled=%d", __func__,priv->wrfilled);
blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) {
- dbg("%s - buffer cleaned", __FUNCTION__);
+ dbg("%s - buffer cleaned", __func__);
memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
- priv->wrfilled=0;
- priv->wrsent=0;
+ priv->wrfilled = 0;
+ priv->wrsent = 0;
}
}
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 779d07851a4d..0230d3c0888a 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -122,6 +122,11 @@ static struct usb_driver cypress_driver = {
.no_dynamic_id = 1,
};
+enum packet_format {
+ packet_format_1, /* b0:status, b1:payload count */
+ packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */
+};
+
struct cypress_private {
spinlock_t lock; /* private lock */
int chiptype; /* identifier of device, for quirks/etc */
@@ -139,8 +144,9 @@ struct cypress_private {
__u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
__u8 current_config; /* stores the current configuration byte */
__u8 rx_flags; /* throttling - used from whiteheat/ftdi_sio */
+ enum packet_format pkt_fmt; /* format to use for packet send / receive */
+ int get_cfg_unsafe; /* If true, the CYPRESS_GET_CONFIG is unsafe */
int baud_rate; /* stores current baud rate in integer form */
- int cbr_mask; /* stores current baud rate in masked form */
int isthrottled; /* if throttled, discard reads */
wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
char prev_status, diff_status; /* used for TIOCMIWAIT */
@@ -176,9 +182,6 @@ static void cypress_unthrottle (struct usb_serial_port *port);
static void cypress_set_dead (struct usb_serial_port *port);
static void cypress_read_int_callback (struct urb *urb);
static void cypress_write_int_callback (struct urb *urb);
-/* baud helper functions */
-static int mask_to_rate (unsigned mask);
-static unsigned rate_to_mask (int rate);
/* write buffer functions */
static struct cypress_buf *cypress_buf_alloc(unsigned int size);
static void cypress_buf_free(struct cypress_buf *cb);
@@ -197,10 +200,6 @@ static struct usb_serial_driver cypress_earthmate_device = {
.description = "DeLorme Earthmate USB",
.usb_driver = &cypress_driver,
.id_table = id_table_earthmate,
- .num_interrupt_in = 1,
- .num_interrupt_out = 1,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.attach = cypress_earthmate_startup,
.shutdown = cypress_shutdown,
@@ -227,10 +226,6 @@ static struct usb_serial_driver cypress_hidcom_device = {
.description = "HID->COM RS232 Adapter",
.usb_driver = &cypress_driver,
.id_table = id_table_cyphidcomrs232,
- .num_interrupt_in = 1,
- .num_interrupt_out = 1,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.attach = cypress_hidcom_startup,
.shutdown = cypress_shutdown,
@@ -257,10 +252,6 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.description = "Nokia CA-42 V2 Adapter",
.usb_driver = &cypress_driver,
.id_table = id_table_nokiaca42v2,
- .num_interrupt_in = 1,
- .num_interrupt_out = 1,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.attach = cypress_ca42v2_startup,
.shutdown = cypress_shutdown,
@@ -284,16 +275,62 @@ static struct usb_serial_driver cypress_ca42v2_device = {
*****************************************************************************/
+static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
+{
+ struct cypress_private *priv;
+ priv = usb_get_serial_port_data(port);
+
+ /*
+ * The general purpose firmware for the Cypress M8 allows for
+ * a maximum speed of 57600bps (I have no idea whether DeLorme
+ * chose to use the general purpose firmware or not), if you
+ * need to modify this speed setting for your own project
+ * please add your own chiptype and modify the code likewise.
+ * The Cypress HID->COM device will work successfully up to
+ * 115200bps (but the actual throughput is around 3kBps).
+ */
+ if (port->serial->dev->speed == USB_SPEED_LOW) {
+ /*
+ * Mike Isely <isely@pobox.com> 2-Feb-2008: The
+ * Cypress app note that describes this mechanism
+ * states the the low-speed part can't handle more
+ * than 800 bytes/sec, in which case 4800 baud is the
+ * safest speed for a part like that.
+ */
+ if (new_rate > 4800) {
+ dbg("%s - failed setting baud rate, device incapable "
+ "speed %d", __func__, new_rate);
+ return -1;
+ }
+ }
+ switch (priv->chiptype) {
+ case CT_EARTHMATE:
+ if (new_rate <= 600) {
+ /* 300 and 600 baud rates are supported under
+ * the generic firmware, but are not used with
+ * NMEA and SiRF protocols */
+ dbg("%s - failed setting baud rate, unsupported speed "
+ "of %d on Earthmate GPS", __func__, new_rate);
+ return -1;
+ }
+ break;
+ default:
+ break;
+ }
+ return new_rate;
+}
+
+
/* This function can either set or retrieve the current serial line settings */
-static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits,
+static int cypress_serial_control (struct usb_serial_port *port, speed_t baud_rate, int data_bits, int stop_bits,
int parity_enable, int parity_type, int reset, int cypress_request_type)
{
int new_baudrate = 0, retval = 0, tries = 0;
struct cypress_private *priv;
- __u8 feature_buffer[8];
+ __u8 feature_buffer[5];
unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
priv = usb_get_serial_port_data(port);
@@ -302,58 +339,23 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
switch(cypress_request_type) {
case CYPRESS_SET_CONFIG:
-
- /*
- * The general purpose firmware for the Cypress M8 allows for a maximum speed
- * of 57600bps (I have no idea whether DeLorme chose to use the general purpose
- * firmware or not), if you need to modify this speed setting for your own
- * project please add your own chiptype and modify the code likewise. The
- * Cypress HID->COM device will work successfully up to 115200bps (but the
- * actual throughput is around 3kBps).
- */
- if (baud_mask != priv->cbr_mask) {
- dbg("%s - baud rate is changing", __FUNCTION__);
- if ( priv->chiptype == CT_EARTHMATE ) {
- /* 300 and 600 baud rates are supported under the generic firmware,
- * but are not used with NMEA and SiRF protocols */
-
- if ( (baud_mask == B300) || (baud_mask == B600) ) {
- err("%s - failed setting baud rate, unsupported speed",
- __FUNCTION__);
- new_baudrate = priv->baud_rate;
- } else if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
- err("%s - failed setting baud rate, unsupported speed",
- __FUNCTION__);
- new_baudrate = priv->baud_rate;
- }
- } else if (priv->chiptype == CT_CYPHIDCOM) {
- if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
- err("%s - failed setting baud rate, unsupported speed",
- __FUNCTION__);
- new_baudrate = priv->baud_rate;
- }
- } else if (priv->chiptype == CT_CA42V2) {
- if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
- err("%s - failed setting baud rate, unsupported speed",
- __FUNCTION__);
- new_baudrate = priv->baud_rate;
- }
- } else if (priv->chiptype == CT_GENERIC) {
- if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
- err("%s - failed setting baud rate, unsupported speed",
- __FUNCTION__);
- new_baudrate = priv->baud_rate;
- }
- } else {
- info("%s - please define your chiptype", __FUNCTION__);
- new_baudrate = priv->baud_rate;
- }
- } else { /* baud rate not changing, keep the old */
+ new_baudrate = priv->baud_rate;
+ /* 0 means 'Hang up' so doesn't change the true bit rate */
+ if (baud_rate == 0)
new_baudrate = priv->baud_rate;
+ /* Change of speed ? */
+ else if (baud_rate != priv->baud_rate) {
+ dbg("%s - baud rate is changing", __func__);
+ retval = analyze_baud_rate(port, baud_rate);
+ if (retval >= 0) {
+ new_baudrate = retval;
+ dbg("%s - New baud rate set to %d",
+ __func__, new_baudrate);
+ }
}
- dbg("%s - baud rate is being sent as %d", __FUNCTION__, new_baudrate);
+ dbg("%s - baud rate is being sent as %d", __func__, new_baudrate);
- memset(feature_buffer, 0, 8);
+ memset(feature_buffer, 0, sizeof(feature_buffer));
/* fill the feature_buffer with new configuration */
*((u_int32_t *)feature_buffer) = new_baudrate;
@@ -365,48 +367,65 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
/* 1 bit gap */
feature_buffer[4] |= (reset << 7); /* assign reset at end of byte, 1 bit space */
- dbg("%s - device is being sent this feature report:", __FUNCTION__);
- dbg("%s - %02X - %02X - %02X - %02X - %02X", __FUNCTION__, feature_buffer[0], feature_buffer[1],
+ dbg("%s - device is being sent this feature report:", __func__);
+ dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, feature_buffer[0], feature_buffer[1],
feature_buffer[2], feature_buffer[3], feature_buffer[4]);
do {
- retval = usb_control_msg (port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
- HID_REQ_SET_REPORT, USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
- 0x0300, 0, feature_buffer, 8, 500);
+ retval = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ HID_REQ_SET_REPORT,
+ USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+ 0x0300, 0, feature_buffer,
+ sizeof(feature_buffer), 500);
if (tries++ >= 3)
break;
- } while (retval != 8 && retval != -ENODEV);
+ } while (retval != sizeof(feature_buffer) &&
+ retval != -ENODEV);
- if (retval != 8) {
- err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
+ if (retval != sizeof(feature_buffer)) {
+ err("%s - failed sending serial line settings - %d", __func__, retval);
cypress_set_dead(port);
} else {
spin_lock_irqsave(&priv->lock, flags);
priv->baud_rate = new_baudrate;
- priv->cbr_mask = baud_mask;
priv->current_config = feature_buffer[4];
spin_unlock_irqrestore(&priv->lock, flags);
+ /* If we asked for a speed change encode it */
+ if (baud_rate)
+ tty_encode_baud_rate(port->tty,
+ new_baudrate, new_baudrate);
}
break;
case CYPRESS_GET_CONFIG:
- dbg("%s - retreiving serial line settings", __FUNCTION__);
+ if (priv->get_cfg_unsafe) {
+ /* Not implemented for this device,
+ and if we try to do it we're likely
+ to crash the hardware. */
+ return -ENOTTY;
+ }
+ dbg("%s - retreiving serial line settings", __func__);
/* set initial values in feature buffer */
- memset(feature_buffer, 0, 8);
+ memset(feature_buffer, 0, sizeof(feature_buffer));
do {
- retval = usb_control_msg (port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0),
- HID_REQ_GET_REPORT, USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
- 0x0300, 0, feature_buffer, 8, 500);
-
+ retval = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+ 0x0300, 0, feature_buffer,
+ sizeof(feature_buffer), 500);
+
if (tries++ >= 3)
break;
- } while (retval != 5 && retval != -ENODEV);
+ } while (retval != sizeof(feature_buffer) &&
+ retval != -ENODEV);
- if (retval != 5) {
- err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval);
+ if (retval != sizeof(feature_buffer)) {
+ err("%s - failed to retrieve serial line settings - %d", __func__, retval);
cypress_set_dead(port);
return retval;
} else {
@@ -415,9 +434,6 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
/* store the config in one byte, and later use bit masks to check values */
priv->current_config = feature_buffer[4];
priv->baud_rate = *((u_int32_t *)feature_buffer);
-
- if ( (priv->cbr_mask = rate_to_mask(priv->baud_rate)) == 0x40)
- dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__);
spin_unlock_irqrestore(&priv->lock, flags);
}
}
@@ -447,51 +463,6 @@ static void cypress_set_dead(struct usb_serial_port *port)
}
-/* given a baud mask, it will return integer baud on success */
-static int mask_to_rate (unsigned mask)
-{
- int rate;
-
- switch (mask) {
- case B0: rate = 0; break;
- case B300: rate = 300; break;
- case B600: rate = 600; break;
- case B1200: rate = 1200; break;
- case B2400: rate = 2400; break;
- case B4800: rate = 4800; break;
- case B9600: rate = 9600; break;
- case B19200: rate = 19200; break;
- case B38400: rate = 38400; break;
- case B57600: rate = 57600; break;
- case B115200: rate = 115200; break;
- default: rate = -1;
- }
-
- return rate;
-}
-
-
-static unsigned rate_to_mask (int rate)
-{
- unsigned mask;
-
- switch (rate) {
- case 0: mask = B0; break;
- case 300: mask = B300; break;
- case 600: mask = B600; break;
- case 1200: mask = B1200; break;
- case 2400: mask = B2400; break;
- case 4800: mask = B4800; break;
- case 9600: mask = B9600; break;
- case 19200: mask = B19200; break;
- case 38400: mask = B38400; break;
- case 57600: mask = B57600; break;
- case 115200: mask = B115200; break;
- default: mask = 0x40;
- }
-
- return mask;
-}
/*****************************************************************************
* Cypress serial driver functions
*****************************************************************************/
@@ -502,7 +473,7 @@ static int generic_startup (struct usb_serial *serial)
struct cypress_private *priv;
struct usb_serial_port *port = serial->port[0];
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
if (!priv)
@@ -523,17 +494,27 @@ static int generic_startup (struct usb_serial *serial)
priv->line_control = 0;
priv->termios_initialized = 0;
priv->rx_flags = 0;
- priv->cbr_mask = B300;
+ /* Default packet format setting is determined by packet size.
+ Anything with a size larger then 9 must have a separate
+ count field since the 3 bit count field is otherwise too
+ small. Otherwise we can use the slightly more compact
+ format. This is in accordance with the cypress_m8 serial
+ converter app note. */
+ if (port->interrupt_out_size > 9) {
+ priv->pkt_fmt = packet_format_1;
+ } else {
+ priv->pkt_fmt = packet_format_2;
+ }
if (interval > 0) {
priv->write_urb_interval = interval;
priv->read_urb_interval = interval;
dbg("%s - port %d read & write intervals forced to %d",
- __FUNCTION__,port->number,interval);
+ __func__,port->number,interval);
} else {
priv->write_urb_interval = port->interrupt_out_urb->interval;
priv->read_urb_interval = port->interrupt_in_urb->interval;
dbg("%s - port %d intervals: read=%d write=%d",
- __FUNCTION__,port->number,
+ __func__,port->number,
priv->read_urb_interval,priv->write_urb_interval);
}
usb_set_serial_port_data(port, priv);
@@ -545,17 +526,30 @@ static int generic_startup (struct usb_serial *serial)
static int cypress_earthmate_startup (struct usb_serial *serial)
{
struct cypress_private *priv;
+ struct usb_serial_port *port = serial->port[0];
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (generic_startup(serial)) {
- dbg("%s - Failed setting up port %d", __FUNCTION__,
- serial->port[0]->number);
+ dbg("%s - Failed setting up port %d", __func__,
+ port->number);
return 1;
}
- priv = usb_get_serial_port_data(serial->port[0]);
+ priv = usb_get_serial_port_data(port);
priv->chiptype = CT_EARTHMATE;
+ /* All Earthmate devices use the separated-count packet
+ format! Idiotic. */
+ priv->pkt_fmt = packet_format_1;
+ if (serial->dev->descriptor.idProduct != cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) {
+ /* The old original USB Earthmate seemed able to
+ handle GET_CONFIG requests; everything they've
+ produced since that time crashes if this command is
+ attempted :-( */
+ dbg("%s - Marking this device as unsafe for GET_CONFIG "
+ "commands", __func__);
+ priv->get_cfg_unsafe = !0;
+ }
return 0;
} /* cypress_earthmate_startup */
@@ -565,10 +559,10 @@ static int cypress_hidcom_startup (struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (generic_startup(serial)) {
- dbg("%s - Failed setting up port %d", __FUNCTION__,
+ dbg("%s - Failed setting up port %d", __func__,
serial->port[0]->number);
return 1;
}
@@ -584,10 +578,10 @@ static int cypress_ca42v2_startup (struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (generic_startup(serial)) {
- dbg("%s - Failed setting up port %d", __FUNCTION__,
+ dbg("%s - Failed setting up port %d", __func__,
serial->port[0]->number);
return 1;
}
@@ -603,7 +597,7 @@ static void cypress_shutdown (struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg ("%s - port %d", __FUNCTION__, serial->port[0]->number);
+ dbg ("%s - port %d", __func__, serial->port[0]->number);
/* all open ports are closed at this point */
@@ -624,7 +618,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!priv->comm_is_ok)
return -EIO;
@@ -652,16 +646,16 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
result = cypress_write(port, NULL, 0);
if (result) {
- dev_err(&port->dev, "%s - failed setting the control lines - error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed setting the control lines - error %d\n", __func__, result);
return result;
} else
- dbg("%s - success setting the control lines", __FUNCTION__);
+ dbg("%s - success setting the control lines", __func__);
cypress_set_termios(port, &priv->tmp_termios);
/* setup the port and start reading from the device */
if(!port->interrupt_in_urb){
- err("%s - interrupt_in_urb is empty!", __FUNCTION__);
+ err("%s - interrupt_in_urb is empty!", __func__);
return(-1);
}
@@ -672,7 +666,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result){
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __func__, result);
cypress_set_dead(port);
}
@@ -688,7 +682,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
long timeout;
wait_queue_t wait;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from buffer */
spin_lock_irq(&priv->lock);
@@ -726,7 +720,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
timeout = 2*HZ;
schedule_timeout_interruptible(timeout);
- dbg("%s - stopping urbs", __FUNCTION__);
+ dbg("%s - stopping urbs", __func__);
usb_kill_urb (port->interrupt_in_urb);
usb_kill_urb (port->interrupt_out_urb);
@@ -755,7 +749,7 @@ static int cypress_write(struct usb_serial_port *port, const unsigned char *buf,
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+ dbg("%s - port %d, %d bytes", __func__, port->number, count);
/* line control commands, which need to be executed immediately,
are not put into the buffer for obvious reasons.
@@ -788,12 +782,12 @@ static void cypress_send(struct usb_serial_port *port)
if (!priv->comm_is_ok)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
- dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
+ dbg("%s - port %d", __func__, port->number);
+ dbg("%s - interrupt out size is %d", __func__, port->interrupt_out_size);
spin_lock_irqsave(&priv->lock, flags);
if (priv->write_urb_in_use) {
- dbg("%s - can't write, urb in use", __FUNCTION__);
+ dbg("%s - can't write, urb in use", __func__);
spin_unlock_irqrestore(&priv->lock, flags);
return;
}
@@ -803,21 +797,18 @@ static void cypress_send(struct usb_serial_port *port)
memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size);
spin_lock_irqsave(&priv->lock, flags);
- switch (port->interrupt_out_size) {
- case 32:
- /* this is for the CY7C64013... */
- offset = 2;
- port->interrupt_out_buffer[0] = priv->line_control;
- break;
- case 8:
- /* this is for the CY7C63743... */
- offset = 1;
- port->interrupt_out_buffer[0] = priv->line_control;
- break;
- default:
- dbg("%s - wrong packet size", __FUNCTION__);
- spin_unlock_irqrestore(&priv->lock, flags);
- return;
+ switch (priv->pkt_fmt) {
+ default:
+ case packet_format_1:
+ /* this is for the CY7C64013... */
+ offset = 2;
+ port->interrupt_out_buffer[0] = priv->line_control;
+ break;
+ case packet_format_2:
+ /* this is for the CY7C63743... */
+ offset = 1;
+ port->interrupt_out_buffer[0] = priv->line_control;
+ break;
}
if (priv->line_control & CONTROL_RESET)
@@ -825,7 +816,7 @@ static void cypress_send(struct usb_serial_port *port)
if (priv->cmd_ctrl) {
priv->cmd_count++;
- dbg("%s - line control command being issued", __FUNCTION__);
+ dbg("%s - line control command being issued", __func__);
spin_unlock_irqrestore(&priv->lock, flags);
goto send;
} else
@@ -838,15 +829,16 @@ static void cypress_send(struct usb_serial_port *port)
return;
}
- switch (port->interrupt_out_size) {
- case 32:
- port->interrupt_out_buffer[1] = count;
- break;
- case 8:
- port->interrupt_out_buffer[0] |= count;
+ switch (priv->pkt_fmt) {
+ default:
+ case packet_format_1:
+ port->interrupt_out_buffer[1] = count;
+ break;
+ case packet_format_2:
+ port->interrupt_out_buffer[0] |= count;
}
- dbg("%s - count is %d", __FUNCTION__, count);
+ dbg("%s - count is %d", __func__, count);
send:
spin_lock_irqsave(&priv->lock, flags);
@@ -856,9 +848,10 @@ send:
if (priv->cmd_ctrl)
actual_size = 1;
else
- actual_size = count + (port->interrupt_out_size == 32 ? 2 : 1);
-
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
+ actual_size = count +
+ (priv->pkt_fmt == packet_format_1 ? 2 : 1);
+
+ usb_serial_debug_data(debug, &port->dev, __func__, port->interrupt_out_size,
port->interrupt_out_urb->transfer_buffer);
usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
@@ -867,7 +860,7 @@ send:
cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
+ dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__,
result);
priv->write_urb_in_use = 0;
cypress_set_dead(port);
@@ -891,13 +884,13 @@ static int cypress_write_room(struct usb_serial_port *port)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
room = cypress_buf_space_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -909,7 +902,7 @@ static int cypress_tiocmget (struct usb_serial_port *port, struct file *file)
unsigned int result = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
@@ -923,7 +916,7 @@ static int cypress_tiocmget (struct usb_serial_port *port, struct file *file)
| ((status & UART_RI) ? TIOCM_RI : 0)
| ((status & UART_CD) ? TIOCM_CD : 0);
- dbg("%s - result = %x", __FUNCTION__, result);
+ dbg("%s - result = %x", __func__, result);
return result;
}
@@ -935,7 +928,7 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
@@ -946,9 +939,9 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
priv->line_control &= ~CONTROL_RTS;
if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR;
+ priv->cmd_ctrl = 1;
spin_unlock_irqrestore(&priv->lock, flags);
- priv->cmd_ctrl = 1;
return cypress_write(port, NULL, 0);
}
@@ -957,23 +950,9 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
{
struct cypress_private *priv = usb_get_serial_port_data(port);
- dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
switch (cmd) {
- case TIOCGSERIAL:
- if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) {
- return -EFAULT;
- }
- return (0);
- break;
- case TIOCSSERIAL:
- if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) {
- return -EFAULT;
- }
- /* here we need to call cypress_set_termios to invoke the new settings */
- cypress_set_termios(port, &priv->tmp_termios);
- return (0);
- break;
/* This code comes from drivers/char/serial.c and ftdi_sio.c */
case TIOCMIWAIT:
while (priv != NULL) {
@@ -1009,7 +988,7 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
break;
}
- dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __FUNCTION__, cmd);
+ dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd);
return -ENOIOCTLCMD;
} /* cypress_ioctl */
@@ -1021,18 +1000,14 @@ static void cypress_set_termios (struct usb_serial_port *port,
struct cypress_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
int data_bits, stop_bits, parity_type, parity_enable;
- unsigned cflag, iflag, baud_mask;
+ unsigned cflag, iflag;
unsigned long flags;
__u8 oldlines;
int linechange = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
tty = port->tty;
- if ((!tty) || (!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
@@ -1040,40 +1015,37 @@ static void cypress_set_termios (struct usb_serial_port *port,
*(tty->termios) = tty_std_termios;
tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
CLOCAL;
+ tty->termios->c_ispeed = 4800;
+ tty->termios->c_ospeed = 4800;
} else if (priv->chiptype == CT_CYPHIDCOM) {
*(tty->termios) = tty_std_termios;
tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
+ tty->termios->c_ispeed = 9600;
+ tty->termios->c_ospeed = 9600;
} else if (priv->chiptype == CT_CA42V2) {
*(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);
+ /* Unsupported features need clearing */
+ tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);
+
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
/* check if there are new settings */
if (old_termios) {
- if ((cflag != old_termios->c_cflag) ||
- (RELEVANT_IFLAG(iflag) !=
- RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - attempting to set new termios settings",
- __FUNCTION__);
- /* should make a copy of this in case something goes
- * wrong in the function, we can restore it */
- spin_lock_irqsave(&priv->lock, flags);
- priv->tmp_termios = *(tty->termios);
- spin_unlock_irqrestore(&priv->lock, flags);
- } else {
- dbg("%s - nothing to do, exiting", __FUNCTION__);
- return;
- }
- } else
- return;
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->tmp_termios = *(tty->termios);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
/* set number of data bits, parity, stop bits */
/* when parity is disabled the parity type bit is ignored */
@@ -1104,7 +1076,7 @@ static void cypress_set_termios (struct usb_serial_port *port,
break;
default:
err("%s - CSIZE was set, but not CS5-CS8",
- __FUNCTION__);
+ __func__);
data_bits = 3;
}
} else
@@ -1114,54 +1086,17 @@ static void cypress_set_termios (struct usb_serial_port *port,
oldlines = priv->line_control;
if ((cflag & CBAUD) == B0) {
/* drop dtr and rts */
- dbg("%s - dropping the lines, baud rate 0bps", __FUNCTION__);
- baud_mask = B0;
+ dbg("%s - dropping the lines, baud rate 0bps", __func__);
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
- } else {
- baud_mask = (cflag & CBAUD);
- switch(baud_mask) {
- case B300:
- dbg("%s - setting baud 300bps", __FUNCTION__);
- break;
- case B600:
- dbg("%s - setting baud 600bps", __FUNCTION__);
- break;
- case B1200:
- dbg("%s - setting baud 1200bps", __FUNCTION__);
- break;
- case B2400:
- dbg("%s - setting baud 2400bps", __FUNCTION__);
- break;
- case B4800:
- dbg("%s - setting baud 4800bps", __FUNCTION__);
- break;
- case B9600:
- dbg("%s - setting baud 9600bps", __FUNCTION__);
- break;
- case B19200:
- dbg("%s - setting baud 19200bps", __FUNCTION__);
- break;
- case B38400:
- dbg("%s - setting baud 38400bps", __FUNCTION__);
- break;
- case B57600:
- dbg("%s - setting baud 57600bps", __FUNCTION__);
- break;
- case B115200:
- dbg("%s - setting baud 115200bps", __FUNCTION__);
- break;
- default:
- dbg("%s - unknown masked baud rate", __FUNCTION__);
- }
+ } else
priv->line_control = (CONTROL_DTR | CONTROL_RTS);
- }
spin_unlock_irqrestore(&priv->lock, flags);
dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
- "%d data_bits (+5)", __FUNCTION__, stop_bits,
+ "%d data_bits (+5)", __func__, stop_bits,
parity_enable, parity_type, data_bits);
- cypress_serial_control(port, baud_mask, data_bits, stop_bits,
+ cypress_serial_control(port, tty_get_baud_rate(tty), data_bits, stop_bits,
parity_enable, parity_type, 0, CYPRESS_SET_CONFIG);
/* we perform a CYPRESS_GET_CONFIG so that the current settings are
@@ -1219,13 +1154,13 @@ static int cypress_chars_in_buffer(struct usb_serial_port *port)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
chars = cypress_buf_data_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return chars;
}
@@ -1235,7 +1170,7 @@ static void cypress_throttle (struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->rx_flags = THROTTLED;
@@ -1249,7 +1184,7 @@ static void cypress_unthrottle (struct usb_serial_port *port)
int actually_throttled, result;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
@@ -1265,7 +1200,7 @@ static void cypress_unthrottle (struct usb_serial_port *port)
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, "
- "error %d\n", __FUNCTION__, result);
+ "error %d\n", __func__, result);
cypress_set_dead(port);
}
}
@@ -1274,7 +1209,7 @@ static void cypress_unthrottle (struct usb_serial_port *port)
static void cypress_read_int_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
@@ -1286,7 +1221,7 @@ static void cypress_read_int_callback(struct urb *urb)
int i = 0;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
switch (status) {
case 0: /* success */
@@ -1302,14 +1237,14 @@ static void cypress_read_int_callback(struct urb *urb)
default:
/* something ugly is going on... */
dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
- __FUNCTION__, status);
+ __func__, status);
cypress_set_dead(port);
return;
}
spin_lock_irqsave(&priv->lock, flags);
if (priv->rx_flags & THROTTLED) {
- dbg("%s - now throttling", __FUNCTION__);
+ dbg("%s - now throttling", __func__);
priv->rx_flags |= ACTUALLY_THROTTLED;
spin_unlock_irqrestore(&priv->lock, flags);
return;
@@ -1318,48 +1253,48 @@ static void cypress_read_int_callback(struct urb *urb)
tty = port->tty;
if (!tty) {
- dbg("%s - bad tty pointer - exiting", __FUNCTION__);
+ dbg("%s - bad tty pointer - exiting", __func__);
return;
}
spin_lock_irqsave(&priv->lock, flags);
- switch(urb->actual_length) {
- case 32:
- /* This is for the CY7C64013... */
- priv->current_status = data[0] & 0xF8;
- bytes = data[1] + 2;
- i = 2;
- if (bytes > 2)
- havedata = 1;
- break;
- case 8:
- /* This is for the CY7C63743... */
- priv->current_status = data[0] & 0xF8;
- bytes = (data[0] & 0x07) + 1;
- i = 1;
- if (bytes > 1)
- havedata = 1;
- break;
- default:
- dbg("%s - wrong packet size - received %d bytes",
- __FUNCTION__, urb->actual_length);
- spin_unlock_irqrestore(&priv->lock, flags);
- goto continue_read;
+ result = urb->actual_length;
+ switch (priv->pkt_fmt) {
+ default:
+ case packet_format_1:
+ /* This is for the CY7C64013... */
+ priv->current_status = data[0] & 0xF8;
+ bytes = data[1] + 2;
+ i = 2;
+ if (bytes > 2)
+ havedata = 1;
+ break;
+ case packet_format_2:
+ /* This is for the CY7C63743... */
+ priv->current_status = data[0] & 0xF8;
+ bytes = (data[0] & 0x07) + 1;
+ i = 1;
+ if (bytes > 1)
+ havedata = 1;
+ break;
}
spin_unlock_irqrestore(&priv->lock, flags);
+ if (result < bytes) {
+ dbg("%s - wrong packet size - received %d bytes but packet "
+ "said %d bytes", __func__, result, bytes);
+ goto continue_read;
+ }
- usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data (debug, &port->dev, __func__,
urb->actual_length, data);
spin_lock_irqsave(&priv->lock, flags);
/* check to see if status has changed */
- if (priv != NULL) {
- if (priv->current_status != priv->prev_status) {
- priv->diff_status |= priv->current_status ^
- priv->prev_status;
- wake_up_interruptible(&priv->delta_msr_wait);
- priv->prev_status = priv->current_status;
- }
+ if (priv->current_status != priv->prev_status) {
+ priv->diff_status |= priv->current_status ^
+ priv->prev_status;
+ wake_up_interruptible(&priv->delta_msr_wait);
+ priv->prev_status = priv->current_status;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1367,7 +1302,7 @@ static void cypress_read_int_callback(struct urb *urb)
* though */
if (tty && !(tty->termios->c_cflag & CLOCAL) &&
!(priv->current_status & UART_CD)) {
- dbg("%s - calling hangup", __FUNCTION__);
+ dbg("%s - calling hangup", __func__);
tty_hangup(tty);
goto continue_read;
}
@@ -1380,7 +1315,7 @@ static void cypress_read_int_callback(struct urb *urb)
if (priv->current_status & CYP_ERROR) {
spin_unlock_irqrestore(&priv->lock, flags);
tty_flag = TTY_PARITY;
- dbg("%s - Parity Error detected", __FUNCTION__);
+ dbg("%s - Parity Error detected", __func__);
} else
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1414,7 +1349,7 @@ continue_read:
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result) {
dev_err(&urb->dev->dev, "%s - failed resubmitting "
- "read urb, error %d\n", __FUNCTION__,
+ "read urb, error %d\n", __func__,
result);
cypress_set_dead(port);
}
@@ -1426,12 +1361,12 @@ continue_read:
static void cypress_write_int_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
switch (status) {
case 0:
@@ -1442,7 +1377,7 @@ static void cypress_write_int_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
priv->write_urb_in_use = 0;
return;
case -EPIPE: /* no break needed; clear halt and resubmit */
@@ -1451,19 +1386,19 @@ static void cypress_write_int_callback(struct urb *urb)
usb_clear_halt(port->serial->dev, 0x02);
/* error in the urb, so we have to resubmit it */
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
port->interrupt_out_urb->transfer_buffer_length = 1;
port->interrupt_out_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
if (!result)
return;
dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
cypress_set_dead(port);
break;
default:
dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
- __FUNCTION__, status);
+ __func__, status);
cypress_set_dead(port);
break;
}
@@ -1668,7 +1603,7 @@ static int __init cypress_init(void)
{
int retval;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
retval = usb_serial_register(&cypress_earthmate_device);
if (retval)
@@ -1699,7 +1634,7 @@ failed_em_register:
static void __exit cypress_exit (void)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
usb_deregister (&cypress_driver);
usb_serial_deregister (&cypress_earthmate_device);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 5f9c6e46bee5..d17d1645714f 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -508,9 +508,6 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.description = "Digi 2 port USB adapter",
.usb_driver = &digi_driver,
.id_table = id_table_2,
- .num_interrupt_in = 0,
- .num_bulk_in = 4,
- .num_bulk_out = 4,
.num_ports = 3,
.open = digi_open,
.close = digi_close,
@@ -538,9 +535,6 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.description = "Digi 4 port USB adapter",
.usb_driver = &digi_driver,
.id_table = id_table_4,
- .num_interrupt_in = 0,
- .num_bulk_in = 5,
- .num_bulk_out = 5,
.num_ports = 4,
.open = digi_open,
.close = digi_close,
@@ -665,7 +659,7 @@ static int digi_write_oob_command(struct usb_serial_port *port,
}
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);
+ err("%s: usb_submit_urb failed, ret=%d", __func__, ret);
return ret;
}
@@ -746,7 +740,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
if (ret)
err("%s: usb_submit_urb failed, ret=%d, port=%d",
- __FUNCTION__, ret, priv->dp_port_num);
+ __func__, ret, priv->dp_port_num);
return ret;
}
@@ -810,7 +804,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
spin_unlock(&port_priv->dp_port_lock);
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
if (ret)
- err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);
+ err("%s: usb_submit_urb failed, ret=%d", __func__, ret);
return ret;
}
@@ -903,7 +897,7 @@ static void digi_rx_unthrottle(struct usb_serial_port *port)
if (ret)
err("%s: usb_submit_urb failed, ret=%d, port=%d",
- __FUNCTION__, ret, priv->dp_port_num);
+ __func__, ret, priv->dp_port_num);
}
@@ -1113,7 +1107,7 @@ static int digi_tiocmget(struct usb_serial_port *port, struct file *file)
unsigned int val;
unsigned long flags;
- dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num);
+ dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = priv->dp_modem_signals;
@@ -1129,7 +1123,7 @@ static int digi_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int val;
unsigned long flags;
- dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num);
+ dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = (priv->dp_modem_signals & ~clear) | set;
@@ -1224,7 +1218,7 @@ static int digi_write(struct usb_serial_port *port, const unsigned char *buf, in
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret < 0)
err("%s: usb_submit_urb failed, ret=%d, port=%d",
- __FUNCTION__, ret, priv->dp_port_num);
+ __func__, ret, priv->dp_port_num);
dbg("digi_write: returning %d", ret);
return ret;
@@ -1233,7 +1227,7 @@ static int digi_write(struct usb_serial_port *port, const unsigned char *buf, in
static void digi_write_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct usb_serial *serial;
struct digi_port *priv;
struct digi_serial *serial_priv;
@@ -1245,13 +1239,13 @@ static void digi_write_bulk_callback(struct urb *urb)
/* port and serial sanity check */
if (port == NULL || (priv=usb_get_serial_port_data(port)) == NULL) {
err("%s: port or port->private is NULL, status=%d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
serial = port->serial;
if (serial == NULL || (serial_priv=usb_get_serial_data(serial)) == NULL) {
err("%s: serial or serial->private is NULL, status=%d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -1292,7 +1286,7 @@ static void digi_write_bulk_callback(struct urb *urb)
spin_unlock(&priv->dp_port_lock);
if (ret)
err("%s: usb_submit_urb failed, ret=%d, port=%d",
- __FUNCTION__, ret, priv->dp_port_num);
+ __func__, ret, priv->dp_port_num);
}
static int digi_write_room(struct usb_serial_port *port)
@@ -1521,7 +1515,7 @@ static int digi_startup_device(struct usb_serial *serial)
port->write_urb->dev = port->serial->dev;
if ((ret = usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0) {
err("%s: usb_submit_urb failed, ret=%d, port=%d",
- __FUNCTION__, ret, i);
+ __func__, ret, i);
break;
}
}
@@ -1611,7 +1605,7 @@ static void digi_shutdown(struct usb_serial *serial)
static void digi_read_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct digi_port *priv;
struct digi_serial *serial_priv;
int ret;
@@ -1622,20 +1616,20 @@ static void digi_read_bulk_callback(struct urb *urb)
/* port sanity check, do not resubmit if port is not valid */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
err("%s: port or port->private is NULL, status=%d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
if (port->serial == NULL ||
(serial_priv=usb_get_serial_data(port->serial)) == NULL) {
err("%s: serial is bad or serial->private is NULL, status=%d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
/* do not resubmit urb if it has any status error */
if (status) {
err("%s: nonzero read bulk status: status=%d, port=%d",
- __FUNCTION__, status, priv->dp_port_num);
+ __func__, status, priv->dp_port_num);
return;
}
@@ -1652,7 +1646,7 @@ static void digi_read_bulk_callback(struct urb *urb)
urb->dev = port->serial->dev;
if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
err("%s: failed resubmitting urb, ret=%d, port=%d",
- __FUNCTION__, ret, priv->dp_port_num);
+ __func__, ret, priv->dp_port_num);
}
}
@@ -1670,7 +1664,7 @@ static void digi_read_bulk_callback(struct urb *urb)
static int digi_read_inb_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty = port->tty;
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
@@ -1690,7 +1684,7 @@ static int digi_read_inb_callback(struct urb *urb)
if (urb->actual_length != len + 2) {
err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, "
"port=%d, opcode=%d, len=%d, actual_length=%d, "
- "status=%d", __FUNCTION__, status, priv->dp_port_num,
+ "status=%d", __func__, status, priv->dp_port_num,
opcode, len, urb->actual_length, port_status);
return -1;
}
@@ -1739,9 +1733,9 @@ static int digi_read_inb_callback(struct urb *urb)
spin_unlock(&priv->dp_port_lock);
if (opcode == DIGI_CMD_RECEIVE_DISABLE)
- dbg("%s: got RECEIVE_DISABLE", __FUNCTION__);
+ dbg("%s: got RECEIVE_DISABLE", __func__);
else if (opcode != DIGI_CMD_RECEIVE_DATA)
- dbg("%s: unknown opcode: %d", __FUNCTION__, opcode);
+ dbg("%s: unknown opcode: %d", __func__, opcode);
return(throttled ? 1 : 0);
@@ -1760,7 +1754,7 @@ static int digi_read_inb_callback(struct urb *urb)
static int digi_read_oob_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct usb_serial *serial = port->serial;
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode, line, status, val;
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index a5c8e1e17ea5..c5ec309a3cb1 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -118,9 +118,6 @@ static struct usb_serial_driver empeg_device = {
},
.id_table = id_table,
.usb_driver = &empeg_driver,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = empeg_open,
.close = empeg_close,
@@ -153,7 +150,7 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* Force default termio settings */
empeg_set_termios (port, NULL) ;
@@ -175,7 +172,7 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __func__, result);
return result;
}
@@ -183,7 +180,7 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
static void empeg_close (struct usb_serial_port *port, struct file * filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* shutdown our bulk read */
usb_kill_urb(port->read_urb);
@@ -203,7 +200,7 @@ static int empeg_write (struct usb_serial_port *port, const unsigned char *buf,
int bytes_sent = 0;
int transfer_size;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
while (count > 0) {
@@ -222,14 +219,14 @@ static int empeg_write (struct usb_serial_port *port, const unsigned char *buf,
spin_unlock_irqrestore (&write_urb_pool_lock, flags);
if (urb == NULL) {
- dbg("%s - no more free urbs", __FUNCTION__);
+ dbg("%s - no more free urbs", __func__);
goto exit;
}
if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
if (urb->transfer_buffer == NULL) {
- dev_err(&port->dev, "%s no more kernel memory...\n", __FUNCTION__);
+ dev_err(&port->dev, "%s no more kernel memory...\n", __func__);
goto exit;
}
}
@@ -238,7 +235,7 @@ static int empeg_write (struct usb_serial_port *port, const unsigned char *buf,
memcpy (urb->transfer_buffer, current_position, transfer_size);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, urb->transfer_buffer);
/* build up our urb */
usb_fill_bulk_urb (
@@ -254,7 +251,7 @@ static int empeg_write (struct usb_serial_port *port, const unsigned char *buf,
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status);
bytes_sent = status;
break;
}
@@ -278,7 +275,7 @@ static int empeg_write_room (struct usb_serial_port *port)
int i;
int room = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave (&write_urb_pool_lock, flags);
@@ -291,7 +288,7 @@ static int empeg_write_room (struct usb_serial_port *port)
spin_unlock_irqrestore (&write_urb_pool_lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return (room);
@@ -304,7 +301,7 @@ static int empeg_chars_in_buffer (struct usb_serial_port *port)
int i;
int chars = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave (&write_urb_pool_lock, flags);
@@ -317,7 +314,7 @@ static int empeg_chars_in_buffer (struct usb_serial_port *port)
spin_unlock_irqrestore (&write_urb_pool_lock, flags);
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return (chars);
@@ -329,11 +326,11 @@ static void empeg_write_bulk_callback (struct urb *urb)
struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -343,21 +340,21 @@ static void empeg_write_bulk_callback (struct urb *urb)
static void empeg_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
tty = port->tty;
@@ -382,7 +379,7 @@ static void empeg_read_bulk_callback (struct urb *urb)
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
return;
@@ -391,7 +388,7 @@ static void empeg_read_bulk_callback (struct urb *urb)
static void empeg_throttle (struct usb_serial_port *port)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->read_urb);
}
@@ -400,14 +397,14 @@ static void empeg_unthrottle (struct usb_serial_port *port)
{
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __func__, result);
return;
}
@@ -417,14 +414,14 @@ static int empeg_startup (struct usb_serial *serial)
{
int r;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
err("active config #%d != 1 ??",
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
- dbg("%s - reset config", __FUNCTION__);
+ dbg("%s - reset config", __func__);
r = usb_reset_configuration (serial->dev);
/* continue on with initialization */
@@ -435,13 +432,13 @@ static int empeg_startup (struct usb_serial *serial)
static void empeg_shutdown (struct usb_serial *serial)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
- dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
return -ENOIOCTLCMD;
}
@@ -450,7 +447,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign
static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct ktermios *termios = port->tty->termios;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* The empeg-car player wants these particular tty settings.
@@ -517,7 +514,7 @@ static int __init empeg_init (void)
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (!urb->transfer_buffer) {
err("%s - out of memory for urb buffers.",
- __FUNCTION__);
+ __func__);
continue;
}
}
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 3f698baa0abb..cc4fbd9d60be 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -27,13 +27,13 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
/* dbg("ezusb_writememory %x, %d", address, length); */
if (!serial->dev) {
- err("%s - no physical device present, failing.", __FUNCTION__);
+ err("%s - no physical device present, failing.", __func__);
return -ENODEV;
}
transfer_buffer = kmemdup(data, length, GFP_KERNEL);
if (!transfer_buffer) {
- dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, length);
+ dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __func__, length);
return -ENOMEM;
}
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3000);
@@ -45,10 +45,10 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
{
int response;
- /* dbg("%s - %d", __FUNCTION__, reset_bit); */
+ /* dbg("%s - %d", __func__, reset_bit); */
response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0)
- dev_err(&serial->dev->dev, "%s- %d failed\n", __FUNCTION__, reset_bit);
+ dev_err(&serial->dev->dev, "%s- %d failed\n", __func__, reset_bit);
return response;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 3abb3c863647..c7329f43d9c9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -439,9 +439,6 @@ static struct usb_serial_driver ftdi_sio_device = {
.description = "FTDI USB Serial Device",
.usb_driver = &ftdi_driver ,
.id_table = id_table_combined,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.probe = ftdi_sio_probe,
.port_probe = ftdi_sio_port_probe,
@@ -528,14 +525,13 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
int rv;
if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
- dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__);
+ dbg("%s - DTR|RTS not being set|cleared", __func__);
return 0; /* no change */
}
buf = kmalloc(1, GFP_NOIO);
- if (!buf) {
+ if (!buf)
return -ENOMEM;
- }
clear &= ~set; /* 'set' takes precedence over 'clear' */
urb_value = 0;
@@ -557,17 +553,18 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
kfree(buf);
if (rv < 0) {
err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
- __FUNCTION__,
+ __func__,
(set & TIOCM_DTR) ? "HIGH" :
(clear & TIOCM_DTR) ? "LOW" : "unchanged",
(set & TIOCM_RTS) ? "HIGH" :
(clear & TIOCM_RTS) ? "LOW" : "unchanged");
} else {
- dbg("%s - DTR %s, RTS %s", __FUNCTION__,
+ dbg("%s - DTR %s, RTS %s", __func__,
(set & TIOCM_DTR) ? "HIGH" :
(clear & TIOCM_DTR) ? "LOW" : "unchanged",
(set & TIOCM_RTS) ? "HIGH" :
(clear & TIOCM_RTS) ? "LOW" : "unchanged");
+ /* FIXME: locking on last_dtr_rts */
priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
}
return rv;
@@ -642,7 +639,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
/* 1. Get the baud rate from the tty settings, this observes alt_speed hack */
baud = tty_get_baud_rate(port->tty);
- dbg("%s - tty_get_baud_rate reports speed %d", __FUNCTION__, baud);
+ dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud);
/* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */
@@ -650,7 +647,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
(priv->custom_divisor)) {
baud = priv->baud_base / priv->custom_divisor;
- dbg("%s - custom divisor %d sets baud rate to %d", __FUNCTION__, priv->custom_divisor, baud);
+ dbg("%s - custom divisor %d sets baud rate to %d", __func__, priv->custom_divisor, baud);
}
/* 3. Convert baudrate to device-specific divisor */
@@ -671,7 +668,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
if (div_value == 0) {
- dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
+ dbg("%s - Baudrate (%d) requested is not supported", __func__, baud);
div_value = ftdi_sio_b9600;
baud = 9600;
div_okay = 0;
@@ -681,7 +678,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
if (baud <= 3000000) {
div_value = ftdi_232am_baud_to_divisor(baud);
} else {
- dbg("%s - Baud rate too high!", __FUNCTION__);
+ dbg("%s - Baud rate too high!", __func__);
baud = 9600;
div_value = ftdi_232am_baud_to_divisor(9600);
div_okay = 0;
@@ -693,7 +690,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
if (baud <= 3000000) {
div_value = ftdi_232bm_baud_to_divisor(baud);
} else {
- dbg("%s - Baud rate too high!", __FUNCTION__);
+ dbg("%s - Baud rate too high!", __func__);
div_value = ftdi_232bm_baud_to_divisor(9600);
div_okay = 0;
baud = 9600;
@@ -703,7 +700,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
if (div_okay) {
dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
- __FUNCTION__, baud, (unsigned long)div_value,
+ __func__, baud, (unsigned long)div_value,
ftdi_chip_name[priv->chip_type]);
}
@@ -804,7 +801,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
version = le16_to_cpu(udev->descriptor.bcdDevice);
interfaces = udev->actconfig->desc.bNumInterfaces;
- dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__,
+ dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __func__,
version, interfaces);
if (interfaces > 1) {
int inter;
@@ -822,7 +819,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
* to 0x200 when iSerialNumber is 0. */
if (version < 0x500) {
dbg("%s: something fishy - bcdDevice too low for multi-interface device",
- __FUNCTION__);
+ __func__);
}
} else if (version < 0x200) {
/* Old device. Assume its the original SIO. */
@@ -860,7 +857,7 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
int rv = 0;
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
@@ -887,7 +884,7 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
- dbg("%s: setting latency timer = %i", __FUNCTION__, v);
+ dbg("%s: setting latency timer = %i", __func__, v);
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
@@ -916,7 +913,7 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
- dbg("%s: setting event char = %i", __FUNCTION__, v);
+ dbg("%s: setting event char = %i", __func__, v);
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
@@ -941,7 +938,7 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int retval = 0;
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
/* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */
@@ -963,7 +960,7 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
@@ -1005,11 +1002,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv){
- err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
+ err("%s- kmalloc(%Zd) failed.", __func__, sizeof(struct ftdi_private));
return -ENOMEM;
}
@@ -1058,7 +1055,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
/* Called from usbserial:serial_probe */
static void ftdi_USB_UIRT_setup (struct ftdi_private *priv)
{
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
@@ -1069,7 +1066,7 @@ static void ftdi_USB_UIRT_setup (struct ftdi_private *priv)
* baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */
static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
{
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
@@ -1087,7 +1084,7 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- dbg("%s",__FUNCTION__);
+ dbg("%s",__func__);
if (interface == udev->actconfig->interface[0]) {
info("Ignoring serial port reserved for JTAG");
@@ -1107,7 +1104,7 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
struct usb_endpoint_descriptor *ep_desc = &ep->desc;
if (ep->enabled && ep_desc->wMaxPacketSize == 0) {
- ep_desc->wMaxPacketSize = 0x40;
+ ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
info("Fixing invalid wMaxPacketSize on read pipe");
}
@@ -1123,14 +1120,14 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
*/
static void ftdi_shutdown (struct usb_serial *serial)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
remove_sysfs_attrs(port);
@@ -1155,7 +1152,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_bytes = 0;
@@ -1200,7 +1197,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting read urb, error %d", __func__, result);
return result;
@@ -1222,7 +1219,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
mutex_lock(&port->serial->disc_mutex);
if (c_cflag & HUPCL && !port->serial->disconnected){
@@ -1269,7 +1266,7 @@ static int ftdi_write (struct usb_serial_port *port,
int transfer_size;
unsigned long flags;
- dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
+ dbg("%s port %d, %d bytes", __func__, port->number, count);
if (count == 0) {
dbg("write request of 0 bytes");
@@ -1278,7 +1275,7 @@ static int ftdi_write (struct usb_serial_port *port,
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
- dbg("%s - write limit hit\n", __FUNCTION__);
+ dbg("%s - write limit hit\n", __func__);
return 0;
}
priv->tx_outstanding_urbs++;
@@ -1298,14 +1295,14 @@ static int ftdi_write (struct usb_serial_port *port,
buffer = kmalloc (transfer_size, GFP_ATOMIC);
if (!buffer) {
- err("%s ran out of kernel memory for urb ...", __FUNCTION__);
+ err("%s ran out of kernel memory for urb ...", __func__);
count = -ENOMEM;
goto error_no_buffer;
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- err("%s - no more free urbs", __FUNCTION__);
+ err("%s - no more free urbs", __func__);
count = -ENOMEM;
goto error_no_urb;
}
@@ -1337,7 +1334,7 @@ static int ftdi_write (struct usb_serial_port *port,
memcpy (buffer, buf, count);
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, buffer);
/* fill the buffer and send it */
usb_fill_bulk_urb(urb, port->serial->dev,
@@ -1347,7 +1344,7 @@ static int ftdi_write (struct usb_serial_port *port,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
+ err("%s - failed submitting write urb, error %d", __func__, status);
count = status;
goto error;
} else {
@@ -1361,7 +1358,7 @@ static int ftdi_write (struct usb_serial_port *port,
* really free it when it is finished with it */
usb_free_urb(urb);
- dbg("%s write returning: %d", __FUNCTION__, count);
+ dbg("%s write returning: %d", __func__, count);
return count;
error:
usb_free_urb(urb);
@@ -1380,7 +1377,7 @@ error_no_buffer:
static void ftdi_write_bulk_callback (struct urb *urb)
{
unsigned long flags;
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct ftdi_private *priv;
int data_offset; /* will be 1 for the SIO and 0 otherwise */
unsigned long countback;
@@ -1389,7 +1386,7 @@ static void ftdi_write_bulk_callback (struct urb *urb)
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("nonzero write bulk status received: %d", status);
@@ -1398,7 +1395,7 @@ static void ftdi_write_bulk_callback (struct urb *urb)
priv = usb_get_serial_port_data(port);
if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+ dbg("%s - bad port private data pointer - exiting", __func__);
return;
}
/* account for transferred data */
@@ -1406,7 +1403,7 @@ static void ftdi_write_bulk_callback (struct urb *urb)
data_offset = priv->write_offset;
if (data_offset > 0) {
/* Subtract the control bytes */
- countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ));
+ countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ));
}
spin_lock_irqsave(&priv->tx_lock, flags);
--priv->tx_outstanding_urbs;
@@ -1423,7 +1420,7 @@ static int ftdi_write_room( struct usb_serial_port *port )
int room;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
@@ -1447,13 +1444,13 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port)
int buffered;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->tx_lock, flags);
buffered = (int)priv->tx_outstanding_bytes;
spin_unlock_irqrestore(&priv->tx_lock, flags);
if (buffered < 0) {
- err("%s outstanding tx bytes is negative!", __FUNCTION__);
+ err("%s outstanding tx bytes is negative!", __func__);
buffered = 0;
}
return buffered;
@@ -1463,7 +1460,7 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port)
static void ftdi_read_bulk_callback (struct urb *urb)
{ /* ftdi_read_bulk_callback */
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty;
struct ftdi_private *priv;
unsigned long countread;
@@ -1471,30 +1468,30 @@ static void ftdi_read_bulk_callback (struct urb *urb)
int status = urb->status;
if (urb->number_of_packets > 0) {
- err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
+ err("%s transfer_buffer_length %d actual_length %d number of packets %d",__func__,
urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets );
- err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags );
+ err("%s transfer_flags %x ", __func__,urb->transfer_flags );
}
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (port->open_count <= 0)
return;
tty = port->tty;
if (!tty) {
- dbg("%s - bad tty pointer - exiting",__FUNCTION__);
+ dbg("%s - bad tty pointer - exiting",__func__);
return;
}
priv = usb_get_serial_port_data(port);
if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+ dbg("%s - bad port private data pointer - exiting", __func__);
return;
}
if (urb != port->read_urb) {
- err("%s - Not my urb!", __FUNCTION__);
+ err("%s - Not my urb!", __func__);
}
if (status) {
@@ -1506,7 +1503,7 @@ static void ftdi_read_bulk_callback (struct urb *urb)
/* count data bytes, but not status bytes */
countread = urb->actual_length;
- countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ);
+ countread -= 2 * DIV_ROUND_UP(countread, PKTSZ);
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_bytes += countread;
spin_unlock_irqrestore(&priv->rx_lock, flags);
@@ -1532,39 +1529,39 @@ static void ftdi_process_read (struct work_struct *work)
int packet_offset;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (port->open_count <= 0)
return;
tty = port->tty;
if (!tty) {
- dbg("%s - bad tty pointer - exiting",__FUNCTION__);
+ dbg("%s - bad tty pointer - exiting",__func__);
return;
}
priv = usb_get_serial_port_data(port);
if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+ dbg("%s - bad port private data pointer - exiting", __func__);
return;
}
urb = port->read_urb;
if (!urb) {
- dbg("%s - bad read_urb pointer - exiting", __FUNCTION__);
+ dbg("%s - bad read_urb pointer - exiting", __func__);
return;
}
data = urb->transfer_buffer;
if (priv->rx_processed) {
- dbg("%s - already processed: %d bytes, %d remain", __FUNCTION__,
+ dbg("%s - already processed: %d bytes, %d remain", __func__,
priv->rx_processed,
urb->actual_length - priv->rx_processed);
} else {
/* The first two bytes of every read packet are status */
if (urb->actual_length > 2) {
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
} else {
dbg("Status only: %03oo %03oo",data[0],data[1]);
}
@@ -1594,17 +1591,17 @@ static void ftdi_process_read (struct work_struct *work)
length = min(PKTSZ, urb->actual_length-packet_offset)-2;
if (length < 0) {
- err("%s - bad packet length: %d", __FUNCTION__, length+2);
+ err("%s - bad packet length: %d", __func__, length+2);
length = 0;
}
if (priv->rx_flags & THROTTLED) {
- dbg("%s - throttled", __FUNCTION__);
+ dbg("%s - throttled", __func__);
break;
}
if (tty_buffer_request_room(tty, length) < length) {
/* break out & wait for throttling/unthrottling to happen */
- dbg("%s - receive room low", __FUNCTION__);
+ dbg("%s - receive room low", __func__);
break;
}
@@ -1672,7 +1669,7 @@ static void ftdi_process_read (struct work_struct *work)
/* not completely processed - record progress */
priv->rx_processed = packet_offset;
dbg("%s - incomplete, %d bytes processed, %d remain",
- __FUNCTION__, packet_offset,
+ __func__, packet_offset,
urb->actual_length - packet_offset);
/* check if we were throttled while processing */
spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1680,7 +1677,7 @@ static void ftdi_process_read (struct work_struct *work)
priv->rx_flags |= ACTUALLY_THROTTLED;
spin_unlock_irqrestore(&priv->rx_lock, flags);
dbg("%s - deferring remainder until unthrottled",
- __FUNCTION__);
+ __func__);
return;
}
spin_unlock_irqrestore(&priv->rx_lock, flags);
@@ -1689,7 +1686,7 @@ static void ftdi_process_read (struct work_struct *work)
/* delay processing of remainder */
schedule_delayed_work(&priv->rx_work, 1);
} else {
- dbg("%s - port is closed", __FUNCTION__);
+ dbg("%s - port is closed", __func__);
}
return;
}
@@ -1707,7 +1704,7 @@ static void ftdi_process_read (struct work_struct *work)
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed resubmitting read urb, error %d", __func__, result);
}
return;
@@ -1736,10 +1733,10 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
- err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
+ err("%s FAILED to enable/disable break state (state was %d)", __func__,break_state);
}
- dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
+ dbg("%s break state is %d - urb is %d", __func__,break_state, urb_value);
}
@@ -1763,18 +1760,18 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
unsigned char vstop;
unsigned char vstart;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Force baud rate if this device requires it, unless it is set to B0. */
if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
- dbg("%s: forcing baud rate for this device", __FUNCTION__);
+ dbg("%s: forcing baud rate for this device", __func__);
tty_encode_baud_rate(port->tty, priv->force_baud,
priv->force_baud);
}
/* Force RTS-CTS if this device requires it. */
if (priv->force_rtscts) {
- dbg("%s: forcing rtscts for this device", __FUNCTION__);
+ dbg("%s: forcing rtscts for this device", __func__);
termios->c_cflag |= CRTSCTS;
}
@@ -1818,7 +1815,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_SHORT_TIMEOUT) < 0) {
- err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
+ err("%s FAILED to set databits/stopbits/parity", __func__);
}
/* Now do the baudrate */
@@ -1829,14 +1826,14 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
- err("%s error from disable flowcontrol urb", __FUNCTION__);
+ err("%s error from disable flowcontrol urb", __func__);
}
/* Drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
/* set the baudrate determined before */
if (change_speed(port)) {
- err("%s urb failed to set baudrate", __FUNCTION__);
+ err("%s urb failed to set baudrate", __func__);
}
/* Ensure RTS and DTR are raised when baudrate changed from 0 */
if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) {
@@ -1847,7 +1844,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
/* Set flow control */
/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
if (cflag & CRTSCTS) {
- dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
+ dbg("%s Setting to CRTSCTS flow control", __func__);
if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
@@ -1865,7 +1862,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
* if IXOFF is not set, the pre-xon/xoff code is executed.
*/
if (iflag & IXOFF) {
- dbg("%s request to enable xonxoff iflag=%04x",__FUNCTION__,iflag);
+ dbg("%s request to enable xonxoff iflag=%04x",__func__,iflag);
// Try to enable the XON/XOFF on the ftdi_sio
// Set the vstart and vstop -- could have been done up above where
// a lot of other dereferencing is done but that would be very
@@ -1886,7 +1883,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
} else {
/* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
- dbg("%s Turning off hardware flow control", __FUNCTION__);
+ dbg("%s Turning off hardware flow control", __func__);
if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
@@ -1908,7 +1905,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
unsigned char buf[2];
int ret;
- dbg("%s TIOCMGET", __FUNCTION__);
+ dbg("%s TIOCMGET", __func__);
switch (priv->chip_type) {
case SIO:
/* Request the status from the device */
@@ -1918,7 +1915,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, 0,
buf, 1, WDR_TIMEOUT)) < 0 ) {
- err("%s Could not get modem status of device - err: %d", __FUNCTION__,
+ err("%s Could not get modem status of device - err: %d", __func__,
ret);
return(ret);
}
@@ -1935,7 +1932,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, priv->interface,
buf, 2, WDR_TIMEOUT)) < 0 ) {
- err("%s Could not get modem status of device - err: %d", __FUNCTION__,
+ err("%s Could not get modem status of device - err: %d", __func__,
ret);
return(ret);
}
@@ -1954,7 +1951,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
{
- dbg("%s TIOCMSET", __FUNCTION__);
+ dbg("%s TIOCMSET", __func__);
return update_mctrl(port, set, clear);
}
@@ -1963,7 +1960,7 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
+ dbg("%s cmd 0x%04x", __func__, cmd);
/* Based on code from acm.c and others */
switch (cmd) {
@@ -2022,7 +2019,7 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
/* This is not necessarily an error - turns out the higher layers will do
* some ioctls itself (see comment above)
*/
- dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
+ dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd);
return(-ENOIOCTLCMD);
} /* ftdi_ioctl */
@@ -2033,7 +2030,7 @@ static void ftdi_throttle (struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags |= THROTTLED;
@@ -2047,7 +2044,7 @@ static void ftdi_unthrottle (struct usb_serial_port *port)
int actually_throttled;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->rx_lock, flags);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
@@ -2062,7 +2059,7 @@ static int __init ftdi_init (void)
{
int retval;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (vendor > 0 && product > 0) {
/* Add user specified VID/PID to reserved element of table. */
int i;
@@ -2091,7 +2088,7 @@ failed_sio_register:
static void __exit ftdi_exit (void)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
usb_deregister (&ftdi_driver);
usb_serial_deregister (&ftdi_sio_device);
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index b5194dc7d3bb..e8ba2cb5995d 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -39,9 +39,6 @@ static struct usb_serial_driver funsoft_device = {
},
.id_table = id_table,
.usb_driver = &funsoft_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
};
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index d74e43d69230..8ce5a56a48e3 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -280,7 +280,7 @@ static void send_to_tty(struct usb_serial_port *port,
if (tty && actual_length) {
usb_serial_debug_data(debug, &port->dev,
- __FUNCTION__, actual_length, data);
+ __func__, actual_length, data);
tty_buffer_request_room(tty, actual_length);
tty_insert_flip_string(tty, data, actual_length);
@@ -355,7 +355,7 @@ static void pkt_clear(struct garmin_data * garmin_data_p)
unsigned long flags;
struct garmin_packet *result = NULL;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
spin_lock_irqsave(&garmin_data_p->lock, flags);
while (!list_empty(&garmin_data_p->pktlist)) {
@@ -379,7 +379,7 @@ static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
__u8 *ptr = pkt;
unsigned l = 0;
- dbg("%s - pkt-id: 0x%X.", __FUNCTION__, 0xFF & pkt_id);
+ dbg("%s - pkt-id: 0x%X.", __func__, 0xFF & pkt_id);
*ptr++ = DLE;
*ptr++ = ACK;
@@ -429,11 +429,11 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
int size = recpkt[1];
usb_serial_debug_data(debug, &garmin_data_p->port->dev,
- __FUNCTION__, count-GSP_INITIAL_OFFSET, recpkt);
+ __func__, count-GSP_INITIAL_OFFSET, recpkt);
if (size != (count-GSP_INITIAL_OFFSET-3)) {
dbg("%s - invalid size, expected %d bytes, got %d",
- __FUNCTION__, size, (count-GSP_INITIAL_OFFSET-3));
+ __func__, size, (count-GSP_INITIAL_OFFSET-3));
return -EINVPKT;
}
@@ -443,7 +443,7 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
// sanity check, remove after test ...
if ((__u8*)&(usbdata[3]) != recpkt) {
dbg("%s - ptr mismatch %p - %p",
- __FUNCTION__, &(usbdata[4]), recpkt);
+ __func__, &(usbdata[4]), recpkt);
return -EINVPKT;
}
@@ -454,7 +454,7 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
if ((0xff & (cksum + *recpkt)) != 0) {
dbg("%s - invalid checksum, expected %02x, got %02x",
- __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
+ __func__, 0xff & -cksum, 0xff & *recpkt);
return -EINVPKT;
}
@@ -519,7 +519,7 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
dbg("%s - dle=%d skip=%d size=%d count=%d",
- __FUNCTION__, dleSeen, skip, size, count);
+ __func__, dleSeen, skip, size, count);
if (size == 0) {
size = GSP_INITIAL_OFFSET;
@@ -578,7 +578,7 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
}
if (size >= GPS_IN_BUFSIZ) {
- dbg("%s - packet too large.", __FUNCTION__);
+ dbg("%s - packet too large.", __func__);
skip = 1;
size = GSP_INITIAL_OFFSET;
dleSeen = 0;
@@ -634,7 +634,7 @@ static int gsp_send(struct garmin_data * garmin_data_p,
int i=0;
int k;
- dbg("%s - state %d - %d bytes.", __FUNCTION__,
+ dbg("%s - state %d - %d bytes.", __func__,
garmin_data_p->state, count);
k = garmin_data_p->outsize;
@@ -658,13 +658,13 @@ static int gsp_send(struct garmin_data * garmin_data_p,
return 0;
}
- dbg("%s - %d bytes in buffer, %d bytes in pkt.", __FUNCTION__,
+ dbg("%s - %d bytes in buffer, %d bytes in pkt.", __func__,
k, i);
/* garmin_data_p->outbuffer now contains a complete packet */
usb_serial_debug_data(debug, &garmin_data_p->port->dev,
- __FUNCTION__, k, garmin_data_p->outbuffer);
+ __func__, k, garmin_data_p->outbuffer);
garmin_data_p->outsize = 0;
@@ -749,7 +749,7 @@ static void gsp_next_packet(struct garmin_data * garmin_data_p)
struct garmin_packet *pkt = NULL;
while ((pkt = pkt_pop(garmin_data_p)) != NULL) {
- dbg("%s - next pkt: %d", __FUNCTION__, pkt->seq);
+ dbg("%s - next pkt: %d", __func__, pkt->seq);
if (gsp_send(garmin_data_p, pkt->data, pkt->size) > 0) {
kfree(pkt);
return;
@@ -794,7 +794,7 @@ static int nat_receive(struct garmin_data * garmin_data_p,
if (len >= GPS_IN_BUFSIZ) {
/* seem to be an invalid packet, ignore rest of input */
dbg("%s - packet size too large: %d",
- __FUNCTION__, len);
+ __func__, len);
garmin_data_p->insize = 0;
count = 0;
result = -EINVPKT;
@@ -873,11 +873,11 @@ static int process_resetdev_request(struct usb_serial_port *port)
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
usb_kill_urb (port->interrupt_in_urb);
- dbg("%s - usb_reset_device", __FUNCTION__ );
+ dbg("%s - usb_reset_device", __func__ );
status = usb_reset_device(port->serial->dev);
if (status)
dbg("%s - usb_reset_device failed: %d",
- __FUNCTION__, status);
+ __func__, status);
return status;
}
@@ -926,18 +926,18 @@ static int garmin_init_session(struct usb_serial_port *port)
if (status == 0) {
usb_kill_urb (port->interrupt_in_urb);
- dbg("%s - adding interrupt input", __FUNCTION__);
+ dbg("%s - adding interrupt input", __func__);
port->interrupt_in_urb->dev = serial->dev;
status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (status)
dev_err(&serial->dev->dev,
"%s - failed submitting interrupt urb,"
" error %d\n",
- __FUNCTION__, status);
+ __func__, status);
}
if (status == 0) {
- dbg("%s - starting session ...", __FUNCTION__);
+ dbg("%s - starting session ...", __func__);
garmin_data_p->state = STATE_ACTIVE;
status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ,
sizeof(GARMIN_START_SESSION_REQ),
@@ -976,7 +976,7 @@ static int garmin_open (struct usb_serial_port *port, struct file *filp)
int status = 0;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* Force low_latency on so that our tty_push actually forces the data
@@ -1013,7 +1013,7 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d - mode=%d state=%d flags=0x%X", __FUNCTION__,
+ dbg("%s - port %d - mode=%d state=%d flags=0x%X", __func__,
port->number, garmin_data_p->mode,
garmin_data_p->state, garmin_data_p->flags);
@@ -1046,13 +1046,13 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
static void garmin_write_bulk_callback (struct urb *urb)
{
unsigned long flags;
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int status = urb->status;
if (port) {
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)
&& (garmin_data_p->mode == MODE_GARMIN_SERIAL)) {
@@ -1061,7 +1061,7 @@ static void garmin_write_bulk_callback (struct urb *urb)
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __func__, urb->status);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1088,7 +1088,7 @@ static int garmin_write_bulk (struct usb_serial_port *port,
unsigned char *buffer;
int status;
- dbg("%s - port %d, state %d", __FUNCTION__, port->number,
+ dbg("%s - port %d, state %d", __func__, port->number,
garmin_data_p->state);
spin_lock_irqsave(&garmin_data_p->lock, flags);
@@ -1110,7 +1110,7 @@ static int garmin_write_bulk (struct usb_serial_port *port,
memcpy (buffer, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
usb_fill_bulk_urb (urb, serial->dev,
usb_sndbulkpipe (serial->dev,
@@ -1134,7 +1134,7 @@ static int garmin_write_bulk (struct usb_serial_port *port,
dev_err(&port->dev,
"%s - usb_submit_urb(write bulk) "
"failed with status = %d\n",
- __FUNCTION__, status);
+ __func__, status);
count = status;
}
@@ -1154,7 +1154,7 @@ static int garmin_write (struct usb_serial_port *port,
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
__le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buf);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, buf);
/* check for our private packets */
if (count >= GARMIN_PKTHDR_LENGTH) {
@@ -1172,7 +1172,7 @@ static int garmin_write (struct usb_serial_port *port,
&& GARMIN_LAYERID_PRIVATE == getLayerId(garmin_data_p->privpkt)) {
dbg("%s - processing private request %d",
- __FUNCTION__, pktid);
+ __func__, pktid);
// drop all unfinished transfers
garmin_clear(garmin_data_p);
@@ -1184,7 +1184,7 @@ static int garmin_write (struct usb_serial_port *port,
return -EINVPKT;
debug = __le32_to_cpu(privpkt[3]);
dbg("%s - debug level set to 0x%X",
- __FUNCTION__, debug);
+ __func__, debug);
break;
case PRIV_PKTID_SET_MODE:
@@ -1192,7 +1192,7 @@ static int garmin_write (struct usb_serial_port *port,
return -EINVPKT;
garmin_data_p->mode = __le32_to_cpu(privpkt[3]);
dbg("%s - mode set to %d",
- __FUNCTION__, garmin_data_p->mode);
+ __func__, garmin_data_p->mode);
break;
case PRIV_PKTID_INFO_REQ:
@@ -1208,7 +1208,7 @@ static int garmin_write (struct usb_serial_port *port,
return -EINVPKT;
initial_mode = __le32_to_cpu(privpkt[3]);
dbg("%s - initial_mode set to %d",
- __FUNCTION__,
+ __func__,
garmin_data_p->mode);
break;
}
@@ -1255,7 +1255,7 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
{
if (garmin_data_p->flags & FLAGS_DROP_DATA) {
/* abort-transfer cmd is actice */
- dbg("%s - pkt dropped", __FUNCTION__);
+ dbg("%s - pkt dropped", __func__);
} else if (garmin_data_p->state != STATE_DISCONNECTED &&
garmin_data_p->state != STATE_RESET ) {
@@ -1286,28 +1286,28 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
static void garmin_read_bulk_callback (struct urb *urb)
{
unsigned long flags;
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
int retval;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!serial) {
- dbg("%s - bad serial pointer, exiting", __FUNCTION__);
+ dbg("%s - bad serial pointer, exiting", __func__);
return;
}
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
usb_serial_debug_data(debug, &port->dev,
- __FUNCTION__, urb->actual_length, data);
+ __func__, urb->actual_length, data);
garmin_read_process(garmin_data_p, data, urb->actual_length);
@@ -1320,7 +1320,7 @@ static void garmin_read_bulk_callback (struct urb *urb)
if (retval)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
} else if (urb->actual_length > 0) {
/* Continue trying to read until nothing more is received */
if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
@@ -1328,10 +1328,10 @@ static void garmin_read_bulk_callback (struct urb *urb)
if (retval)
dev_err(&port->dev,
"%s - failed resubmitting read urb, "
- "error %d\n", __FUNCTION__, retval);
+ "error %d\n", __func__, retval);
}
} else {
- dbg("%s - end of bulk data", __FUNCTION__);
+ dbg("%s - end of bulk data", __func__);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1344,7 +1344,7 @@ static void garmin_read_int_callback (struct urb *urb)
{
unsigned long flags;
int retval;
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
@@ -1359,22 +1359,22 @@ static void garmin_read_int_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, urb->transfer_buffer);
if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) &&
0 == memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY,
sizeof(GARMIN_BULK_IN_AVAIL_REPLY))) {
- dbg("%s - bulk data available.", __FUNCTION__);
+ dbg("%s - bulk data available.", __func__);
if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
@@ -1389,7 +1389,7 @@ static void garmin_read_int_callback (struct urb *urb)
if (retval) {
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
} else {
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
@@ -1417,14 +1417,14 @@ static void garmin_read_int_callback (struct urb *urb)
= __le32_to_cpup((__le32*)(data+GARMIN_PKTHDR_LENGTH));
dbg("%s - start-of-session reply seen - serial %u.",
- __FUNCTION__, garmin_data_p->serial_num);
+ __func__, garmin_data_p->serial_num);
}
if (garmin_data_p->ignorePkts) {
/* this reply belongs to a request generated by the driver,
ignore it. */
dbg("%s - pkt ignored (%d)",
- __FUNCTION__, garmin_data_p->ignorePkts);
+ __func__, garmin_data_p->ignorePkts);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts--;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1437,7 +1437,7 @@ static void garmin_read_int_callback (struct urb *urb)
if (retval)
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
@@ -1473,7 +1473,7 @@ static void garmin_throttle (struct usb_serial_port *port)
unsigned long flags;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* set flag, data received will be put into a queue
for later processing */
spin_lock_irqsave(&garmin_data_p->lock, flags);
@@ -1488,7 +1488,7 @@ static void garmin_unthrottle (struct usb_serial_port *port)
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_THROTTLED;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1503,7 +1503,7 @@ static void garmin_unthrottle (struct usb_serial_port *port)
if (status)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, status);
+ __func__, status);
}
}
@@ -1532,11 +1532,11 @@ static int garmin_attach (struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data * garmin_data_p = NULL;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
if (garmin_data_p == NULL) {
- dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - Out of memory\n", __func__);
return -ENOMEM;
}
init_timer(&garmin_data_p->timer);
@@ -1561,7 +1561,7 @@ static void garmin_shutdown (struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
usb_kill_urb (port->interrupt_in_urb);
del_timer_sync(&garmin_data_p->timer);
@@ -1579,9 +1579,6 @@ static struct usb_serial_driver garmin_device = {
.description = "Garmin GPS usb/tty",
.usb_driver = &garmin_driver,
.id_table = id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = garmin_open,
.close = garmin_close,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 7cfce9dabb90..537f12a027c2 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -62,9 +62,6 @@ struct usb_serial_driver usb_serial_generic_device = {
},
.id_table = generic_device_ids,
.usb_driver = &generic_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.shutdown = usb_serial_generic_shutdown,
.throttle = usb_serial_generic_throttle,
@@ -121,7 +118,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
int result = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* force low_latency on so that our tty_push actually forces the data through,
otherwise it is scheduled, and with high data rates (like with OHCI) data
@@ -148,7 +145,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
}
return result;
@@ -159,7 +156,7 @@ static void generic_cleanup (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (serial->dev) {
/* shutdown any bulk reads that might be going on */
@@ -197,7 +194,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
void usb_serial_generic_close (struct usb_serial_port *port, struct file * filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
generic_cleanup (port);
}
@@ -207,10 +204,10 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
int result;
unsigned char *data;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return (0);
}
@@ -220,7 +217,7 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
spin_lock_irqsave(&port->lock, flags);
if (port->write_urb_busy) {
spin_unlock_irqrestore(&port->lock, flags);
- dbg("%s - already writing", __FUNCTION__);
+ dbg("%s - already writing", __func__);
return 0;
}
port->write_urb_busy = 1;
@@ -230,7 +227,7 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
memcpy (port->write_urb->transfer_buffer, buf, count);
data = port->write_urb->transfer_buffer;
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, data);
/* set up our urb */
usb_fill_bulk_urb (port->write_urb, serial->dev,
@@ -245,7 +242,7 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
port->write_urb_busy = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, result);
/* don't have to grab the lock here, as we will retry if != 0 */
port->write_urb_busy = 0;
} else
@@ -263,15 +260,16 @@ int usb_serial_generic_write_room (struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
int room = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
+ /* FIXME: Locking */
if (serial->num_bulk_out) {
if (!(port->write_urb_busy))
room = port->bulk_out_size;
}
- dbg("%s - returns %d", __FUNCTION__, room);
- return (room);
+ dbg("%s - returns %d", __func__, room);
+ return room;
}
int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
@@ -279,14 +277,15 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
int chars = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
+ /* FIXME: Locking */
if (serial->num_bulk_out) {
if (port->write_urb_busy)
chars = port->write_urb->transfer_buffer_length;
}
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return (chars);
}
@@ -308,7 +307,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
usb_serial_generic_read_bulk_callback), port);
result = usb_submit_urb(urb, mem_flags);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
}
/* Push data to tty layer and resubmit the bulk read URB */
@@ -332,20 +331,20 @@ static void flush_and_resubmit_read_urb (struct usb_serial_port *port)
void usb_serial_generic_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (unlikely(status != 0)) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
/* Throttle the device if requested by tty */
spin_lock_irqsave(&port->lock, flags);
@@ -360,18 +359,17 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
void usb_serial_generic_write_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
port->write_urb_busy = 0;
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
-
usb_serial_port_softint(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
@@ -380,7 +378,7 @@ void usb_serial_generic_throttle (struct usb_serial_port *port)
{
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* Set the throttle request flag. It will be picked up
* by usb_serial_generic_read_bulk_callback(). */
@@ -394,7 +392,7 @@ void usb_serial_generic_unthrottle (struct usb_serial_port *port)
int was_throttled;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* Clear the throttle flags */
spin_lock_irqsave(&port->lock, flags);
@@ -412,7 +410,7 @@ void usb_serial_generic_shutdown (struct usb_serial *serial)
{
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 6c6ebae741c9..75b88b356ebc 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -50,9 +50,6 @@ static struct usb_serial_driver hp49gp_device = {
},
.id_table = id_table,
.usb_driver = &hp49gp_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
};
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 3428ccc28da7..06b52f4098f1 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -371,7 +371,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
struct usb_string_descriptor StringDesc;
struct usb_string_descriptor *pStringDesc;
- dbg("%s - USB String ID = %d", __FUNCTION__, Id );
+ dbg("%s - USB String ID = %d", __func__, Id );
if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) {
return 0;
@@ -391,7 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
kfree(pStringDesc);
- dbg("%s - USB String %s", __FUNCTION__, string);
+ dbg("%s - USB String %s", __func__, string);
return strlen(string);
}
@@ -407,7 +407,7 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
struct usb_string_descriptor StringDesc;
struct usb_string_descriptor *pStringDesc;
- dbg("%s - USB String ID = %d", __FUNCTION__, Id );
+ dbg("%s - USB String ID = %d", __func__, Id );
if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) {
return 0;
@@ -537,7 +537,7 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
sizeof(struct edge_compatibility_descriptor),
300);
- dbg("%s result = %d", __FUNCTION__, result);
+ dbg("%s result = %d", __func__, result);
if (result > 0) {
ep->is_epic = 1;
@@ -589,7 +589,7 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
*****************************************************************************/
static void edge_interrupt_callback (struct urb *urb)
{
- struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
+ struct edgeport_serial *edge_serial = urb->context;
struct edgeport_port *edge_port;
struct usb_serial_port *port;
unsigned char *data = urb->transfer_buffer;
@@ -601,7 +601,7 @@ static void edge_interrupt_callback (struct urb *urb)
int result;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
switch (status) {
case 0:
@@ -612,35 +612,35 @@ static void edge_interrupt_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
// process this interrupt-read even if there are no ports open
if (length) {
- usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, length, data);
+ usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __func__, length, data);
if (length > 1) {
bytes_avail = data[0] | (data[1] << 8);
if (bytes_avail) {
spin_lock(&edge_serial->es_lock);
edge_serial->rxBytesAvail += bytes_avail;
- dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress);
+ dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __func__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress);
if (edge_serial->rxBytesAvail > 0 &&
!edge_serial->read_in_progress) {
- dbg("%s - posting a read", __FUNCTION__);
+ dbg("%s - posting a read", __func__);
edge_serial->read_in_progress = true;
/* we have pending bytes on the bulk in pipe, send a request */
edge_serial->read_urb->dev = edge_serial->serial->dev;
result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
if (result) {
- dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __FUNCTION__, result);
+ dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result);
edge_serial->read_in_progress = false;
}
}
@@ -659,7 +659,7 @@ static void edge_interrupt_callback (struct urb *urb)
spin_lock(&edge_port->ep_lock);
edge_port->txCredits += txCredits;
spin_unlock(&edge_port->ep_lock);
- dbg("%s - txcredits for port%d = %d", __FUNCTION__, portNumber, edge_port->txCredits);
+ dbg("%s - txcredits for port%d = %d", __func__, portNumber, edge_port->txCredits);
/* tell the tty driver that something has changed */
if (edge_port->port->tty)
@@ -677,7 +677,7 @@ static void edge_interrupt_callback (struct urb *urb)
exit:
result = usb_submit_urb (urb, GFP_ATOMIC);
if (result) {
- dev_err(&urb->dev->dev, "%s - Error %d submitting control urb\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - Error %d submitting control urb\n", __func__, result);
}
}
@@ -689,49 +689,49 @@ exit:
*****************************************************************************/
static void edge_bulk_in_callback (struct urb *urb)
{
- struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
+ struct edgeport_serial *edge_serial = urb->context;
unsigned char *data = urb->transfer_buffer;
int retval;
__u16 raw_data_length;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
edge_serial->read_in_progress = false;
return;
}
if (urb->actual_length == 0) {
- dbg("%s - read bulk callback with no data", __FUNCTION__);
+ dbg("%s - read bulk callback with no data", __func__);
edge_serial->read_in_progress = false;
return;
}
raw_data_length = urb->actual_length;
- usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, raw_data_length, data);
+ usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __func__, raw_data_length, data);
spin_lock(&edge_serial->es_lock);
/* decrement our rxBytes available by the number that we just got */
edge_serial->rxBytesAvail -= raw_data_length;
- dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);
+ dbg("%s - Received = %d, rxBytesAvail %d", __func__, raw_data_length, edge_serial->rxBytesAvail);
process_rcvd_data (edge_serial, data, urb->actual_length);
/* check to see if there's any more data for us to read */
if (edge_serial->rxBytesAvail > 0) {
- dbg("%s - posting a read", __FUNCTION__);
+ dbg("%s - posting a read", __func__);
edge_serial->read_urb->dev = edge_serial->serial->dev;
retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
if (retval) {
dev_err(&urb->dev->dev,
"%s - usb_submit_urb(read bulk) failed, "
- "retval = %d\n", __FUNCTION__, retval);
+ "retval = %d\n", __func__, retval);
edge_serial->read_in_progress = false;
}
} else {
@@ -749,15 +749,15 @@ static void edge_bulk_in_callback (struct urb *urb)
*****************************************************************************/
static void edge_bulk_out_data_callback (struct urb *urb)
{
- struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+ struct edgeport_port *edge_port = urb->context;
struct tty_struct *tty;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
}
tty = edge_port->port->tty;
@@ -782,14 +782,14 @@ static void edge_bulk_out_data_callback (struct urb *urb)
*****************************************************************************/
static void edge_bulk_out_cmd_callback (struct urb *urb)
{
- struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+ struct edgeport_port *edge_port = urb->context;
struct tty_struct *tty;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
atomic_dec(&CmdUrbs);
- dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs));
+ dbg("%s - FREE URB %p (outstanding %d)", __func__, urb, atomic_read(&CmdUrbs));
/* clean up the transfer buffer */
@@ -799,7 +799,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb)
usb_free_urb (urb);
if (status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, status);
+ dbg("%s - nonzero write bulk status received: %d", __func__, status);
return;
}
@@ -833,7 +833,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
struct edgeport_serial *edge_serial;
int response;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return -ENODEV;
@@ -883,7 +883,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
* this interrupt will continue as long as the edgeport is connected */
response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL);
if (response) {
- dev_err(&port->dev, "%s - Error %d submitting control urb\n", __FUNCTION__, response);
+ dev_err(&port->dev, "%s - Error %d submitting control urb\n", __func__, response);
}
}
@@ -907,7 +907,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
if (response < 0) {
- dev_err(&port->dev, "%s - error sending open port command\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - error sending open port command\n", __func__);
edge_port->openPending = false;
return -ENODEV;
}
@@ -917,7 +917,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
if (!edge_port->open) {
/* open timed out */
- dbg("%s - open timedout", __FUNCTION__);
+ dbg("%s - open timedout", __func__);
edge_port->openPending = false;
return -ENODEV;
}
@@ -930,7 +930,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
edge_port->txfifo.fifo = kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
if (!edge_port->txfifo.fifo) {
- dbg("%s - no memory", __FUNCTION__);
+ dbg("%s - no memory", __func__);
edge_close (port, filp);
return -ENOMEM;
}
@@ -940,14 +940,14 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
edge_port->write_in_progress = false;
if (!edge_port->write_urb) {
- dbg("%s - no memory", __FUNCTION__);
+ dbg("%s - no memory", __func__);
edge_close (port, filp);
return -ENOMEM;
}
- dbg("%s(%d) - Initialize TX fifo to %d bytes", __FUNCTION__, port->number, edge_port->maxTxCredits);
+ dbg("%s(%d) - Initialize TX fifo to %d bytes", __func__, port->number, edge_port->maxTxCredits);
- dbg("%s exited", __FUNCTION__);
+ dbg("%s exited", __func__);
return 0;
}
@@ -976,11 +976,11 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
// Did we get our Chase response
if (!edge_port->chaseResponsePending) {
- dbg("%s - Got Chase Response", __FUNCTION__);
+ dbg("%s - Got Chase Response", __func__);
// did we get all of our credit back?
if (edge_port->txCredits == edge_port->maxTxCredits ) {
- dbg("%s - Got all credits", __FUNCTION__);
+ dbg("%s - Got all credits", __func__);
return;
}
}
@@ -995,12 +995,12 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
loop--;
if (loop == 0) {
edge_port->chaseResponsePending = false;
- dbg("%s - Chase TIMEOUT", __FUNCTION__);
+ dbg("%s - Chase TIMEOUT", __func__);
return;
}
} else {
// Reset timeout value back to 10 seconds
- dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
+ dbg("%s - Last %d, Current %d", __func__, lastCredits, edge_port->txCredits);
loop = 10;
}
}
@@ -1031,7 +1031,7 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
// Is the Edgeport Buffer empty?
if (lastCount == 0) {
- dbg("%s - TX Buffer Empty", __FUNCTION__);
+ dbg("%s - TX Buffer Empty", __func__);
return;
}
@@ -1040,13 +1040,13 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
schedule_timeout(timeout);
finish_wait(&edge_port->wait_chase, &wait);
- dbg("%s wait", __FUNCTION__);
+ dbg("%s wait", __func__);
if (lastCount == fifo->count) {
// No activity.. count down.
loop--;
if (loop == 0) {
- dbg("%s - TIMEOUT", __FUNCTION__);
+ dbg("%s - TIMEOUT", __func__);
return;
}
} else {
@@ -1067,7 +1067,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
struct edgeport_port *edge_port;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
edge_serial = usb_get_serial_data(port->serial);
edge_port = usb_get_serial_port_data(port);
@@ -1085,7 +1085,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
/* flush and chase */
edge_port->chaseResponsePending = true;
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__);
status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
if (status == 0) {
// block until chase finished
@@ -1099,7 +1099,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPClose))) {
/* close the port */
- dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+ dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __func__);
send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
}
@@ -1119,7 +1119,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
kfree(edge_port->txfifo.fifo);
edge_port->txfifo.fifo = NULL;
- dbg("%s exited", __FUNCTION__);
+ dbg("%s exited", __func__);
}
/*****************************************************************************
@@ -1139,7 +1139,7 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
int secondhalf;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return -ENODEV;
@@ -1152,12 +1152,12 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
// calculate number of bytes to put in fifo
copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count));
- dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", __FUNCTION__,
+ dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", __func__,
port->number, count, edge_port->txCredits - fifo->count, copySize);
/* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */
if (copySize == 0) {
- dbg("%s - copySize = Zero", __FUNCTION__);
+ dbg("%s - copySize = Zero", __func__);
goto finish_write;
}
@@ -1169,11 +1169,11 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
bytesleft = fifo->size - fifo->head;
firsthalf = min (bytesleft, copySize);
- dbg("%s - copy %d bytes of %d into fifo ", __FUNCTION__, firsthalf, bytesleft);
+ dbg("%s - copy %d bytes of %d into fifo ", __func__, firsthalf, bytesleft);
/* now copy our data */
memcpy(&fifo->fifo[fifo->head], data, firsthalf);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, firsthalf, &fifo->fifo[fifo->head]);
+ usb_serial_debug_data(debug, &port->dev, __func__, firsthalf, &fifo->fifo[fifo->head]);
// update the index and size
fifo->head += firsthalf;
@@ -1187,9 +1187,9 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
secondhalf = copySize-firsthalf;
if (secondhalf) {
- dbg("%s - copy rest of data %d", __FUNCTION__, secondhalf);
+ dbg("%s - copy rest of data %d", __func__, secondhalf);
memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, secondhalf, &fifo->fifo[fifo->head]);
+ usb_serial_debug_data(debug, &port->dev, __func__, secondhalf, &fifo->fifo[fifo->head]);
// update the index and size
fifo->count += secondhalf;
fifo->head += secondhalf;
@@ -1201,7 +1201,7 @@ finish_write:
send_more_port_data((struct edgeport_serial *)usb_get_serial_data(port->serial), edge_port);
- dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count);
+ dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __func__, copySize, edge_port->txCredits, fifo->count);
return copySize;
}
@@ -1232,14 +1232,14 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
int secondhalf;
unsigned long flags;
- dbg("%s(%d)", __FUNCTION__, edge_port->port->number);
+ dbg("%s(%d)", __func__, edge_port->port->number);
spin_lock_irqsave(&edge_port->ep_lock, flags);
if (edge_port->write_in_progress ||
!edge_port->open ||
(fifo->count == 0)) {
- dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress);
+ dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __func__, edge_port->port->number, fifo->count, edge_port->write_in_progress);
goto exit_send;
}
@@ -1251,7 +1251,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
// it's better to wait for more credits so we can do a larger
// write.
if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) {
- dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits );
+ dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __func__, edge_port->port->number, fifo->count, edge_port->txCredits );
goto exit_send;
}
@@ -1269,7 +1269,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
count = fifo->count;
buffer = kmalloc (count+2, GFP_ATOMIC);
if (buffer == NULL) {
- dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__);
+ dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __func__);
edge_port->write_in_progress = false;
goto exit_send;
}
@@ -1294,7 +1294,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
}
if (count)
- usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, count, &buffer[2]);
+ usb_serial_debug_data(debug, &edge_port->port->dev, __func__, count, &buffer[2]);
/* fill up the urb with all of our data and submit it */
usb_fill_bulk_urb (urb, edge_serial->serial->dev,
@@ -1309,14 +1309,14 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
/* something went wrong */
- dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status);
+ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __func__, status);
edge_port->write_in_progress = false;
/* revert the credits as something bad happened. */
edge_port->txCredits += count;
edge_port->icount.tx -= count;
}
- dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);
+ dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __func__, count, edge_port->txCredits, fifo->count);
exit_send:
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
@@ -1337,17 +1337,17 @@ static int edge_write_room (struct usb_serial_port *port)
int room;
unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (edge_port == NULL)
return -ENODEV;
if (edge_port->closePending)
return -ENODEV;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!edge_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return -EINVAL;
}
@@ -1356,7 +1356,7 @@ static int edge_write_room (struct usb_serial_port *port)
room = edge_port->txCredits - edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -1376,7 +1376,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
int num_chars;
unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (edge_port == NULL)
return -ENODEV;
@@ -1384,7 +1384,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
return -ENODEV;
if (!edge_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return -EINVAL;
}
@@ -1392,7 +1392,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (num_chars) {
- dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars);
+ dbg("%s(port %d) - returns %d", __func__, port->number, num_chars);
}
return num_chars;
@@ -1410,19 +1410,19 @@ static void edge_throttle (struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return;
if (!edge_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
tty = port->tty;
if (!tty) {
- dbg ("%s - no tty available", __FUNCTION__);
+ dbg ("%s - no tty available", __func__);
return;
}
@@ -1459,19 +1459,19 @@ static void edge_unthrottle (struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return;
if (!edge_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
tty = port->tty;
if (!tty) {
- dbg ("%s - no tty available", __FUNCTION__);
+ dbg ("%s - no tty available", __func__);
return;
}
@@ -1509,18 +1509,18 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
unsigned int cflag;
cflag = tty->termios->c_cflag;
- dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ dbg("%s - clfag %08x iflag %08x", __func__,
tty->termios->c_cflag, tty->termios->c_iflag);
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, old_termios->c_iflag);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return;
if (!edge_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
@@ -1549,7 +1549,7 @@ static int get_lsr_info(struct edgeport_port *edge_port, unsigned int __user *va
spin_lock_irqsave(&edge_port->ep_lock, flags);
if (edge_port->maxTxCredits == edge_port->txCredits &&
edge_port->txfifo.count == 0) {
- dbg("%s -- Empty", __FUNCTION__);
+ dbg("%s -- Empty", __func__);
result = TIOCSER_TEMT;
}
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
@@ -1569,7 +1569,7 @@ static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int
result = tty->read_cnt;
- dbg("%s(%d) = %d", __FUNCTION__, edge_port->port->number, result);
+ dbg("%s(%d) = %d", __func__, edge_port->port->number, result);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
//return 0;
@@ -1581,7 +1581,7 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int mcr;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
mcr = edge_port->shadowMCR;
if (set & TIOCM_RTS)
@@ -1612,7 +1612,7 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
unsigned int msr;
unsigned int mcr;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
msr = edge_port->shadowMSR;
mcr = edge_port->shadowMCR;
@@ -1624,7 +1624,7 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
| ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
- dbg("%s -- %x", __FUNCTION__, result);
+ dbg("%s -- %x", __func__, result);
return result;
}
@@ -1670,30 +1670,30 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
struct async_icount cprev;
struct serial_icounter_struct icount;
- dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
switch (cmd) {
// return number of bytes available
case TIOCINQ:
- dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCINQ", __func__, port->number);
return get_number_bytes_avail(edge_port, (unsigned int __user *) arg);
break;
case TIOCSERGETLSR:
- dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
return get_lsr_info(edge_port, (unsigned int __user *) arg);
return 0;
case TIOCGSERIAL:
- dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
return get_serial_info(edge_port, (struct serial_struct __user *) arg);
case TIOCSSERIAL:
- dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
break;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
cprev = edge_port->icount;
while (1) {
prepare_to_wait(&edge_port->delta_msr_wait, &wait, TASK_INTERRUPTIBLE);
@@ -1732,7 +1732,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
- dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, port->number, icount.rx, icount.tx );
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, port->number, icount.rx, icount.tx );
if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
return -EFAULT;
return 0;
@@ -1758,7 +1758,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
/* flush and chase */
edge_port->chaseResponsePending = true;
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__);
status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
if (status == 0) {
// block until chase finished
@@ -1772,14 +1772,14 @@ static void edge_break (struct usb_serial_port *port, int break_state)
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
if (break_state == -1) {
- dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+ dbg("%s - Sending IOSP_CMD_SET_BREAK", __func__);
status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
} else {
- dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+ dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __func__);
status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
}
if (status) {
- dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ dbg("%s - error sending break set/clear command.", __func__);
}
}
@@ -1799,14 +1799,14 @@ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned cha
__u16 lastBufferLength;
__u16 rxLen;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
lastBufferLength = bufferLength + 1;
while (bufferLength > 0) {
/* failsafe incase we get a message that we don't understand */
if (lastBufferLength == bufferLength) {
- dbg("%s - stuck in loop, exiting it.", __FUNCTION__);
+ dbg("%s - stuck in loop, exiting it.", __func__);
break;
}
lastBufferLength = bufferLength;
@@ -1828,7 +1828,7 @@ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned cha
++buffer;
--bufferLength;
- dbg("%s - Hdr1=%02X Hdr2=%02X", __FUNCTION__, edge_serial->rxHeader1, edge_serial->rxHeader2);
+ dbg("%s - Hdr1=%02X Hdr2=%02X", __func__, edge_serial->rxHeader1, edge_serial->rxHeader2);
// Process depending on whether this header is
// data or status
@@ -1858,7 +1858,7 @@ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned cha
edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1);
edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, edge_serial->rxHeader2);
- dbg("%s - Data for Port %u Len %u", __FUNCTION__, edge_serial->rxPort, edge_serial->rxBytesRemaining);
+ dbg("%s - Data for Port %u Len %u", __func__, edge_serial->rxPort, edge_serial->rxBytesRemaining);
//ASSERT( DevExt->RxPort < DevExt->NumPorts );
//ASSERT( DevExt->RxBytesRemaining < IOSP_MAX_DATA_LENGTH );
@@ -1891,7 +1891,7 @@ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned cha
if (edge_port->open) {
tty = edge_port->port->tty;
if (tty) {
- dbg("%s - Sending %d bytes to TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort);
+ 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);
}
edge_port->icount.rx += rxLen;
@@ -1930,17 +1930,17 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
port = edge_serial->serial->port[edge_serial->rxPort];
edge_port = usb_get_serial_port_data(port);
if (edge_port == NULL) {
- dev_err(&edge_serial->serial->dev->dev, "%s - edge_port == NULL for port %d\n", __FUNCTION__, edge_serial->rxPort);
+ dev_err(&edge_serial->serial->dev->dev, "%s - edge_port == NULL for port %d\n", __func__, edge_serial->rxPort);
return;
}
- dbg("%s - port %d", __FUNCTION__, edge_serial->rxPort);
+ dbg("%s - port %d", __func__, edge_serial->rxPort);
if (code == IOSP_EXT_STATUS) {
switch (byte2) {
case IOSP_EXT_STATUS_CHASE_RSP:
// we want to do EXT status regardless of port open/closed
- dbg("%s - Port %u EXT CHASE_RSP Data = %02x", __FUNCTION__, edge_serial->rxPort, byte3 );
+ dbg("%s - Port %u EXT CHASE_RSP Data = %02x", __func__, edge_serial->rxPort, byte3 );
// Currently, the only EXT_STATUS is Chase, so process here instead of one more call
// to one more subroutine. If/when more EXT_STATUS, there'll be more work to do.
// Also, we currently clear flag and close the port regardless of content of above's Byte3.
@@ -1951,7 +1951,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
return;
case IOSP_EXT_STATUS_RX_CHECK_RSP:
- dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 );
+ dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __func__, edge_serial->rxPort, byte3 );
//Port->RxCheckRsp = true;
return;
}
@@ -1960,7 +1960,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
if (code == IOSP_STATUS_OPEN_RSP) {
edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3);
edge_port->maxTxCredits = edge_port->txCredits;
- dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __FUNCTION__, edge_serial->rxPort, byte2, edge_port->txCredits);
+ dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits);
handle_new_msr (edge_port, byte2);
/* send the current line settings to the port so we are in sync with any further termios calls */
@@ -1984,23 +1984,23 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
switch (code) {
// Not currently sent by Edgeport
case IOSP_STATUS_LSR:
- dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2);
+ dbg("%s - Port %u LSR Status = %02x", __func__, edge_serial->rxPort, byte2);
handle_new_lsr(edge_port, false, byte2, 0);
break;
case IOSP_STATUS_LSR_DATA:
- dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3);
+ dbg("%s - Port %u LSR Status = %02x, Data = %02x", __func__, edge_serial->rxPort, byte2, byte3);
// byte2 is LSR Register
// byte3 is broken data byte
handle_new_lsr(edge_port, true, byte2, byte3);
break;
//
// case IOSP_EXT_4_STATUS:
- // dbg("%s - Port %u LSR Status = %02x Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3);
+ // dbg("%s - Port %u LSR Status = %02x Data = %02x", __func__, edge_serial->rxPort, byte2, byte3);
// break;
//
case IOSP_STATUS_MSR:
- dbg("%s - Port %u MSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2);
+ dbg("%s - Port %u MSR Status = %02x", __func__, edge_serial->rxPort, byte2);
// Process this new modem status and generate appropriate
// events, etc, based on the new status. This routine
@@ -2009,7 +2009,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2
break;
default:
- dbg("%s - Unrecognized IOSP status code %u\n", __FUNCTION__, code);
+ dbg("%s - Unrecognized IOSP status code %u\n", __func__, code);
break;
}
@@ -2029,7 +2029,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c
cnt = tty_buffer_request_room(tty, length);
if (cnt < length) {
dev_err(dev, "%s - dropping data, %d bytes lost\n",
- __FUNCTION__, length - cnt);
+ __func__, length - cnt);
if(cnt == 0)
break;
}
@@ -2050,7 +2050,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
{
struct async_icount *icount;
- dbg("%s %02x", __FUNCTION__, newMsr);
+ dbg("%s %02x", __func__, newMsr);
if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
icount = &edge_port->icount;
@@ -2087,7 +2087,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 l
__u8 newLsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
struct async_icount *icount;
- dbg("%s - %02x", __FUNCTION__, newLsr);
+ dbg("%s - %02x", __func__, newLsr);
edge_port->shadowLSR = lsr;
@@ -2136,11 +2136,11 @@ static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u
__u16 current_length;
unsigned char *transfer_buffer;
- dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
+ dbg("%s - %x, %x, %d", __func__, extAddr, addr, length);
transfer_buffer = kmalloc (64, GFP_KERNEL);
if (!transfer_buffer) {
- dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 64);
+ dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __func__, 64);
return -ENOMEM;
}
@@ -2152,7 +2152,7 @@ static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u
} else {
current_length = length;
}
-// dbg("%s - writing %x, %x, %d", __FUNCTION__, extAddr, addr, current_length);
+// dbg("%s - writing %x, %x, %d", __func__, extAddr, addr, current_length);
memcpy (transfer_buffer, data, current_length);
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_RAM,
0x40, addr, extAddr, transfer_buffer, current_length, 300);
@@ -2181,11 +2181,11 @@ static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u1
__u16 current_length;
unsigned char *transfer_buffer;
-// dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
+// dbg("%s - %x, %x, %d", __func__, extAddr, addr, length);
transfer_buffer = kmalloc (64, GFP_KERNEL);
if (!transfer_buffer) {
- dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 64);
+ dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __func__, 64);
return -ENOMEM;
}
@@ -2197,7 +2197,7 @@ static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u1
} else {
current_length = length;
}
-// dbg("%s - writing %x, %x, %d", __FUNCTION__, extAddr, addr, current_length);
+// dbg("%s - writing %x, %x, %d", __func__, extAddr, addr, current_length);
memcpy (transfer_buffer, data, current_length);
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_ROM,
0x40, addr, extAddr, transfer_buffer, current_length, 300);
@@ -2226,11 +2226,11 @@ static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16
__u16 current_length;
unsigned char *transfer_buffer;
- dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
+ dbg("%s - %x, %x, %d", __func__, extAddr, addr, length);
transfer_buffer = kmalloc (64, GFP_KERNEL);
if (!transfer_buffer) {
- dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 64);
+ dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __func__, 64);
return -ENOMEM;
}
@@ -2242,7 +2242,7 @@ static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16
} else {
current_length = length;
}
-// dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, current_length);
+// dbg("%s - %x, %x, %d", __func__, extAddr, addr, current_length);
result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM,
0xC0, addr, extAddr, transfer_buffer, current_length, 300);
if (result < 0)
@@ -2269,11 +2269,11 @@ static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u
int length = 0;
int status = 0;
- dbg("%s - %d, %d", __FUNCTION__, command, param);
+ dbg("%s - %d, %d", __func__, command, param);
buffer = kmalloc (10, GFP_ATOMIC);
if (!buffer) {
- dev_err(&edge_port->port->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 10);
+ dev_err(&edge_port->port->dev, "%s - kmalloc(%d) failed.\n", __func__, 10);
return -ENOMEM;
}
@@ -2304,7 +2304,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
struct urb *urb;
int timeout;
- usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, length, buffer);
+ usb_serial_debug_data(debug, &edge_port->port->dev, __func__, length, buffer);
/* Allocate our next urb */
urb = usb_alloc_urb (0, GFP_ATOMIC);
@@ -2312,7 +2312,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
return -ENOMEM;
atomic_inc(&CmdUrbs);
- dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs));
+ dbg("%s - ALLOCATE URB %p (outstanding %d)", __func__, urb, atomic_read(&CmdUrbs));
usb_fill_bulk_urb (urb, edge_serial->serial->dev,
usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
@@ -2323,7 +2323,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
if (status) {
/* something went wrong */
- dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status);
+ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __func__, status);
usb_kill_urb(urb);
usb_free_urb(urb);
atomic_dec(&CmdUrbs);
@@ -2337,7 +2337,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
if (edge_port->commandPending) {
/* command timed out */
- dbg("%s - command timed out", __FUNCTION__);
+ dbg("%s - command timed out", __func__);
status = -EINVAL;
}
#endif
@@ -2367,18 +2367,18 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
return 0;
}
- dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
+ dbg("%s - port = %d, baud = %d", __func__, edge_port->port->number, baudRate);
status = calc_baud_rate_divisor (baudRate, &divisor);
if (status) {
- dev_err(&edge_port->port->dev, "%s - bad baud rate\n", __FUNCTION__);
+ dev_err(&edge_port->port->dev, "%s - bad baud rate\n", __func__);
return status;
}
// Alloc memory for the string of commands.
cmdBuffer = kmalloc (0x100, GFP_ATOMIC);
if (!cmdBuffer) {
- dev_err(&edge_port->port->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, 0x100);
+ dev_err(&edge_port->port->dev, "%s - kmalloc(%d) failed.\n", __func__, 0x100);
return -ENOMEM;
}
currCmd = cmdBuffer;
@@ -2414,7 +2414,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
__u16 custom;
- dbg("%s - %d", __FUNCTION__, baudrate);
+ dbg("%s - %d", __func__, baudrate);
for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
if ( divisor_table[i].BaudRate == baudrate ) {
@@ -2432,7 +2432,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
*divisor = custom;
- dbg("%s - Baud %d = %d\n", __FUNCTION__, baudrate, custom);
+ dbg("%s - Baud %d = %d\n", __func__, baudrate, custom);
return 0;
}
@@ -2452,7 +2452,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
unsigned long cmdLen = 0;
int status;
- dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
+ dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __func__, regValue);
if (edge_serial->is_epic &&
!edge_serial->epic_descriptor.Supports.IOSPWriteMCR &&
@@ -2513,29 +2513,29 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
__u8 txFlow;
int status;
- dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
+ dbg("%s - port %d", __func__, edge_port->port->number);
if (!edge_port->open &&
!edge_port->openPending) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
tty = edge_port->port->tty;
if ((!tty) ||
(!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
+ dbg("%s - no tty structures", __func__);
return;
}
cflag = tty->termios->c_cflag;
switch (cflag & CSIZE) {
- case CS5: lData = LCR_BITS_5; mask = 0x1f; dbg("%s - data bits = 5", __FUNCTION__); break;
- case CS6: lData = LCR_BITS_6; mask = 0x3f; dbg("%s - data bits = 6", __FUNCTION__); break;
- case CS7: lData = LCR_BITS_7; mask = 0x7f; dbg("%s - data bits = 7", __FUNCTION__); break;
+ case CS5: lData = LCR_BITS_5; mask = 0x1f; dbg("%s - data bits = 5", __func__); break;
+ case CS6: lData = LCR_BITS_6; mask = 0x3f; dbg("%s - data bits = 6", __func__); break;
+ case CS7: lData = LCR_BITS_7; mask = 0x7f; dbg("%s - data bits = 7", __func__); break;
default:
- case CS8: lData = LCR_BITS_8; dbg("%s - data bits = 8", __FUNCTION__); break;
+ case CS8: lData = LCR_BITS_8; dbg("%s - data bits = 8", __func__); break;
}
lParity = LCR_PAR_NONE;
@@ -2543,28 +2543,28 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
if (cflag & CMSPAR) {
if (cflag & PARODD) {
lParity = LCR_PAR_MARK;
- dbg("%s - parity = mark", __FUNCTION__);
+ dbg("%s - parity = mark", __func__);
} else {
lParity = LCR_PAR_SPACE;
- dbg("%s - parity = space", __FUNCTION__);
+ dbg("%s - parity = space", __func__);
}
} else if (cflag & PARODD) {
lParity = LCR_PAR_ODD;
- dbg("%s - parity = odd", __FUNCTION__);
+ dbg("%s - parity = odd", __func__);
} else {
lParity = LCR_PAR_EVEN;
- dbg("%s - parity = even", __FUNCTION__);
+ dbg("%s - parity = even", __func__);
}
} else {
- dbg("%s - parity = none", __FUNCTION__);
+ dbg("%s - parity = none", __func__);
}
if (cflag & CSTOPB) {
lStop = LCR_STOP_2;
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
} else {
lStop = LCR_STOP_1;
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
}
/* figure out the flow control settings */
@@ -2572,9 +2572,9 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
if (cflag & CRTSCTS) {
rxFlow |= IOSP_RX_FLOW_RTS;
txFlow |= IOSP_TX_FLOW_CTS;
- dbg("%s - RTS/CTS is enabled", __FUNCTION__);
+ dbg("%s - RTS/CTS is enabled", __func__);
} else {
- dbg("%s - RTS/CTS is disabled", __FUNCTION__);
+ dbg("%s - RTS/CTS is disabled", __func__);
}
/* if we are implementing XON/XOFF, set the start and stop character in the device */
@@ -2592,17 +2592,17 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
/* if we are implementing INBOUND XON/XOFF */
if (I_IXOFF(tty)) {
rxFlow |= IOSP_RX_FLOW_XON_XOFF;
- dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __FUNCTION__, start_char, stop_char);
+ dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __func__, start_char, stop_char);
} else {
- dbg("%s - INBOUND XON/XOFF is disabled", __FUNCTION__);
+ dbg("%s - INBOUND XON/XOFF is disabled", __func__);
}
/* if we are implementing OUTBOUND XON/XOFF */
if (I_IXON(tty)) {
txFlow |= IOSP_TX_FLOW_XON_XOFF;
- dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __FUNCTION__, start_char, stop_char);
+ dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", __func__, start_char, stop_char);
} else {
- dbg("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__);
+ dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
}
}
@@ -2645,7 +2645,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
baud = 9600;
}
- dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ dbg("%s - baud rate = %d", __func__, baud);
status = send_cmd_write_baud_rate (edge_port, baud);
if (status == -1) {
/* Speed change was not possible - put back the old speed */
@@ -2843,7 +2843,7 @@ static int edge_startup (struct usb_serial *serial)
/* create our private serial structure */
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
if (edge_serial == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
return -ENOMEM;
}
spin_lock_init(&edge_serial->es_lock);
@@ -2885,19 +2885,19 @@ static int edge_startup (struct usb_serial *serial)
serial->num_ports);
}
- dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
+ dbg("%s - time 1 %ld", __func__, jiffies);
/* If not an EPiC device */
if (!edge_serial->is_epic) {
/* now load the application firmware into this device */
load_application_firmware (edge_serial);
- dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+ dbg("%s - time 2 %ld", __func__, jiffies);
/* Check current Edgeport EEPROM and update if necessary */
update_edgeport_E2PROM (edge_serial);
- dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+ dbg("%s - time 3 %ld", __func__, jiffies);
/* set the configuration to use #1 */
// dbg("set_configuration 1");
@@ -2911,7 +2911,7 @@ static int edge_startup (struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
if (edge_port == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
for (j = 0; j < i; ++j) {
kfree (usb_get_serial_port_data(serial->port[j]));
usb_set_serial_port_data(serial->port[j], NULL);
@@ -2993,7 +2993,7 @@ static int edge_startup (struct usb_serial *serial)
usb_fill_bulk_urb(edge_serial->read_urb, dev,
usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
edge_serial->bulk_in_buffer,
- endpoint->wMaxPacketSize,
+ le16_to_cpu(endpoint->wMaxPacketSize),
edge_bulk_in_callback,
edge_serial);
bulk_in_found = true;
@@ -3017,7 +3017,7 @@ static int edge_startup (struct usb_serial *serial)
* continue as long as the edgeport is connected */
response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
if (response)
- err("%s - Error %d submitting control urb", __FUNCTION__, response);
+ err("%s - Error %d submitting control urb", __func__, response);
}
return response;
}
@@ -3032,7 +3032,7 @@ static void edge_shutdown (struct usb_serial *serial)
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 6d3008772540..2ec85893f27a 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -111,9 +111,6 @@ static struct usb_serial_driver edgeport_2port_device = {
.description = "Edgeport 2 port adapter",
.usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 2,
.open = edge_open,
.close = edge_close,
@@ -142,9 +139,6 @@ static struct usb_serial_driver edgeport_4port_device = {
.description = "Edgeport 4 port adapter",
.usb_driver = &io_driver,
.id_table = edgeport_4port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 4,
.open = edge_open,
.close = edge_close,
@@ -173,9 +167,6 @@ static struct usb_serial_driver edgeport_8port_device = {
.description = "Edgeport 8 port adapter",
.usb_driver = &io_driver,
.id_table = edgeport_8port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 8,
.open = edge_open,
.close = edge_close,
@@ -203,9 +194,6 @@ static struct usb_serial_driver epic_device = {
},
.description = "EPiC device",
.id_table = Epic_port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = edge_open,
.close = edge_close,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index e5ea5ef6335d..05e4fa730730 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -290,7 +290,7 @@ static int TIReadVendorRequestSync (struct usb_device *dev,
return status;
if (status != size) {
dbg ("%s - wanted to write %d, but only wrote %d",
- __FUNCTION__, size, status);
+ __func__, size, status);
return -ECOMM;
}
return 0;
@@ -320,7 +320,7 @@ static int TISendVendorRequestSync (struct usb_device *dev,
return status;
if (status != size) {
dbg ("%s - wanted to write %d, but only wrote %d",
- __FUNCTION__, size, status);
+ __func__, size, status);
return -ECOMM;
}
return 0;
@@ -344,7 +344,7 @@ static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask)
{
int port_number = port->number - port->serial->minor;
- dbg ("%s - port %d, mask %x", __FUNCTION__, port_number, mask);
+ dbg ("%s - port %d, mask %x", __func__, port_number, mask);
return TIWriteCommandSync (port->serial->dev,
UMPC_PURGE_PORT,
@@ -369,7 +369,7 @@ static int TIReadDownloadMemory(struct usb_device *dev, int start_address,
__u8 read_length;
__be16 be_start_address;
- dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length);
+ dbg ("%s - @ %x for %d", __func__, start_address, length);
/* Read in blocks of 64 bytes
* (TI firmware can't handle more than 64 byte reads)
@@ -381,7 +381,7 @@ static int TIReadDownloadMemory(struct usb_device *dev, int start_address,
read_length = (__u8)length;
if (read_length > 1) {
- dbg ("%s - @ %x for %d", __FUNCTION__,
+ dbg ("%s - @ %x for %d", __func__,
start_address, read_length);
}
be_start_address = cpu_to_be16 (start_address);
@@ -393,12 +393,12 @@ static int TIReadDownloadMemory(struct usb_device *dev, int start_address,
read_length); // TransferBufferLength
if (status) {
- dbg ("%s - ERROR %x", __FUNCTION__, status);
+ dbg ("%s - ERROR %x", __func__, status);
return status;
}
if (read_length > 1) {
- usb_serial_debug_data(debug, &dev->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &dev->dev, __func__,
read_length, buffer);
}
@@ -434,13 +434,13 @@ static int TIReadBootMemory (struct edgeport_serial *serial, int start_address,
&buffer[i], // TransferBuffer
0x01); // TransferBufferLength
if (status) {
- dbg ("%s - ERROR %x", __FUNCTION__, status);
+ dbg ("%s - ERROR %x", __func__, status);
return status;
}
}
- dbg ("%s - start_address = %x, length = %d", __FUNCTION__, start_address, length);
- usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, length, buffer);
+ dbg ("%s - start_address = %x, length = %d", __func__, start_address, length);
+ usb_serial_debug_data(debug, &serial->serial->dev->dev, __func__, length, buffer);
serial->TiReadI2C = 1;
@@ -472,8 +472,8 @@ static int TIWriteBootMemory (struct edgeport_serial *serial, int start_address,
return status;
}
- dbg ("%s - start_sddr = %x, length = %d", __FUNCTION__, start_address, length);
- usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, length, buffer);
+ dbg ("%s - start_sddr = %x, length = %d", __func__, start_address, length);
+ usb_serial_debug_data(debug, &serial->serial->dev->dev, __func__, length, buffer);
return status;
}
@@ -494,8 +494,8 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
if (write_length > length)
write_length = length;
- dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
- usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, write_length, buffer);
+ dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __func__, start_address, write_length);
+ usb_serial_debug_data(debug, &serial->serial->dev->dev, __func__, write_length, buffer);
/* Write first page */
be_start_address = cpu_to_be16 (start_address);
@@ -506,7 +506,7 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
buffer, // TransferBuffer
write_length);
if (status) {
- dbg ("%s - ERROR %d", __FUNCTION__, status);
+ dbg ("%s - ERROR %d", __func__, status);
return status;
}
@@ -521,8 +521,8 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
else
write_length = length;
- dbg ("%s - Page Write Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
- usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, write_length, buffer);
+ dbg ("%s - Page Write Addr = %x, length = %d", __func__, start_address, write_length);
+ usb_serial_debug_data(debug, &serial->serial->dev->dev, __func__, write_length, buffer);
/* Write next page */
be_start_address = cpu_to_be16 (start_address);
@@ -533,7 +533,7 @@ static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address
buffer, // TransferBuffer
write_length); // TransferBufferLength
if (status) {
- dev_err (&serial->serial->dev->dev, "%s - ERROR %d\n", __FUNCTION__, status);
+ dev_err (&serial->serial->dev->dev, "%s - ERROR %d\n", __func__, status);
return status;
}
@@ -559,7 +559,7 @@ static int TIIsTxActive (struct edgeport_port *port)
oedb = kmalloc (sizeof (* oedb), GFP_KERNEL);
if (!oedb) {
- dev_err (&port->port->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err (&port->port->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -579,7 +579,7 @@ static int TIIsTxActive (struct edgeport_port *port)
if (status)
goto exit_is_tx_active;
- dbg ("%s - XByteCount 0x%X", __FUNCTION__, oedb->XByteCount);
+ dbg ("%s - XByteCount 0x%X", __func__, oedb->XByteCount);
/* and the LSR */
status = TIReadRam (port->port->serial->dev,
@@ -589,7 +589,7 @@ static int TIIsTxActive (struct edgeport_port *port)
if (status)
goto exit_is_tx_active;
- dbg ("%s - LSR = 0x%X", __FUNCTION__, *lsr);
+ dbg ("%s - LSR = 0x%X", __func__, *lsr);
/* If either buffer has data or we are transmitting then return TRUE */
if ((oedb->XByteCount & 0x80 ) != 0 )
@@ -600,7 +600,7 @@ static int TIIsTxActive (struct edgeport_port *port)
/* We return Not Active if we get any kind of error */
exit_is_tx_active:
- dbg ("%s - return %d", __FUNCTION__, bytes_left );
+ dbg ("%s - return %d", __func__, bytes_left );
kfree(lsr);
kfree(oedb);
@@ -654,7 +654,7 @@ static void TIChasePort(struct edgeport_port *port, unsigned long timeout, int f
/* (TIIsTxActive doesn't seem to wait for the last byte) */
if ((baud_rate=port->baud_rate) == 0)
baud_rate = 50;
- msleep(max(1,(10000+baud_rate-1)/baud_rate));
+ msleep(max(1, DIV_ROUND_UP(10000, baud_rate)));
}
static int TIChooseConfiguration (struct usb_device *dev)
@@ -664,11 +664,11 @@ static int TIChooseConfiguration (struct usb_device *dev)
// we want. However, we just support one config at this point,
// configuration # 1, which is Config Descriptor 0.
- dbg ("%s - Number of Interfaces = %d", __FUNCTION__, dev->config->desc.bNumInterfaces);
- dbg ("%s - MAX Power = %d", __FUNCTION__, dev->config->desc.bMaxPower*2);
+ dbg ("%s - Number of Interfaces = %d", __func__, dev->config->desc.bNumInterfaces);
+ dbg ("%s - MAX Power = %d", __func__, dev->config->desc.bMaxPower*2);
if (dev->config->desc.bNumInterfaces != 1) {
- dev_err (&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __FUNCTION__);
+ dev_err (&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __func__);
return -ENODEV;
}
@@ -751,7 +751,7 @@ static int ValidChecksum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
cs = (__u8)(cs + buffer[i]);
}
if (cs != rom_desc->CheckSum) {
- dbg ("%s - Mismatch %x - %x", __FUNCTION__, rom_desc->CheckSum, cs);
+ dbg ("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs);
return -EINVAL;
}
return 0;
@@ -769,12 +769,12 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
if (!rom_desc) {
- dev_err (dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
buffer = kmalloc (TI_MAX_I2C_SIZE, GFP_KERNEL);
if (!buffer) {
- dev_err (dev, "%s - out of memory when allocating buffer\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory when allocating buffer\n", __func__);
kfree (rom_desc);
return -ENOMEM;
}
@@ -785,7 +785,7 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
goto ExitTiValidateI2cImage;
if (*buffer != UMP5152 && *buffer != UMP3410) {
- dev_err (dev, "%s - invalid buffer signature\n", __FUNCTION__);
+ dev_err (dev, "%s - invalid buffer signature\n", __func__);
status = -ENODEV;
goto ExitTiValidateI2cImage;
}
@@ -801,11 +801,11 @@ static int TiValidateI2cImage (struct edgeport_serial *serial)
if ((start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size) > TI_MAX_I2C_SIZE) {
status = -ENODEV;
- dbg ("%s - structure too big, erroring out.", __FUNCTION__);
+ dbg ("%s - structure too big, erroring out.", __func__);
break;
}
- dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type);
+ dbg ("%s Type = 0x%x", __func__, rom_desc->Type);
// Skip type 2 record
ttype = rom_desc->Type & 0x0f;
@@ -845,13 +845,13 @@ static int TIReadManufDescriptor (struct edgeport_serial *serial, __u8 *buffer)
rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
if (!rom_desc) {
- dev_err (&serial->serial->dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err (&serial->serial->dev->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_ION, rom_desc);
if (!start_address) {
- dbg ("%s - Edge Descriptor not found in I2C", __FUNCTION__);
+ dbg ("%s - Edge Descriptor not found in I2C", __func__);
status = -ENODEV;
goto exit;
}
@@ -867,12 +867,12 @@ static int TIReadManufDescriptor (struct edgeport_serial *serial, __u8 *buffer)
status = ValidChecksum(rom_desc, buffer);
desc = (struct edge_ti_manuf_descriptor *)buffer;
- dbg ( "%s - IonConfig 0x%x", __FUNCTION__, desc->IonConfig );
- dbg ( "%s - Version %d", __FUNCTION__, desc->Version );
- dbg ( "%s - Cpu/Board 0x%x", __FUNCTION__, desc->CpuRev_BoardRev );
- dbg ( "%s - NumPorts %d", __FUNCTION__, desc->NumPorts );
- dbg ( "%s - NumVirtualPorts %d", __FUNCTION__, desc->NumVirtualPorts );
- dbg ( "%s - TotalPorts %d", __FUNCTION__, desc->TotalPorts );
+ dbg ( "%s - IonConfig 0x%x", __func__, desc->IonConfig );
+ dbg ( "%s - Version %d", __func__, desc->Version );
+ dbg ( "%s - Cpu/Board 0x%x", __func__, desc->CpuRev_BoardRev );
+ dbg ( "%s - NumPorts %d", __func__, desc->NumPorts );
+ dbg ( "%s - NumVirtualPorts %d", __func__, desc->NumVirtualPorts );
+ dbg ( "%s - TotalPorts %d", __func__, desc->TotalPorts );
exit:
kfree (rom_desc);
@@ -902,7 +902,7 @@ static int BuildI2CFirmwareHeader (__u8 *header, struct device *dev)
buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!buffer) {
- dev_err (dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -955,11 +955,11 @@ static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
&data, // TransferBuffer
0x01); // TransferBufferLength
if (status)
- dbg ("%s - read 2 status error = %d", __FUNCTION__, status);
+ dbg ("%s - read 2 status error = %d", __func__, status);
else
- dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
+ dbg ("%s - read 2 data = 0x%x", __func__, data);
if ((!status) && (data == UMP5152 || data == UMP3410)) {
- dbg ("%s - ROM_TYPE_II", __FUNCTION__);
+ dbg ("%s - ROM_TYPE_II", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
return 0;
}
@@ -972,16 +972,16 @@ static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
&data, // TransferBuffer
0x01); // TransferBufferLength
if (status)
- dbg ("%s - read 3 status error = %d", __FUNCTION__, status);
+ dbg ("%s - read 3 status error = %d", __func__, status);
else
- dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
+ dbg ("%s - read 2 data = 0x%x", __func__, data);
if ((!status) && (data == UMP5152 || data == UMP3410)) {
- dbg ("%s - ROM_TYPE_III", __FUNCTION__);
+ dbg ("%s - ROM_TYPE_III", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
return 0;
}
- dbg ("%s - Unknown", __FUNCTION__);
+ dbg ("%s - Unknown", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
return -ENODEV;
}
@@ -1063,7 +1063,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
interface = &serial->serial->interface->cur_altsetting->desc;
if (!interface) {
- dev_err (dev, "%s - no interface set, error!\n", __FUNCTION__);
+ dev_err (dev, "%s - no interface set, error!\n", __func__);
return -ENODEV;
}
@@ -1086,12 +1086,11 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
struct ti_i2c_desc *rom_desc;
- dbg ("%s - <<<<<<<<<<<<<<<RUNNING IN DOWNLOAD MODE>>>>>>>>>>", __FUNCTION__);
+ dbg("%s - RUNNING IN DOWNLOAD MODE", __func__);
status = TiValidateI2cImage (serial);
if (status) {
- dbg ("%s - <<<<<<<<<<<<<<<DOWNLOAD MODE -- BAD I2C >>>>>>>>>>",
- __FUNCTION__);
+ dbg("%s - DOWNLOAD MODE -- BAD I2C", __func__);
return status;
}
@@ -1100,7 +1099,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
*/
ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL);
if (!ti_manuf_desc) {
- dev_err (dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory.\n", __func__);
return -ENOMEM;
}
status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc);
@@ -1111,7 +1110,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
// Check version number of ION descriptor
if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) {
- dbg ( "%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__,
+ dbg ( "%s - Wrong CPU Rev %d (Must be 2)", __func__,
TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev));
kfree (ti_manuf_desc);
return -EINVAL;
@@ -1119,7 +1118,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
if (!rom_desc) {
- dev_err (dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory.\n", __func__);
kfree (ti_manuf_desc);
return -ENOMEM;
}
@@ -1129,11 +1128,11 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
struct ti_i2c_firmware_rec *firmware_version;
__u8 record;
- dbg ("%s - Found Type FIRMWARE (Type 2) record", __FUNCTION__);
+ dbg ("%s - Found Type FIRMWARE (Type 2) record", __func__);
firmware_version = kmalloc (sizeof (*firmware_version), GFP_KERNEL);
if (!firmware_version) {
- dev_err (dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory.\n", __func__);
kfree (rom_desc);
kfree (ti_manuf_desc);
return -ENOMEM;
@@ -1159,7 +1158,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
(OperationalCodeImageVersion.MinorVersion);
dbg ("%s - >>>Firmware Versions Device %d.%d Driver %d.%d",
- __FUNCTION__,
+ __func__,
firmware_version->Ver_Major,
firmware_version->Ver_Minor,
OperationalCodeImageVersion.MajorVersion,
@@ -1168,7 +1167,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
// Check if we have an old version in the I2C and update if necessary
if (download_cur_ver != download_new_ver) {
dbg ("%s - Update I2C Download from %d.%d to %d.%d",
- __FUNCTION__,
+ __func__,
firmware_version->Ver_Major,
firmware_version->Ver_Minor,
OperationalCodeImageVersion.MajorVersion,
@@ -1210,14 +1209,14 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
}
if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
- dev_err (dev, "%s - error resetting device\n", __FUNCTION__);
+ dev_err (dev, "%s - error resetting device\n", __func__);
kfree (firmware_version);
kfree (rom_desc);
kfree (ti_manuf_desc);
return -ENODEV;
}
- dbg ("%s - HARDWARE RESET", __FUNCTION__);
+ dbg ("%s - HARDWARE RESET", __func__);
// Reset UMP -- Back to BOOT MODE
status = TISendVendorRequestSync (serial->serial->dev,
@@ -1227,7 +1226,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
NULL, // TransferBuffer
0); // TransferBufferLength
- dbg ( "%s - HARDWARE RESET return %d", __FUNCTION__, status);
+ dbg ( "%s - HARDWARE RESET return %d", __func__, status);
/* return an error on purpose. */
kfree (firmware_version);
@@ -1245,7 +1244,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
header = kmalloc (HEADER_SIZE, GFP_KERNEL);
if (!header) {
- dev_err (dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory.\n", __func__);
kfree (rom_desc);
kfree (ti_manuf_desc);
return -ENOMEM;
@@ -1253,14 +1252,14 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
vheader = kmalloc (HEADER_SIZE, GFP_KERNEL);
if (!vheader) {
- dev_err (dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory.\n", __func__);
kfree (header);
kfree (rom_desc);
kfree (ti_manuf_desc);
return -ENOMEM;
}
- dbg ("%s - Found Type BLANK FIRMWARE (Type F2) record", __FUNCTION__);
+ dbg ("%s - Found Type BLANK FIRMWARE (Type F2) record", __func__);
// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
// This will force the UMP to come up in Boot Mode. Then while in boot mode, the driver
@@ -1298,7 +1297,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
vheader);
if (status) {
- dbg ("%s - can't read header back", __FUNCTION__);
+ dbg ("%s - can't read header back", __func__);
kfree (vheader);
kfree (header);
kfree (rom_desc);
@@ -1306,7 +1305,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
return status;
}
if (memcmp(vheader, header, HEADER_SIZE)) {
- dbg ("%s - write download record failed", __FUNCTION__);
+ dbg ("%s - write download record failed", __func__);
kfree (vheader);
kfree (header);
kfree (rom_desc);
@@ -1317,7 +1316,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
kfree (vheader);
kfree (header);
- dbg ("%s - Start firmware update", __FUNCTION__);
+ dbg ("%s - Start firmware update", __func__);
// Tell firmware to copy download image into I2C
status = TISendVendorRequestSync (serial->serial->dev,
@@ -1327,9 +1326,9 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
NULL, // TransferBuffer
0); // TransferBufferLength
- dbg ("%s - Update complete 0x%x", __FUNCTION__, status);
+ dbg ("%s - Update complete 0x%x", __func__, status);
if (status) {
- dev_err (dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", __FUNCTION__);
+ dev_err (dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", __func__);
kfree (rom_desc);
kfree (ti_manuf_desc);
return status;
@@ -1345,8 +1344,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
/********************************************************************/
/* Boot Mode */
/********************************************************************/
- dbg ("%s - <<<<<<<<<<<<<<<RUNNING IN BOOT MODE>>>>>>>>>>>>>>>",
- __FUNCTION__);
+ dbg("%s - RUNNING IN BOOT MODE", __func__);
// Configure the TI device so we can use the BULK pipes for download
status = TIConfigureBootDevice (serial->serial->dev);
@@ -1354,7 +1352,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
return status;
if (le16_to_cpu(serial->serial->dev->descriptor.idVendor) != USB_VENDOR_ID_ION) {
- dbg ("%s - VID = 0x%x", __FUNCTION__,
+ dbg ("%s - VID = 0x%x", __func__,
le16_to_cpu(serial->serial->dev->descriptor.idVendor));
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
goto StayInBootMode;
@@ -1368,7 +1366,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
// Registry variable set?
if (TIStayInBootMode) {
- dbg ("%s - TIStayInBootMode", __FUNCTION__);
+ dbg ("%s - TIStayInBootMode", __func__);
goto StayInBootMode;
}
@@ -1385,7 +1383,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
*/
ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL);
if (!ti_manuf_desc) {
- dev_err (dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory.\n", __func__);
return -ENOMEM;
}
status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc);
@@ -1396,7 +1394,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
// Check for version 2
if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) {
- dbg ("%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__,
+ dbg ("%s - Wrong CPU Rev %d (Must be 2)", __func__,
TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev));
kfree (ti_manuf_desc);
goto StayInBootMode;
@@ -1420,7 +1418,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header));
buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!buffer) {
- dev_err (dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err (dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -1440,20 +1438,20 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
header->CheckSum = cs;
// Download the operational code
- dbg ("%s - Downloading operational code image (TI UMP)", __FUNCTION__);
+ dbg ("%s - Downloading operational code image (TI UMP)", __func__);
status = TIDownloadCodeImage (serial, buffer, buffer_size);
kfree (buffer);
if (status) {
- dbg ("%s - Error downloading operational code image", __FUNCTION__);
+ dbg ("%s - Error downloading operational code image", __func__);
return status;
}
// Device will reboot
serial->product_info.TiMode = TI_MODE_TRANSITIONING;
- dbg ("%s - Download successful -- Device rebooting...", __FUNCTION__);
+ dbg ("%s - Download successful -- Device rebooting...", __func__);
/* return an error on purpose */
return -ENODEV;
@@ -1461,7 +1459,7 @@ static int TIDownloadFirmware (struct edgeport_serial *serial)
StayInBootMode:
// Eprom is invalid or blank stay in boot mode
- dbg ("%s - <<<<<<<<<<<<<<<STAYING IN BOOT MODE>>>>>>>>>>>>", __FUNCTION__);
+ dbg("%s - STAYING IN BOOT MODE", __func__);
serial->product_info.TiMode = TI_MODE_BOOT;
return 0;
@@ -1472,7 +1470,7 @@ static int TISetDtr (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
port->shadow_mcr |= MCR_DTR;
return TIWriteCommandSync (port->port->serial->dev,
@@ -1487,7 +1485,7 @@ static int TIClearDtr (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
port->shadow_mcr &= ~MCR_DTR;
return TIWriteCommandSync (port->port->serial->dev,
@@ -1502,7 +1500,7 @@ static int TISetRts (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
port->shadow_mcr |= MCR_RTS;
return TIWriteCommandSync (port->port->serial->dev,
@@ -1517,7 +1515,7 @@ static int TIClearRts (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
port->shadow_mcr &= ~MCR_RTS;
return TIWriteCommandSync (port->port->serial->dev,
@@ -1532,7 +1530,7 @@ static int TISetLoopBack (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
return TIWriteCommandSync (port->port->serial->dev,
UMPC_SET_CLR_LOOPBACK,
@@ -1546,7 +1544,7 @@ static int TIClearLoopBack (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
return TIWriteCommandSync (port->port->serial->dev,
UMPC_SET_CLR_LOOPBACK,
@@ -1560,7 +1558,7 @@ static int TISetBreak (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
return TIWriteCommandSync (port->port->serial->dev,
UMPC_SET_CLR_BREAK,
@@ -1574,7 +1572,7 @@ static int TIClearBreak (struct edgeport_port *port)
{
int port_number = port->port->number - port->port->serial->minor;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
return TIWriteCommandSync (port->port->serial->dev,
UMPC_SET_CLR_BREAK,
@@ -1588,7 +1586,7 @@ static int TIRestoreMCR (struct edgeport_port *port, __u8 mcr)
{
int status = 0;
- dbg ("%s - %x", __FUNCTION__, mcr);
+ dbg ("%s - %x", __func__, mcr);
if (mcr & MCR_DTR)
status = TISetDtr (port);
@@ -1642,7 +1640,7 @@ static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
struct async_icount *icount;
struct tty_struct *tty;
- dbg ("%s - %02x", __FUNCTION__, msr);
+ dbg ("%s - %02x", __func__, msr);
if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
icount = &edge_port->icount;
@@ -1681,7 +1679,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8
struct async_icount *icount;
__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
- dbg ("%s - %02x", __FUNCTION__, new_lsr);
+ dbg ("%s - %02x", __func__, new_lsr);
edge_port->shadow_lsr = lsr;
@@ -1712,7 +1710,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8
static void edge_interrupt_callback (struct urb *urb)
{
- struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
+ struct edgeport_serial *edge_serial = urb->context;
struct usb_serial_port *port;
struct edgeport_port *edge_port;
unsigned char *data = urb->transfer_buffer;
@@ -1724,7 +1722,7 @@ static void edge_interrupt_callback (struct urb *urb)
__u8 msr;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
switch (status) {
case 0:
@@ -1735,34 +1733,34 @@ static void edge_interrupt_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dev_err(&urb->dev->dev, "%s - nonzero urb status received: "
- "%d\n", __FUNCTION__, status);
+ "%d\n", __func__, status);
goto exit;
}
if (!length) {
- dbg ("%s - no data in urb", __FUNCTION__);
+ dbg ("%s - no data in urb", __func__);
goto exit;
}
- usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, length, data);
+ usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __func__, length, data);
if (length != 2) {
- dbg ("%s - expecting packet of size 2, got %d", __FUNCTION__, length);
+ dbg ("%s - expecting packet of size 2, got %d", __func__, length);
goto exit;
}
port_number = TIUMP_GET_PORT_FROM_CODE (data[0]);
function = TIUMP_GET_FUNC_FROM_CODE (data[0]);
dbg ("%s - port_number %d, function %d, info 0x%x",
- __FUNCTION__, port_number, function, data[1]);
+ __func__, port_number, function, data[1]);
port = edge_serial->serial->port[port_number];
edge_port = usb_get_serial_port_data(port);
if (!edge_port) {
- dbg ("%s - edge_port not found", __FUNCTION__);
+ dbg ("%s - edge_port not found", __func__);
return;
}
switch (function) {
@@ -1771,12 +1769,12 @@ static void edge_interrupt_callback (struct urb *urb)
if (lsr & UMP_UART_LSR_DATA_MASK) {
/* Save the LSR event for bulk read completion routine */
dbg ("%s - LSR Event Port %u LSR Status = %02x",
- __FUNCTION__, port_number, lsr);
+ __func__, port_number, lsr);
edge_port->lsr_event = 1;
edge_port->lsr_mask = lsr;
} else {
dbg ("%s - ===== Port %d LSR Status = %02x ======",
- __FUNCTION__, port_number, lsr);
+ __func__, port_number, lsr);
handle_new_lsr (edge_port, 0, lsr, 0);
}
break;
@@ -1785,13 +1783,13 @@ static void edge_interrupt_callback (struct urb *urb)
/* Copy MSR from UMP */
msr = data[1];
dbg ("%s - ===== Port %u MSR Status = %02x ======\n",
- __FUNCTION__, port_number, msr);
+ __func__, port_number, msr);
handle_new_msr (edge_port, msr);
break;
default:
dev_err (&urb->dev->dev, "%s - Unknown Interrupt code from UMP %x\n",
- __FUNCTION__, data[1]);
+ __func__, data[1]);
break;
}
@@ -1800,19 +1798,19 @@ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
static void edge_bulk_in_callback (struct urb *urb)
{
- struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+ struct edgeport_port *edge_port = urb->context;
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
int retval = 0;
int port_number;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
switch (status) {
case 0:
@@ -1823,18 +1821,18 @@ static void edge_bulk_in_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dev_err (&urb->dev->dev,"%s - nonzero read bulk status received: %d\n",
- __FUNCTION__, status);
+ __func__, status);
}
if (status == -EPIPE)
goto exit;
if (status) {
- dev_err(&urb->dev->dev,"%s - stopping read!\n", __FUNCTION__);
+ dev_err(&urb->dev->dev,"%s - stopping read!\n", __func__);
return;
}
@@ -1843,7 +1841,7 @@ static void edge_bulk_in_callback (struct urb *urb)
if (edge_port->lsr_event) {
edge_port->lsr_event = 0;
dbg ("%s ===== Port %u LSR Status = %02x, Data = %02x ======",
- __FUNCTION__, port_number, edge_port->lsr_mask, *data);
+ __func__, port_number, edge_port->lsr_mask, *data);
handle_new_lsr (edge_port, 1, edge_port->lsr_mask, *data);
/* Adjust buffer length/pointer */
--urb->actual_length;
@@ -1852,10 +1850,10 @@ static void edge_bulk_in_callback (struct urb *urb)
tty = edge_port->port->tty;
if (tty && urb->actual_length) {
- usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &edge_port->port->dev, __func__, urb->actual_length, data);
if (edge_port->close_pending) {
- dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__);
+ dbg ("%s - close is pending, dropping data on the floor.", __func__);
} else {
edge_tty_recv(&edge_port->port->dev, tty, data, urb->actual_length);
}
@@ -1874,7 +1872,7 @@ exit:
spin_unlock(&edge_port->ep_lock);
if (retval)
dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length)
@@ -1885,7 +1883,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c
cnt = tty_buffer_request_room(tty, length);
if (cnt < length) {
dev_err(dev, "%s - dropping data, %d bytes lost\n",
- __FUNCTION__, length - cnt);
+ __func__, length - cnt);
if(cnt == 0)
break;
}
@@ -1899,11 +1897,11 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c
static void edge_bulk_out_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int status = urb->status;
- dbg ("%s - port %d", __FUNCTION__, port->number);
+ dbg ("%s - port %d", __func__, port->number);
edge_port->ep_write_urb_in_use = 0;
@@ -1916,11 +1914,11 @@ static void edge_bulk_out_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dev_err(&urb->dev->dev, "%s - nonzero write bulk status "
- "received: %d\n", __FUNCTION__, status);
+ "received: %d\n", __func__, status);
}
/* send any buffered data */
@@ -1938,13 +1936,12 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
u16 open_settings;
u8 transaction_timeout;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return -ENODEV;
- if (port->tty)
- port->tty->low_latency = low_latency;
+ port->tty->low_latency = low_latency;
port_number = port->number - port->serial->minor;
switch (port_number) {
@@ -1962,7 +1959,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
}
dbg ("%s - port_number = %d, uart_base = %04x, dma_address = %04x",
- __FUNCTION__, port_number, edge_port->uart_base, edge_port->dma_address);
+ __func__, port_number, edge_port->uart_base, edge_port->dma_address);
dev = port->serial->dev;
@@ -1973,7 +1970,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
status = TIClearLoopBack (edge_port);
if (status) {
dev_err(&port->dev,"%s - cannot send clear loopback command, %d\n",
- __FUNCTION__, status);
+ __func__, status);
return status;
}
@@ -1992,7 +1989,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
UMP_PIPE_TRANS_TIMEOUT_ENA |
(transaction_timeout << 2));
- dbg ("%s - Sending UMPC_OPEN_PORT", __FUNCTION__);
+ dbg ("%s - Sending UMPC_OPEN_PORT", __func__);
/* Tell TI to open and start the port */
status = TIWriteCommandSync (dev,
@@ -2002,7 +1999,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
NULL,
0);
if (status) {
- dev_err(&port->dev,"%s - cannot send open command, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev,"%s - cannot send open command, %d\n", __func__, status);
return status;
}
@@ -2014,14 +2011,14 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
NULL,
0);
if (status) {
- dev_err(&port->dev,"%s - cannot send start DMA command, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev,"%s - cannot send start DMA command, %d\n", __func__, status);
return status;
}
/* Clear TX and RX buffers in UMP */
status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN);
if (status) {
- dev_err(&port->dev,"%s - cannot send clear buffers command, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev,"%s - cannot send clear buffers command, %d\n", __func__, status);
return status;
}
@@ -2033,7 +2030,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
&edge_port->shadow_msr, // TransferBuffer
1); // TransferBufferLength
if (status) {
- dev_err(&port->dev,"%s - cannot send read MSR command, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev,"%s - cannot send read MSR command, %d\n", __func__, status);
return status;
}
@@ -2050,7 +2047,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
/* we are the first port to be opened, let's post the interrupt urb */
urb = edge_serial->serial->port[0]->interrupt_in_urb;
if (!urb) {
- dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
+ dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __func__);
status = -EINVAL;
goto release_es_lock;
}
@@ -2059,7 +2056,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
urb->dev = dev;
status = usb_submit_urb (urb, GFP_KERNEL);
if (status) {
- dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
+ dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __func__, status);
goto release_es_lock;
}
}
@@ -2074,7 +2071,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
/* start up our bulk read urb */
urb = port->read_urb;
if (!urb) {
- dev_err (&port->dev, "%s - no read urb present, exiting\n", __FUNCTION__);
+ dev_err (&port->dev, "%s - no read urb present, exiting\n", __func__);
status = -EINVAL;
goto unlink_int_urb;
}
@@ -2084,13 +2081,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
urb->dev = dev;
status = usb_submit_urb (urb, GFP_KERNEL);
if (status) {
- dev_err (&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status);
+ dev_err (&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __func__, status);
goto unlink_int_urb;
}
++edge_serial->num_ports_open;
- dbg("%s - exited", __FUNCTION__);
+ dbg("%s - exited", __func__);
goto release_es_lock;
@@ -2109,7 +2106,7 @@ static void edge_close (struct usb_serial_port *port, struct file *filp)
int port_number;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
edge_serial = usb_get_serial_data(port->serial);
edge_port = usb_get_serial_port_data(port);
@@ -2129,7 +2126,7 @@ static void edge_close (struct usb_serial_port *port, struct file *filp)
/* assuming we can still talk to the device,
* send a close port command to it */
- dbg("%s - send umpc_close_port", __FUNCTION__);
+ dbg("%s - send umpc_close_port", __func__);
port_number = port->number - port->serial->minor;
status = TIWriteCommandSync (port->serial->dev,
UMPC_CLOSE_PORT,
@@ -2147,7 +2144,7 @@ static void edge_close (struct usb_serial_port *port, struct file *filp)
mutex_unlock(&edge_serial->es_lock);
edge_port->close_pending = 0;
- dbg("%s - exited", __FUNCTION__);
+ dbg("%s - exited", __func__);
}
static int edge_write (struct usb_serial_port *port, const unsigned char *data, int count)
@@ -2155,10 +2152,10 @@ static int edge_write (struct usb_serial_port *port, const unsigned char *data,
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return 0;
}
@@ -2184,7 +2181,7 @@ static void edge_send(struct usb_serial_port *port)
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&edge_port->ep_lock, flags);
@@ -2206,7 +2203,7 @@ static void edge_send(struct usb_serial_port *port)
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, port->write_urb->transfer_buffer);
/* set up our urb */
usb_fill_bulk_urb (port->write_urb, port->serial->dev,
@@ -2219,7 +2216,7 @@ static void edge_send(struct usb_serial_port *port)
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, result);
edge_port->ep_write_urb_in_use = 0;
// TODO: reschedule edge_send
} else {
@@ -2240,7 +2237,7 @@ static int edge_write_room (struct usb_serial_port *port)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return -ENODEV;
@@ -2251,7 +2248,7 @@ static int edge_write_room (struct usb_serial_port *port)
room = edge_buf_space_avail(edge_port->ep_out_buf);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -2261,7 +2258,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return -ENODEV;
@@ -2272,7 +2269,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
chars = edge_buf_data_avail(edge_port->ep_out_buf);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dbg ("%s - returns %d", __FUNCTION__, chars);
+ dbg ("%s - returns %d", __func__, chars);
return chars;
}
@@ -2282,14 +2279,14 @@ static void edge_throttle (struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return;
tty = port->tty;
if (!tty) {
- dbg ("%s - no tty available", __FUNCTION__);
+ dbg ("%s - no tty available", __func__);
return;
}
@@ -2298,7 +2295,7 @@ static void edge_throttle (struct usb_serial_port *port)
unsigned char stop_char = STOP_CHAR(tty);
status = edge_write (port, &stop_char, 1);
if (status <= 0) {
- dev_err(&port->dev, "%s - failed to write stop character, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - failed to write stop character, %d\n", __func__, status);
}
}
@@ -2315,14 +2312,14 @@ static void edge_unthrottle (struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return;
tty = port->tty;
if (!tty) {
- dbg ("%s - no tty available", __FUNCTION__);
+ dbg ("%s - no tty available", __func__);
return;
}
@@ -2331,7 +2328,7 @@ static void edge_unthrottle (struct usb_serial_port *port)
unsigned char start_char = START_CHAR(tty);
status = edge_write (port, &start_char, 1);
if (status <= 0) {
- dev_err(&port->dev, "%s - failed to write start character, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - failed to write start character, %d\n", __func__, status);
}
}
@@ -2340,7 +2337,7 @@ static void edge_unthrottle (struct usb_serial_port *port)
if (C_CRTSCTS(tty)) {
status = restart_read(edge_port);
if (status)
- dev_err(&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __func__, status);
}
}
@@ -2390,13 +2387,13 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
int status;
int port_number = edge_port->port->number - edge_port->port->serial->minor;
- dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
+ dbg("%s - port %d", __func__, edge_port->port->number);
tty = edge_port->port->tty;
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
- dev_err (&edge_port->port->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err (&edge_port->port->dev, "%s - out of memory\n", __func__);
return;
}
@@ -2412,20 +2409,20 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
switch (cflag & CSIZE) {
case CS5:
config->bDataBits = UMP_UART_CHAR5BITS;
- dbg ("%s - data bits = 5", __FUNCTION__);
+ dbg ("%s - data bits = 5", __func__);
break;
case CS6:
config->bDataBits = UMP_UART_CHAR6BITS;
- dbg ("%s - data bits = 6", __FUNCTION__);
+ dbg ("%s - data bits = 6", __func__);
break;
case CS7:
config->bDataBits = UMP_UART_CHAR7BITS;
- dbg ("%s - data bits = 7", __FUNCTION__);
+ dbg ("%s - data bits = 7", __func__);
break;
default:
case CS8:
config->bDataBits = UMP_UART_CHAR8BITS;
- dbg ("%s - data bits = 8", __FUNCTION__);
+ dbg ("%s - data bits = 8", __func__);
break;
}
@@ -2433,32 +2430,32 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
if (cflag & PARODD) {
config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
config->bParity = UMP_UART_ODDPARITY;
- dbg("%s - parity = odd", __FUNCTION__);
+ dbg("%s - parity = odd", __func__);
} else {
config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
config->bParity = UMP_UART_EVENPARITY;
- dbg("%s - parity = even", __FUNCTION__);
+ dbg("%s - parity = even", __func__);
}
} else {
config->bParity = UMP_UART_NOPARITY;
- dbg("%s - parity = none", __FUNCTION__);
+ dbg("%s - parity = none", __func__);
}
if (cflag & CSTOPB) {
config->bStopBits = UMP_UART_STOPBIT2;
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
} else {
config->bStopBits = UMP_UART_STOPBIT1;
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
}
/* figure out the flow control settings */
if (cflag & CRTSCTS) {
config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW;
config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW;
- dbg("%s - RTS/CTS is enabled", __FUNCTION__);
+ dbg("%s - RTS/CTS is enabled", __func__);
} else {
- dbg("%s - RTS/CTS is disabled", __FUNCTION__);
+ dbg("%s - RTS/CTS is disabled", __func__);
tty->hw_stopped = 0;
restart_read(edge_port);
}
@@ -2472,18 +2469,18 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
if (I_IXOFF(tty)) {
config->wFlags |= UMP_MASK_UART_FLAGS_IN_X;
dbg ("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
- __FUNCTION__, config->cXon, config->cXoff);
+ __func__, config->cXon, config->cXoff);
} else {
- dbg ("%s - INBOUND XON/XOFF is disabled", __FUNCTION__);
+ dbg ("%s - INBOUND XON/XOFF is disabled", __func__);
}
/* if we are implementing OUTBOUND XON/XOFF */
if (I_IXON(tty)) {
config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X;
dbg ("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
- __FUNCTION__, config->cXon, config->cXoff);
+ __func__, config->cXon, config->cXoff);
} else {
- dbg ("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__);
+ dbg ("%s - OUTBOUND XON/XOFF is disabled", __func__);
}
}
@@ -2502,7 +2499,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
/* FIXME: Recompute actual baud from divisor here */
- dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
+ dbg ("%s - baud rate = %d, wBaudRate = %d", __func__, baud, config->wBaudRate);
dbg ("wBaudRate: %d", (int)(461550L / config->wBaudRate));
dbg ("wFlags: 0x%x", config->wFlags);
@@ -2525,7 +2522,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
sizeof(*config));
if (status) {
dbg ("%s - error %d when trying to write config to device",
- __FUNCTION__, status);
+ __func__, status);
}
kfree (config);
@@ -2541,12 +2538,12 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
cflag = tty->termios->c_cflag;
- dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ dbg("%s - clfag %08x iflag %08x", __func__,
tty->termios->c_cflag, tty->termios->c_iflag);
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, old_termios->c_iflag);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (edge_port == NULL)
return;
@@ -2561,9 +2558,11 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int mcr;
+ unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
mcr = edge_port->shadow_mcr;
if (set & TIOCM_RTS)
mcr |= MCR_RTS;
@@ -2580,6 +2579,7 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig
mcr &= ~MCR_LOOPBACK;
edge_port->shadow_mcr = mcr;
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
TIRestoreMCR (edge_port, mcr);
@@ -2592,8 +2592,11 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
unsigned int result = 0;
unsigned int msr;
unsigned int mcr;
+ unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
msr = edge_port->shadow_msr;
mcr = edge_port->shadow_mcr;
@@ -2605,7 +2608,8 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
| ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
- dbg("%s -- %x", __FUNCTION__, result);
+ dbg("%s -- %x", __func__, result);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
return result;
}
@@ -2644,30 +2648,30 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
struct async_icount cnow;
struct async_icount cprev;
- dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
switch (cmd) {
case TIOCINQ:
- dbg("%s - (%d) TIOCINQ", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCINQ", __func__, port->number);
// return get_number_bytes_avail(edge_port, (unsigned int *) arg);
break;
case TIOCSERGETLSR:
- dbg("%s - (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCSERGETLSR", __func__, port->number);
// return get_lsr_info(edge_port, (unsigned int *) arg);
break;
case TIOCGSERIAL:
- dbg("%s - (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCGSERIAL", __func__, port->number);
return get_serial_info(edge_port, (struct serial_struct __user *) arg);
break;
case TIOCSSERIAL:
- dbg("%s - (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
break;
case TIOCMIWAIT:
- dbg("%s - (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
cprev = edge_port->icount;
while (1) {
interruptible_sleep_on(&edge_port->delta_msr_wait);
@@ -2690,7 +2694,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
break;
case TIOCGICOUNT:
- dbg ("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ dbg ("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
port->number, edge_port->icount.rx, edge_port->icount.tx);
if (copy_to_user((void __user *)arg, &edge_port->icount, sizeof(edge_port->icount)))
return -EFAULT;
@@ -2705,7 +2709,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int status;
- dbg ("%s - state = %d", __FUNCTION__, break_state);
+ dbg ("%s - state = %d", __func__, break_state);
/* chase the port close */
TIChasePort (edge_port, 0, 0);
@@ -2717,7 +2721,7 @@ static void edge_break (struct usb_serial_port *port, int break_state)
}
if (status) {
dbg ("%s - error %d sending break set/clear command.",
- __FUNCTION__, status);
+ __func__, status);
}
}
@@ -2734,7 +2738,7 @@ static int edge_startup (struct usb_serial *serial)
/* create our private serial structure */
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
if (edge_serial == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
return -ENOMEM;
}
mutex_init(&edge_serial->es_lock);
@@ -2751,13 +2755,13 @@ static int edge_startup (struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL);
if (edge_port == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
goto cleanup;
}
spin_lock_init(&edge_port->ep_lock);
edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
if (edge_port->ep_out_buf == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
kfree(edge_port);
goto cleanup;
}
@@ -2786,7 +2790,7 @@ static void edge_shutdown (struct usb_serial *serial)
int i;
struct edgeport_port *edge_port;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
for (i = 0; i < serial->num_ports; ++i) {
edge_port = usb_get_serial_port_data(serial->port[i]);
@@ -2818,12 +2822,12 @@ static ssize_t store_uart_mode(struct device *dev,
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int v = simple_strtoul(valbuf, NULL, 0);
- dbg("%s: setting uart_mode = %d", __FUNCTION__, v);
+ dbg("%s: setting uart_mode = %d", __func__, v);
if (v < 256)
edge_port->bUartMode = v;
else
- dev_err(dev, "%s - uart_mode %d is invalid\n", __FUNCTION__, v);
+ dev_err(dev, "%s - uart_mode %d is invalid\n", __func__, v);
return count;
}
@@ -3028,9 +3032,6 @@ static struct usb_serial_driver edgeport_1port_device = {
.description = "Edgeport TI 1 port adapter",
.usb_driver = &io_driver,
.id_table = edgeport_1port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = edge_open,
.close = edge_close,
@@ -3060,9 +3061,6 @@ static struct usb_serial_driver edgeport_2port_device = {
.description = "Edgeport TI 2 port adapter",
.usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 2,
- .num_bulk_out = 2,
.num_ports = 2,
.open = edge_open,
.close = edge_close,
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 9b38a08ac83a..ea924dc48496 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -570,10 +570,7 @@ static struct usb_serial_driver ipaq_device = {
.description = "PocketPC PDA",
.usb_driver = &ipaq_driver,
.id_table = ipaq_id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
+ .num_ports = 2,
.open = ipaq_open,
.close = ipaq_close,
.attach = ipaq_startup,
@@ -597,13 +594,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
int i, result = 0;
int retries = connect_retries;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
bytes_in = 0;
bytes_out = 0;
priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
if (priv == NULL) {
- err("%s - Out of memory", __FUNCTION__);
+ err("%s - Out of memory", __func__);
return -ENOMEM;
}
usb_set_serial_port_data(port, priv);
@@ -682,7 +679,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
}
if (!retries && result) {
- err("%s - failed doing control urb, error %d", __FUNCTION__,
+ err("%s - failed doing control urb, error %d", __func__,
result);
goto error;
}
@@ -695,7 +692,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting read urb, error %d", __func__, result);
goto error;
}
@@ -703,7 +700,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
enomem:
result = -ENOMEM;
- err("%s - Out of memory", __FUNCTION__);
+ err("%s - Out of memory", __func__);
error:
ipaq_destroy_lists(port);
kfree(priv);
@@ -715,7 +712,7 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp)
{
struct ipaq_private *priv = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* shut down bulk read and write
@@ -732,21 +729,21 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp)
static void ipaq_read_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -763,7 +760,7 @@ static void ipaq_read_bulk_callback(struct urb *urb)
ipaq_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed resubmitting read urb, error %d", __func__, result);
return;
}
@@ -774,7 +771,7 @@ static int ipaq_write(struct usb_serial_port *port, const unsigned char *buf,
int bytes_sent = 0;
int transfer_size;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
while (count > 0) {
transfer_size = min(count, PACKET_SIZE);
@@ -799,7 +796,7 @@ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *bu
unsigned long flags;
if (priv->free_len <= 0) {
- dbg("%s - we're stuffed", __FUNCTION__);
+ dbg("%s - we're stuffed", __func__);
return -EAGAIN;
}
@@ -811,12 +808,12 @@ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *bu
}
spin_unlock_irqrestore(&write_list_lock, flags);
if (pkt == NULL) {
- dbg("%s - we're stuffed", __FUNCTION__);
+ dbg("%s - we're stuffed", __func__);
return -EAGAIN;
}
memcpy(pkt->data, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, pkt->data);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, pkt->data);
pkt->len = count;
pkt->written = 0;
@@ -829,7 +826,7 @@ static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *bu
spin_unlock_irqrestore(&write_list_lock, flags);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
}
} else {
spin_unlock_irqrestore(&write_list_lock, flags);
@@ -872,17 +869,17 @@ static void ipaq_write_gather(struct usb_serial_port *port)
static void ipaq_write_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct ipaq_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -892,7 +889,7 @@ static void ipaq_write_bulk_callback(struct urb *urb)
spin_unlock_irqrestore(&write_list_lock, flags);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
}
} else {
priv->active = 0;
@@ -906,7 +903,7 @@ static int ipaq_write_room(struct usb_serial_port *port)
{
struct ipaq_private *priv = usb_get_serial_port_data(port);
- dbg("%s - freelen %d", __FUNCTION__, priv->free_len);
+ dbg("%s - freelen %d", __func__, priv->free_len);
return priv->free_len;
}
@@ -914,7 +911,7 @@ static int ipaq_chars_in_buffer(struct usb_serial_port *port)
{
struct ipaq_private *priv = usb_get_serial_port_data(port);
- dbg("%s - queuelen %d", __FUNCTION__, priv->queue_len);
+ dbg("%s - queuelen %d", __func__, priv->queue_len);
return priv->queue_len;
}
@@ -936,7 +933,7 @@ static void ipaq_destroy_lists(struct usb_serial_port *port)
static int ipaq_startup(struct usb_serial *serial)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
err("active config #%d != 1 ??",
serial->dev->actconfig->desc.bConfigurationValue);
@@ -947,7 +944,7 @@ static int ipaq_startup(struct usb_serial *serial)
static void ipaq_shutdown(struct usb_serial *serial)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static int __init ipaq_init(void)
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index cbe5530f3db2..bc85ca5c1c37 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -169,15 +169,15 @@ static void ipw_read_bulk_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -195,7 +195,7 @@ static void ipw_read_bulk_callback(struct urb *urb)
ipw_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
return;
}
@@ -206,7 +206,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
u8 *buf_flow_init;
int result;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL);
if (!buf_flow_init)
@@ -217,7 +217,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
/* --1: Tell the modem to initialize (we think) From sniffs this is always the
* first thing that gets sent to the modem during opening of the device */
- dbg("%s: Sending SIO_INIT (we guess)",__FUNCTION__);
+ dbg("%s: Sending SIO_INIT (we guess)",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
IPW_SIO_INIT,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -234,7 +234,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
usb_clear_halt(dev, usb_sndbulkpipe(dev, port->bulk_out_endpointAddress));
/*--2: Start reading from the device */
- dbg("%s: setting up bulk read callback",__FUNCTION__);
+ dbg("%s: setting up bulk read callback",__func__);
usb_fill_bulk_urb(port->read_urb, dev,
usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
port->bulk_in_buffer,
@@ -242,10 +242,10 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
ipw_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result < 0)
- dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result);
+ dbg("%s - usb_submit_urb(read bulk) failed with status %d", __func__, result);
/*--3: Tell the modem to open the floodgates on the rx bulk channel */
- dbg("%s:asking modem for RxRead (RXBULK_ON)",__FUNCTION__);
+ dbg("%s:asking modem for RxRead (RXBULK_ON)",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_RXCTL,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -258,7 +258,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
dev_err(&port->dev, "Enabling bulk RxRead failed (error = %d)\n", result);
/*--4: setup the initial flowcontrol */
- dbg("%s:setting init flowcontrol (%s)",__FUNCTION__,buf_flow_init);
+ dbg("%s:setting init flowcontrol (%s)",__func__,buf_flow_init);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_HANDFLOW,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -272,7 +272,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
/*--5: raise the dtr */
- dbg("%s:raising dtr",__FUNCTION__);
+ dbg("%s:raising dtr",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_SET_PIN,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -285,7 +285,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
dev_err(&port->dev, "setting dtr failed (error = %d)\n", result);
/*--6: raise the rts */
- dbg("%s:raising rts",__FUNCTION__);
+ dbg("%s:raising rts",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_SET_PIN,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -307,12 +307,12 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
int result;
if (tty_hung_up_p(filp)) {
- dbg("%s: tty_hung_up_p ...", __FUNCTION__);
+ dbg("%s: tty_hung_up_p ...", __func__);
return;
}
/*--1: drop the dtr */
- dbg("%s:dropping dtr",__FUNCTION__);
+ dbg("%s:dropping dtr",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_SET_PIN,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -325,7 +325,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
dev_err(&port->dev, "dropping dtr failed (error = %d)\n", result);
/*--2: drop the rts */
- dbg("%s:dropping rts",__FUNCTION__);
+ dbg("%s:dropping rts",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
IPW_PIN_CLRRTS,
@@ -338,7 +338,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
/*--3: purge */
- dbg("%s:sending purge",__FUNCTION__);
+ dbg("%s:sending purge",__func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_PURGE, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
0x03,
@@ -373,13 +373,13 @@ static void ipw_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
port->write_urb_busy = 0;
if (status)
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
usb_serial_port_softint(port);
}
@@ -389,18 +389,18 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
struct usb_device *dev = port->serial->dev;
int ret;
- dbg("%s: TOP: count=%d, in_interrupt=%ld", __FUNCTION__,
+ dbg("%s: TOP: count=%d, in_interrupt=%ld", __func__,
count, in_interrupt() );
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return 0;
}
spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
spin_unlock_bh(&port->lock);
- dbg("%s - already writing", __FUNCTION__);
+ dbg("%s - already writing", __func__);
return 0;
}
port->write_urb_busy = 1;
@@ -409,7 +409,7 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
- dbg("%s count now:%d", __FUNCTION__, count);
+ dbg("%s count now:%d", __func__, count);
usb_fill_bulk_urb(port->write_urb, dev,
usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
@@ -421,11 +421,11 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (ret != 0) {
port->write_urb_busy = 0;
- dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
+ dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __func__, ret);
return ret;
}
- dbg("%s returning %d", __FUNCTION__, count);
+ dbg("%s returning %d", __func__, count);
return count;
}
@@ -448,9 +448,6 @@ static struct usb_serial_driver ipw_device = {
.description = "IPWireless converter",
.usb_driver = &usb_ipw_driver,
.id_table = usb_ipw_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = ipw_open,
.close = ipw_close,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 6b803ab98543..004d57385a75 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -145,9 +145,6 @@ static struct usb_serial_driver ir_device = {
.description = "IR Dongle",
.usb_driver = &ir_driver,
.id_table = id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.set_termios = ir_set_termios,
.attach = ir_startup,
@@ -198,16 +195,16 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), 1000);
- dbg("%s - ret=%d", __FUNCTION__, ret);
+ dbg("%s - ret=%d", __func__, ret);
if (ret < sizeof(*desc)) {
dbg("%s - class descriptor read %s (%d)",
- __FUNCTION__,
+ __func__,
(ret<0) ? "failed" : "too short",
ret);
goto error;
}
if (desc->bDescriptorType != USB_DT_IRDA) {
- dbg("%s - bad class descriptor type", __FUNCTION__);
+ dbg("%s - bad class descriptor type", __func__);
goto error;
}
@@ -251,7 +248,7 @@ static int ir_startup (struct usb_serial *serial)
}
dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
- __FUNCTION__,
+ __func__,
(irda_desc->wBaudRate & 0x0001) ? " 2400" : "",
(irda_desc->wBaudRate & 0x0002) ? " 9600" : "",
(irda_desc->wBaudRate & 0x0004) ? " 19200" : "",
@@ -284,13 +281,13 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
char *buffer;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (buffer_size) {
/* override the default buffer sizes */
buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!buffer) {
- dev_err (&port->dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (&port->dev, "%s - out of memory.\n", __func__);
return -ENOMEM;
}
kfree (port->read_urb->transfer_buffer);
@@ -299,7 +296,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!buffer) {
- dev_err (&port->dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err (&port->dev, "%s - out of memory.\n", __func__);
return -ENOMEM;
}
kfree (port->write_urb->transfer_buffer);
@@ -319,14 +316,14 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __func__, result);
return result;
}
static void ir_close (struct usb_serial_port *port, struct file * filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* shutdown our bulk read */
usb_kill_urb(port->read_urb);
@@ -338,10 +335,10 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
int result;
int transfer_size;
- dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count);
+ dbg("%s - port = %d, count = %d", __func__, port->number, count);
if (!port->tty) {
- dev_err (&port->dev, "%s - no tty???\n", __FUNCTION__);
+ dev_err (&port->dev, "%s - no tty???\n", __func__);
return 0;
}
@@ -351,7 +348,7 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
spin_unlock_bh(&port->lock);
- dbg("%s - already writing", __FUNCTION__);
+ dbg("%s - already writing", __func__);
return 0;
}
port->write_urb_busy = 1;
@@ -387,7 +384,7 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result) {
port->write_urb_busy = 0;
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, result);
} else
result = transfer_size;
@@ -396,22 +393,22 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
static void ir_write_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
port->write_urb_busy = 0;
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
usb_serial_debug_data (
debug,
&port->dev,
- __FUNCTION__,
+ __func__,
urb->actual_length,
urb->transfer_buffer);
@@ -420,16 +417,16 @@ static void ir_write_bulk_callback (struct urb *urb)
static void ir_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port closed.", __FUNCTION__);
+ dbg("%s - port closed.", __func__);
return;
}
@@ -447,7 +444,7 @@ static void ir_read_bulk_callback (struct urb *urb)
usb_serial_debug_data (
debug,
&port->dev,
- __FUNCTION__,
+ __func__,
urb->actual_length,
data);
@@ -480,13 +477,13 @@ static void ir_read_bulk_callback (struct urb *urb)
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
break ;
default:
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__,
+ __func__,
status);
break ;
@@ -502,7 +499,7 @@ static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_t
speed_t baud;
int ir_baud;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
baud = tty_get_baud_rate(port->tty);
@@ -554,7 +551,7 @@ static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_t
result = usb_submit_urb (port->write_urb, GFP_KERNEL);
if (result)
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, result);
/* Only speed changes are supported */
tty_termios_copy_hw(port->tty->termios, old_termios);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index fde188e23ce1..8a217648b250 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -98,10 +98,10 @@ static int iuu_alloc_buf(struct iuu_private *priv)
priv->writebuf = kzalloc(256, GFP_KERNEL);
if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
iuu_free_buf(priv);
- dbg("%s problem allocation buffer", __FUNCTION__);
+ dbg("%s problem allocation buffer", __func__);
return -ENOMEM;
}
- dbg("%s - Privates buffers allocation success", __FUNCTION__);
+ dbg("%s - Privates buffers allocation success", __func__);
return 0;
}
@@ -109,7 +109,7 @@ static int iuu_startup(struct usb_serial *serial)
{
struct iuu_private *priv;
priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
- dbg("%s- priv allocation success", __FUNCTION__);
+ dbg("%s- priv allocation success", __func__);
if (!priv)
return -ENOMEM;
if (iuu_alloc_buf(priv)) {
@@ -130,17 +130,17 @@ static void iuu_shutdown(struct usb_serial *serial)
if (!port)
return;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (priv) {
iuu_free_buf(priv);
- dbg("%s - I will free all", __FUNCTION__);
+ dbg("%s - I will free all", __func__);
usb_set_serial_port_data(port, NULL);
- dbg("%s - priv is not anymore in port structure", __FUNCTION__);
+ dbg("%s - priv is not anymore in port structure", __func__);
kfree(priv);
- dbg("%s priv is now kfree", __FUNCTION__);
+ dbg("%s priv is now kfree", __func__);
}
}
@@ -148,20 +148,21 @@ static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
- tty = port->tty;
+ unsigned long flags;
- dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__,
+ /* FIXME: locking on tiomstatus */
+ dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __func__,
port->number, set, clear);
+
+ spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
priv->tiostatus = TIOCM_RTS;
if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) {
- dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
+ dbg("%s TIOCMSET RESET called !!!", __func__);
priv->reset = 1;
- return 0;
}
-
+ spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
@@ -173,17 +174,24 @@ static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
static int iuu_tiocmget(struct usb_serial_port *port, struct file *file)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
- return priv->tiostatus;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = priv->tiostatus;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
}
static void iuu_rxcmd(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int result;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
/* error stop all */
return;
}
@@ -203,7 +211,7 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt)
struct iuu_private *priv = usb_get_serial_port_data(port);
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
/* Prepare the reset sequence */
@@ -232,19 +240,19 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt)
*/
static void iuu_update_status_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct iuu_private *priv = usb_get_serial_port_data(port);
u8 *st;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
/* error stop all */
return;
}
st = urb->transfer_buffer;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (urb->actual_length == 1) {
switch (st[0]) {
case 0x1:
@@ -262,11 +270,11 @@ static void iuu_update_status_callback(struct urb *urb)
static void iuu_status_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int result;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
port->bulk_in_endpointAddress),
@@ -279,7 +287,7 @@ static int iuu_status(struct usb_serial_port *port)
{
int result;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
@@ -298,7 +306,7 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
struct usb_serial *serial = port->serial;
int actual = 0;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
/* send the data out the bulk port */
@@ -309,9 +317,9 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
count, &actual, HZ * 1);
if (status != IUU_OPERATION_OK) {
- dbg("%s - error = %2x", __FUNCTION__, status);
+ dbg("%s - error = %2x", __func__, status);
} else {
- dbg("%s - write OK !", __FUNCTION__);
+ dbg("%s - write OK !", __func__);
}
return status;
}
@@ -322,7 +330,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
struct usb_serial *serial = port->serial;
int actual = 0;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
/* send the data out the bulk port */
@@ -333,9 +341,9 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
count, &actual, HZ * 1);
if (status != IUU_OPERATION_OK) {
- dbg("%s - error = %2x", __FUNCTION__, status);
+ dbg("%s - error = %2x", __func__, status);
} else {
- dbg("%s - read OK !", __FUNCTION__);
+ dbg("%s - read OK !", __func__);
}
return status;
@@ -350,7 +358,7 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R,
if (!buf)
return -ENOMEM;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
buf[0] = IUU_SET_LED;
buf[1] = R & 0xFF;
@@ -363,9 +371,9 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R,
status = bulk_immediate(port, buf, 8);
kfree(buf);
if (status != IUU_OPERATION_OK)
- dbg("%s - led error status = %2x", __FUNCTION__, status);
+ dbg("%s - led error status = %2x", __func__, status);
else
- dbg("%s - led OK !", __FUNCTION__);
+ dbg("%s - led OK !", __func__);
return IUU_OPERATION_OK;
}
@@ -384,7 +392,7 @@ static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
static void iuu_led_activity_on(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
*buf_ptr++ = IUU_SET_LED;
@@ -405,7 +413,7 @@ static void iuu_led_activity_on(struct urb *urb)
static void iuu_led_activity_off(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
if (xmas == 1) {
@@ -443,7 +451,7 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq)
unsigned int P2 = 0;
int frq = (int)dwFrq;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (frq == 0) {
priv->buf[Count++] = IUU_UART_WRITE_I2C;
@@ -453,7 +461,7 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq)
status = bulk_immediate(port, (u8 *) priv->buf, Count);
if (status != 0) {
- dbg("%s - write error ", __FUNCTION__);
+ dbg("%s - write error ", __func__);
return status;
}
} else if (frq == 3579000) {
@@ -562,7 +570,7 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq)
status = bulk_immediate(port, (u8 *) priv->buf, Count);
if (status != IUU_OPERATION_OK)
- dbg("%s - write error ", __FUNCTION__);
+ dbg("%s - write error ", __func__);
return status;
}
@@ -573,7 +581,7 @@ static int iuu_uart_flush(struct usb_serial_port *port)
u8 rxcmd = IUU_UART_RX;
struct iuu_private *priv = usb_get_serial_port_data(port);
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
return -EIO;
@@ -581,50 +589,50 @@ static int iuu_uart_flush(struct usb_serial_port *port)
for (i = 0; i < 2; i++) {
status = bulk_immediate(port, &rxcmd, 1);
if (status != IUU_OPERATION_OK) {
- dbg("%s - uart_flush_write error", __FUNCTION__);
+ dbg("%s - uart_flush_write error", __func__);
return status;
}
status = read_immediate(port, &priv->len, 1);
if (status != IUU_OPERATION_OK) {
- dbg("%s - uart_flush_read error", __FUNCTION__);
+ dbg("%s - uart_flush_read error", __func__);
return status;
}
if (priv->len > 0) {
- dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
+ dbg("%s - uart_flush datalen is : %i ", __func__,
priv->len);
status = read_immediate(port, priv->buf, priv->len);
if (status != IUU_OPERATION_OK) {
- dbg("%s - uart_flush_read error", __FUNCTION__);
+ dbg("%s - uart_flush_read error", __func__);
return status;
}
}
}
- dbg("%s - uart_flush_read OK!", __FUNCTION__);
+ dbg("%s - uart_flush_read OK!", __func__);
iuu_led(port, 0, 0xF000, 0, 0xFF);
return status;
}
static void read_buf_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
if (urb->status == -EPROTO) {
/* reschedule needed */
}
return;
}
- dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length);
+ dbg("%s - %i chars to write", __func__, urb->actual_length);
tty = port->tty;
if (data == NULL)
- dbg("%s - data is NULL !!!", __FUNCTION__);
+ 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);
@@ -639,7 +647,7 @@ static int iuu_bulk_write(struct usb_serial_port *port)
int result;
int i;
char *buf_ptr = port->write_urb->transfer_buffer;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
*buf_ptr++ = IUU_UART_ESC;
*buf_ptr++ = IUU_UART_TX;
@@ -652,7 +660,7 @@ static int iuu_bulk_write(struct usb_serial_port *port)
sprintf(priv->dbgbuf + i*2 ,
"%02X", priv->writebuf[i]);
priv->dbgbuf[priv->writelen+i*2] = 0;
- dbg("%s - writing %i chars : %s", __FUNCTION__,
+ dbg("%s - writing %i chars : %s", __func__,
priv->writelen, priv->dbgbuf);
}
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
@@ -671,7 +679,7 @@ static int iuu_bulk_write(struct usb_serial_port *port)
static int iuu_read_buf(struct usb_serial_port *port, int len)
{
int result;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
@@ -684,7 +692,7 @@ static int iuu_read_buf(struct usb_serial_port *port, int len)
static void iuu_uart_read_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned int flags;
int status;
@@ -693,21 +701,21 @@ static void iuu_uart_read_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
priv->poll++;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
/* error stop all */
return;
}
if (data == NULL)
- dbg("%s - data is NULL !!!", __FUNCTION__);
+ dbg("%s - data is NULL !!!", __func__);
if (urb->actual_length == 1 && data != NULL)
len = (int) data[0];
if (urb->actual_length > 1) {
- dbg("%s - urb->actual_length = %i", __FUNCTION__,
+ dbg("%s - urb->actual_length = %i", __func__,
urb->actual_length);
error = 1;
return;
@@ -716,7 +724,7 @@ static void iuu_uart_read_callback(struct urb *urb)
if (len > 0 && error == 0) {
dbg("%s - call read buf - len to read is %i ",
- __FUNCTION__, len);
+ __func__, len);
status = iuu_read_buf(port, len);
return;
}
@@ -742,7 +750,7 @@ static void iuu_uart_read_callback(struct urb *urb)
}
spin_unlock_irqrestore(&priv->lock, flags);
/* if nothing to write call again rxcmd */
- dbg("%s - rxcmd recall", __FUNCTION__);
+ dbg("%s - rxcmd recall", __func__);
iuu_led_activity_off(urb);
return;
}
@@ -752,7 +760,7 @@ static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
{
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned int flags;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
if (count > 256)
return -ENOMEM;
@@ -773,14 +781,14 @@ static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
static void read_rxcmd_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int result;
- dbg("%s - enter", __FUNCTION__);
+ dbg("%s - enter", __func__);
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ dbg("%s - urb->status = %d", __func__, urb->status);
/* error stop all */
return;
}
@@ -791,7 +799,7 @@ static void read_rxcmd_callback(struct urb *urb)
port->read_urb->transfer_buffer, 256,
iuu_uart_read_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- dbg("%s - submit result = %d", __FUNCTION__, result);
+ dbg("%s - submit result = %d", __func__, result);
return;
}
@@ -812,13 +820,13 @@ static int iuu_uart_on(struct usb_serial_port *port)
status = bulk_immediate(port, buf, 4);
if (status != IUU_OPERATION_OK) {
- dbg("%s - uart_on error", __FUNCTION__);
+ dbg("%s - uart_on error", __func__);
goto uart_enable_failed;
}
/* iuu_reset() the card after iuu_uart_on() */
status = iuu_uart_flush(port);
if (status != IUU_OPERATION_OK)
- dbg("%s - uart_flush error", __FUNCTION__);
+ dbg("%s - uart_flush error", __func__);
uart_enable_failed:
kfree(buf);
return status;
@@ -836,7 +844,7 @@ static int iuu_uart_off(struct usb_serial_port *port)
status = bulk_immediate(port, buf, 1);
if (status != IUU_OPERATION_OK)
- dbg("%s - uart_off error", __FUNCTION__);
+ dbg("%s - uart_off error", __func__);
kfree(buf);
return status;
@@ -930,7 +938,7 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
status = bulk_immediate(port, dataout, DataCount);
if (status != IUU_OPERATION_OK)
- dbg("%s - uart_off error", __FUNCTION__);
+ dbg("%s - uart_off error", __func__);
kfree(dataout);
return status;
}
@@ -952,7 +960,7 @@ static void iuu_close(struct usb_serial_port *port, struct file *filp)
if (!serial)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
iuu_uart_off(port);
if (serial->dev) {
@@ -969,7 +977,7 @@ static void iuu_close(struct usb_serial_port *port, struct file *filp)
}
/* free writebuf */
/* shutdown our urbs */
- dbg("%s - shutting down urbs", __FUNCTION__);
+ dbg("%s - shutting down urbs", __func__);
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
@@ -990,7 +998,7 @@ static int iuu_open(struct usb_serial_port *port, struct file *filp)
unsigned long flags;
struct iuu_private *priv = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -1127,7 +1135,7 @@ static int iuu_open(struct usb_serial_port *port, struct file *filp)
iuu_uart_flush(port);
- dbg("%s - initialization done", __FUNCTION__);
+ dbg("%s - initialization done", __func__);
memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
@@ -1139,11 +1147,11 @@ static int iuu_open(struct usb_serial_port *port, struct file *filp)
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
iuu_close(port, NULL);
return -EPROTO;
} else {
- dbg("%s - rxcmd OK", __FUNCTION__);
+ dbg("%s - rxcmd OK", __func__);
}
return result;
}
@@ -1154,9 +1162,6 @@ static struct usb_serial_driver iuu_device = {
.name = "iuu_phoenix",
},
.id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = iuu_open,
.close = iuu_close,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index ea7bba69f4da..3df8a66c5c3c 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -244,13 +244,13 @@ module_exit(keyspan_exit);
static void keyspan_rx_throttle (struct usb_serial_port *port)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
}
static void keyspan_rx_unthrottle (struct usb_serial_port *port)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
}
@@ -258,7 +258,7 @@ static void keyspan_break_ctl (struct usb_serial_port *port, int break_state)
{
struct keyspan_port_private *p_priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
p_priv = usb_get_serial_port_data(port);
@@ -280,7 +280,7 @@ static void keyspan_set_termios (struct usb_serial_port *port,
unsigned int cflag;
struct tty_struct *tty = port->tty;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
@@ -377,7 +377,7 @@ static int keyspan_write(struct usb_serial_port *port,
}
dbg("%s - for port %d (%d chars), flip=%d",
- __FUNCTION__, port->number, count, p_priv->out_flip);
+ __func__, port->number, count, p_priv->out_flip);
for (left = count; left > 0; left -= todo) {
todo = left;
@@ -389,11 +389,11 @@ static int keyspan_write(struct usb_serial_port *port,
/* Check we have a valid urb/endpoint before we use it... */
if ((this_urb = p_priv->out_urbs[flip]) == NULL) {
/* no bulk out, so return 0 bytes written */
- dbg("%s - no output urb :(", __FUNCTION__);
+ dbg("%s - no output urb :(", __func__);
return count;
}
- dbg("%s - endpoint %d flip %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), flip);
+ dbg("%s - endpoint %d flip %d", __func__, usb_pipeendpoint(this_urb->pipe), flip);
if (this_urb->status == -EINPROGRESS) {
if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
@@ -435,17 +435,17 @@ static void usa26_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
dbg("%s - nonzero status: %x on endpoint %d.",
- __FUNCTION__, status, endpoint);
+ __func__, status, endpoint);
return;
}
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
tty = port->tty;
if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
@@ -459,7 +459,7 @@ static void usa26_indat_callback(struct urb *urb)
}
} else {
/* some bytes had errors, every byte has status */
- dbg("%s - RX error!!!!", __FUNCTION__);
+ dbg("%s - RX error!!!!", __func__);
for (i = 0; i + 1 < urb->actual_length; i += 2) {
int stat = data[i], flag = 0;
if (stat & RXERROR_OVERRUN)
@@ -479,7 +479,7 @@ static void usa26_indat_callback(struct urb *urb)
urb->dev = port->serial->dev;
if (port->open_count)
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
return;
}
@@ -490,9 +490,9 @@ static void usa2x_outdat_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
- dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]);
+ dbg ("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
if (port->open_count)
usb_serial_port_softint(port);
@@ -500,7 +500,7 @@ static void usa2x_outdat_callback(struct urb *urb)
static void usa26_inack_callback(struct urb *urb)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
@@ -509,11 +509,11 @@ static void usa26_outcont_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
if (p_priv->resend_cont) {
- dbg ("%s - sending setup", __FUNCTION__);
+ dbg ("%s - sending setup", __func__);
keyspan_usa26_send_setup(port->serial, port, p_priv->resend_cont - 1);
}
}
@@ -528,14 +528,14 @@ static void usa26_instat_callback(struct urb *urb)
int old_dcd_state, err;
int status = urb->status;
- serial = (struct usb_serial *) urb->context;
+ serial = urb->context;
if (status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ dbg("%s - nonzero status: %x", __func__, status);
return;
}
if (urb->actual_length != 9) {
- dbg("%s - %d byte report??", __FUNCTION__, urb->actual_length);
+ dbg("%s - %d byte report??", __func__, urb->actual_length);
goto exit;
}
@@ -543,7 +543,7 @@ static void usa26_instat_callback(struct urb *urb)
#if 0
dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
- __FUNCTION__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
+ __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
msg->_txXoff, msg->rxEnabled, msg->controlResponse);
#endif
@@ -552,7 +552,7 @@ static void usa26_instat_callback(struct urb *urb)
/* Check port number from message and retrieve private data */
if (msg->port >= serial->num_ports) {
- dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
+ dbg ("%s - Unexpected port number %d", __func__, msg->port);
goto exit;
}
port = serial->port[msg->port];
@@ -576,14 +576,14 @@ static void usa26_instat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
exit: ;
}
static void usa26_glocont_callback(struct urb *urb)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
@@ -597,9 +597,9 @@ static void usa28_indat_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
data = urb->transfer_buffer;
@@ -609,11 +609,11 @@ static void usa28_indat_callback(struct urb *urb)
do {
if (status) {
dbg("%s - nonzero status: %x on endpoint %d.",
- __FUNCTION__, status, usb_pipeendpoint(urb->pipe));
+ __func__, status, usb_pipeendpoint(urb->pipe));
return;
}
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
data = urb->transfer_buffer;
@@ -629,7 +629,7 @@ static void usa28_indat_callback(struct urb *urb)
urb->dev = port->serial->dev;
if (port->open_count)
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
p_priv->in_flip ^= 1;
@@ -639,7 +639,7 @@ static void usa28_indat_callback(struct urb *urb)
static void usa28_inack_callback(struct urb *urb)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
static void usa28_outcont_callback(struct urb *urb)
@@ -647,11 +647,11 @@ static void usa28_outcont_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
if (p_priv->resend_cont) {
- dbg ("%s - sending setup", __FUNCTION__);
+ dbg ("%s - sending setup", __func__);
keyspan_usa28_send_setup(port->serial, port, p_priv->resend_cont - 1);
}
}
@@ -667,19 +667,19 @@ static void usa28_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- serial = (struct usb_serial *) urb->context;
+ serial = urb->context;
if (status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ dbg("%s - nonzero status: %x", __func__, status);
return;
}
if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
- dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
+ dbg("%s - bad length %d", __func__, urb->actual_length);
goto exit;
}
- /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __FUNCTION__
+ /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__
data[0], data[1], data[2], data[3], data[4], data[5],
data[6], data[7], data[8], data[9], data[10], data[11]);*/
@@ -689,7 +689,7 @@ static void usa28_instat_callback(struct urb *urb)
/* Check port number from message and retrieve private data */
if (msg->port >= serial->num_ports) {
- dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
+ dbg ("%s - Unexpected port number %d", __func__, msg->port);
goto exit;
}
port = serial->port[msg->port];
@@ -713,14 +713,14 @@ static void usa28_instat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
exit: ;
}
static void usa28_glocont_callback(struct urb *urb)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
@@ -731,15 +731,15 @@ static void usa49_glocont_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int i;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
- serial = (struct usb_serial *) urb->context;
+ serial = urb->context;
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
p_priv = usb_get_serial_port_data(port);
if (p_priv->resend_cont) {
- dbg ("%s - sending setup", __FUNCTION__);
+ dbg ("%s - sending setup", __func__);
keyspan_usa49_send_setup(serial, port, p_priv->resend_cont - 1);
break;
}
@@ -759,21 +759,21 @@ static void usa49_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
- serial = (struct usb_serial *) urb->context;
+ serial = urb->context;
if (status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ dbg("%s - nonzero status: %x", __func__, status);
return;
}
if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) {
- dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
+ dbg("%s - bad length %d", __func__, urb->actual_length);
goto exit;
}
- /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __FUNCTION__,
+ /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__,
data[0], data[1], data[2], data[3], data[4], data[5],
data[6], data[7], data[8], data[9], data[10]);*/
@@ -782,7 +782,7 @@ static void usa49_instat_callback(struct urb *urb)
/* Check port number from message and retrieve private data */
if (msg->portNumber >= serial->num_ports) {
- dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->portNumber);
+ dbg ("%s - Unexpected port number %d", __func__, msg->portNumber);
goto exit;
}
port = serial->port[msg->portNumber];
@@ -807,14 +807,14 @@ static void usa49_instat_callback(struct urb *urb)
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
exit: ;
}
static void usa49_inack_callback(struct urb *urb)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
static void usa49_indat_callback(struct urb *urb)
@@ -826,17 +826,17 @@ static void usa49_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
- dbg("%s - nonzero status: %x on endpoint %d.", __FUNCTION__,
+ dbg("%s - nonzero status: %x on endpoint %d.", __func__,
status, endpoint);
return;
}
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
tty = port->tty;
if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
@@ -866,7 +866,7 @@ static void usa49_indat_callback(struct urb *urb)
urb->dev = port->serial->dev;
if (port->open_count)
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
}
@@ -879,12 +879,12 @@ static void usa49wg_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
serial = urb->context;
if (status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ dbg("%s - nonzero status: %x", __func__, status);
return;
}
@@ -898,7 +898,7 @@ static void usa49wg_indat_callback(struct urb *urb)
/* Check port number from message*/
if (data[i] >= serial->num_ports) {
dbg ("%s - Unexpected port number %d",
- __FUNCTION__, data[i]);
+ __func__, data[i]);
return;
}
port = serial->port[data[i++]];
@@ -944,13 +944,13 @@ static void usa49wg_indat_callback(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err != 0)
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
/* not used, usa-49 doesn't have per-port control endpoints */
static void usa49_outcont_callback(struct urb *urb)
{
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
}
static void usa90_indat_callback(struct urb *urb)
@@ -963,17 +963,17 @@ static void usa90_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
dbg("%s - nonzero status: %x on endpoint %d.",
- __FUNCTION__, status, endpoint);
+ __func__, status, endpoint);
return;
}
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
tty = port->tty;
@@ -1000,7 +1000,7 @@ static void usa90_indat_callback(struct urb *urb)
}
else {
/* some bytes had errors, every byte has status */
- dbg("%s - RX error!!!!", __FUNCTION__);
+ dbg("%s - RX error!!!!", __func__);
for (i = 0; i + 1 < urb->actual_length; i += 2) {
int stat = data[i], flag = 0;
if (stat & RXERROR_OVERRUN)
@@ -1021,7 +1021,7 @@ static void usa90_indat_callback(struct urb *urb)
urb->dev = port->serial->dev;
if (port->open_count)
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
return;
}
@@ -1037,14 +1037,14 @@ static void usa90_instat_callback(struct urb *urb)
int old_dcd_state, err;
int status = urb->status;
- serial = (struct usb_serial *) urb->context;
+ serial = urb->context;
if (status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ dbg("%s - nonzero status: %x", __func__, status);
return;
}
if (urb->actual_length < 14) {
- dbg("%s - %d byte report??", __FUNCTION__, urb->actual_length);
+ dbg("%s - %d byte report??", __func__, urb->actual_length);
goto exit;
}
@@ -1073,7 +1073,7 @@ static void usa90_instat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving */
urb->dev = serial->dev;
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
exit:
;
@@ -1084,11 +1084,11 @@ static void usa90_outcont_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
p_priv = usb_get_serial_port_data(port);
if (p_priv->resend_cont) {
- dbg ("%s - sending setup", __FUNCTION__);
+ dbg ("%s - sending setup", __func__);
keyspan_usa90_send_setup(port->serial, port, p_priv->resend_cont - 1);
}
}
@@ -1105,17 +1105,17 @@ static void usa67_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
serial = urb->context;
if (status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ dbg("%s - nonzero status: %x", __func__, status);
return;
}
if (urb->actual_length != sizeof(struct keyspan_usa67_portStatusMessage)) {
- dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
+ dbg("%s - bad length %d", __func__, urb->actual_length);
return;
}
@@ -1125,7 +1125,7 @@ static void usa67_instat_callback(struct urb *urb)
/* Check port number from message and retrieve private data */
if (msg->port >= serial->num_ports) {
- dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
+ dbg ("%s - Unexpected port number %d", __func__, msg->port);
return;
}
@@ -1149,7 +1149,7 @@ static void usa67_instat_callback(struct urb *urb)
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err != 0)
- dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+ dbg("%s - resubmit read urb failed. (%d)", __func__, err);
}
static void usa67_glocont_callback(struct urb *urb)
@@ -1159,7 +1159,7 @@ static void usa67_glocont_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int i;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
serial = urb->context;
for (i = 0; i < serial->num_ports; ++i) {
@@ -1167,7 +1167,7 @@ static void usa67_glocont_callback(struct urb *urb)
p_priv = usb_get_serial_port_data(port);
if (p_priv->resend_cont) {
- dbg ("%s - sending setup", __FUNCTION__);
+ dbg ("%s - sending setup", __func__);
keyspan_usa67_send_setup(serial, port,
p_priv->resend_cont - 1);
break;
@@ -1183,10 +1183,11 @@ static int keyspan_write_room (struct usb_serial_port *port)
int data_len;
struct urb *this_urb;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
+ /* FIXME: locking */
if (d_details->msg_format == msg_usa90)
data_len = 64;
else
@@ -1203,13 +1204,13 @@ static int keyspan_write_room (struct usb_serial_port *port)
if (this_urb->status != -EINPROGRESS)
return (data_len);
}
- return (0);
+ return 0;
}
static int keyspan_chars_in_buffer (struct usb_serial_port *port)
{
- return (0);
+ return 0;
}
@@ -1228,7 +1229,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
- dbg("%s - port%d.", __FUNCTION__, port->number);
+ dbg("%s - port%d.", __func__, port->number);
/* Set some sane defaults */
p_priv->rts_state = 1;
@@ -1253,7 +1254,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
usb_clear_halt(urb->dev, urb->pipe);
if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
- dbg("%s - submit urb %d failed (%d)", __FUNCTION__, i, err);
+ dbg("%s - submit urb %d failed (%d)", __func__, i, err);
}
}
@@ -1289,7 +1290,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
//mdelay(100);
//keyspan_set_termios(port, NULL);
- return (0);
+ return 0;
}
static inline void stop_urb(struct urb *urb)
@@ -1305,7 +1306,7 @@ static void keyspan_close(struct usb_serial_port *port, struct file *filp)
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -1320,7 +1321,7 @@ static void keyspan_close(struct usb_serial_port *port, struct file *filp)
}
/*while (p_priv->outcont_urb->status == -EINPROGRESS) {
- dbg("%s - urb in progress", __FUNCTION__);
+ dbg("%s - urb in progress", __func__);
}*/
p_priv->out_flip = 0;
@@ -1484,10 +1485,10 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
if (endpoint == -1)
return NULL; /* endpoint not needed */
- dbg ("%s - alloc for endpoint %d.", __FUNCTION__, endpoint);
+ dbg ("%s - alloc for endpoint %d.", __func__, endpoint);
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (urb == NULL) {
- dbg ("%s - alloc for endpoint %d failed.", __FUNCTION__, endpoint);
+ dbg ("%s - alloc for endpoint %d failed.", __func__, endpoint);
return NULL;
}
@@ -1588,7 +1589,7 @@ static void keyspan_setup_urbs(struct usb_serial *serial)
struct callbacks *cback;
int endp;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
s_priv = usb_get_serial_data(serial);
d_details = s_priv->device_details;
@@ -1662,7 +1663,7 @@ static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
div, /* divisor */
cnt; /* inverse of divisor (programmed into 8051) */
- dbg ("%s - %d.", __FUNCTION__, baud_rate);
+ dbg ("%s - %d.", __func__, baud_rate);
/* prevent divide by zero... */
if( (b16 = (baud_rate * 16L)) == 0) {
@@ -1695,7 +1696,7 @@ static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
*rate_hi = (u8) ((cnt >> 8) & 0xff);
}
if (rate_low && rate_hi) {
- dbg ("%s - %d %02x %02x.", __FUNCTION__, baud_rate, *rate_hi, *rate_low);
+ dbg ("%s - %d %02x %02x.", __func__, baud_rate, *rate_hi, *rate_low);
}
return (KEYSPAN_BAUD_RATE_OK);
@@ -1708,7 +1709,7 @@ static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
u32 b16, /* baud rate times 16 (actual rate used internally) */
div; /* divisor */
- dbg ("%s - %d.", __FUNCTION__, baud_rate);
+ dbg ("%s - %d.", __func__, baud_rate);
/* prevent divide by zero... */
if( (b16 = (baud_rate * 16L)) == 0)
@@ -1731,7 +1732,7 @@ static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
*rate_hi = (u8) ((div >> 8) & 0xff);
if (rate_low && rate_hi)
- dbg ("%s - %d %02x %02x.", __FUNCTION__, baud_rate, *rate_hi, *rate_low);
+ dbg ("%s - %d %02x %02x.", __func__, baud_rate, *rate_hi, *rate_low);
return (KEYSPAN_BAUD_RATE_OK);
}
@@ -1748,7 +1749,7 @@ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
u8 best_prescaler;
int i;
- dbg ("%s - %d.", __FUNCTION__, baud_rate);
+ dbg ("%s - %d.", __func__, baud_rate);
/* prevent divide by zero */
if( (b16 = baud_rate * 16L) == 0) {
@@ -1796,7 +1797,7 @@ static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
}
if (prescaler) {
*prescaler = best_prescaler;
- /* dbg("%s - %d %d", __FUNCTION__, *prescaler, div); */
+ /* dbg("%s - %d %d", __func__, *prescaler, div); */
}
return (KEYSPAN_BAUD_RATE_OK);
}
@@ -1809,7 +1810,7 @@ static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
div, /* divisor */
cnt; /* inverse of divisor (programmed into 8051) */
- dbg ("%s - %d.", __FUNCTION__, baud_rate);
+ dbg ("%s - %d.", __func__, baud_rate);
/* prevent divide by zero */
if ((b16 = baud_rate * 16L) == 0)
@@ -1848,7 +1849,7 @@ static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi,
if (rate_hi) {
*rate_hi = (u8) ((cnt >> 8) & 0xff);
}
- dbg ("%s - %d OK.", __FUNCTION__, baud_rate);
+ dbg ("%s - %d OK.", __func__, baud_rate);
return (KEYSPAN_BAUD_RATE_OK);
}
@@ -1864,7 +1865,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int device_port, err;
- dbg ("%s reset=%d", __FUNCTION__, reset_port);
+ dbg ("%s reset=%d", __func__, reset_port);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -1874,11 +1875,11 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
outcont_urb = d_details->outcont_endpoints[port->number];
this_urb = p_priv->outcont_urb;
- dbg("%s - endpoint %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe));
+ dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe));
/* Make sure we have an urb then send the message */
if (this_urb == NULL) {
- dbg("%s - oops no urb.", __FUNCTION__);
+ dbg("%s - oops no urb.", __func__);
return -1;
}
@@ -1887,7 +1888,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
if ((reset_port + 1) > p_priv->resend_cont)
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
- /* dbg ("%s - already writing", __FUNCTION__); */
+ /* dbg ("%s - already writing", __func__); */
mdelay(5);
return(-1);
}
@@ -1901,7 +1902,7 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
if (d_details->calculate_baud_rate
(p_priv->baud, d_details->baudclk, &msg.baudHi,
&msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
- dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
+ dbg("%s - Invalid baud rate %d requested, using 9600.", __func__,
p_priv->baud);
msg.baudLo = 0;
msg.baudHi = 125; /* Values for 9600 baud */
@@ -1996,17 +1997,17 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
this_urb->dev = serial->dev;
if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
- dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
+ dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
}
#if 0
else {
- dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __FUNCTION__
+ dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__
outcont_urb, this_urb->transfer_buffer_length,
usb_pipeendpoint(this_urb->pipe));
}
#endif
- return (0);
+ return 0;
}
static int keyspan_usa28_send_setup(struct usb_serial *serial,
@@ -2020,7 +2021,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int device_port, err;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -2029,7 +2030,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
/* only do something if we have a bulk out endpoint */
if ((this_urb = p_priv->outcont_urb) == NULL) {
- dbg("%s - oops no urb.", __FUNCTION__);
+ dbg("%s - oops no urb.", __func__);
return -1;
}
@@ -2038,7 +2039,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
if ((reset_port + 1) > p_priv->resend_cont)
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
- dbg ("%s already writing", __FUNCTION__);
+ dbg ("%s already writing", __func__);
mdelay(5);
return(-1);
}
@@ -2048,7 +2049,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
msg.setBaudRate = 1;
if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk,
&msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
- dbg("%s - Invalid baud rate requested %d.", __FUNCTION__, p_priv->baud);
+ dbg("%s - Invalid baud rate requested %d.", __func__, p_priv->baud);
msg.baudLo = 0xff;
msg.baudHi = 0xb2; /* Values for 9600 baud */
}
@@ -2122,16 +2123,16 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
this_urb->dev = serial->dev;
if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
- dbg("%s - usb_submit_urb(setup) failed", __FUNCTION__);
+ dbg("%s - usb_submit_urb(setup) failed", __func__);
}
#if 0
else {
- dbg("%s - usb_submit_urb(setup) OK %d bytes", __FUNCTION__,
+ dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__,
this_urb->transfer_buffer_length);
}
#endif
- return (0);
+ return 0;
}
static int keyspan_usa49_send_setup(struct usb_serial *serial,
@@ -2146,7 +2147,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int err, device_port;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -2157,11 +2158,11 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
/* Work out which port within the device is being setup */
device_port = port->number - port->serial->minor;
- dbg("%s - endpoint %d port %d (%d)",__FUNCTION__, usb_pipeendpoint(this_urb->pipe), port->number, device_port);
+ dbg("%s - endpoint %d port %d (%d)",__func__, usb_pipeendpoint(this_urb->pipe), port->number, device_port);
/* Make sure we have an urb then send the message */
if (this_urb == NULL) {
- dbg("%s - oops no urb for port %d.", __FUNCTION__, port->number);
+ dbg("%s - oops no urb for port %d.", __func__, port->number);
return -1;
}
@@ -2171,7 +2172,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
- /* dbg ("%s - already writing", __FUNCTION__); */
+ /* dbg ("%s - already writing", __func__); */
mdelay(5);
return(-1);
}
@@ -2188,7 +2189,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
if (d_details->calculate_baud_rate
(p_priv->baud, d_details->baudclk, &msg.baudHi,
&msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
- dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
+ dbg("%s - Invalid baud rate %d requested, using 9600.", __func__,
p_priv->baud);
msg.baudLo = 0;
msg.baudHi = 125; /* Values for 9600 baud */
@@ -2307,17 +2308,17 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
this_urb->dev = serial->dev;
}
if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
- dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
+ dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
}
#if 0
else {
- dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __FUNCTION__,
+ dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__,
outcont_urb, this_urb->transfer_buffer_length,
usb_pipeendpoint(this_urb->pipe));
}
#endif
- return (0);
+ return 0;
}
static int keyspan_usa90_send_setup(struct usb_serial *serial,
@@ -2332,7 +2333,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
int err;
u8 prescaler;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -2340,7 +2341,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
/* only do something if we have a bulk out endpoint */
if ((this_urb = p_priv->outcont_urb) == NULL) {
- dbg("%s - oops no urb.", __FUNCTION__);
+ dbg("%s - oops no urb.", __func__);
return -1;
}
@@ -2349,7 +2350,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
if ((reset_port + 1) > p_priv->resend_cont)
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
- dbg ("%s already writing", __FUNCTION__);
+ dbg ("%s already writing", __func__);
mdelay(5);
return(-1);
}
@@ -2363,7 +2364,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
if (d_details->calculate_baud_rate
(p_priv->baud, d_details->baudclk, &msg.baudHi,
&msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE ) {
- dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
+ dbg("%s - Invalid baud rate %d requested, using 9600.", __func__,
p_priv->baud);
p_priv->baud = 9600;
d_details->calculate_baud_rate (p_priv->baud, d_details->baudclk,
@@ -2453,9 +2454,9 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
this_urb->dev = serial->dev;
if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
- dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__, err);
+ dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
}
- return (0);
+ return 0;
}
static int keyspan_usa67_send_setup(struct usb_serial *serial,
@@ -2469,7 +2470,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int err, device_port;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -2482,7 +2483,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
/* Make sure we have an urb then send the message */
if (this_urb == NULL) {
- dbg("%s - oops no urb for port %d.", __FUNCTION__,
+ dbg("%s - oops no urb for port %d.", __func__,
port->number);
return -1;
}
@@ -2492,7 +2493,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
if ((reset_port + 1) > p_priv->resend_cont)
p_priv->resend_cont = reset_port + 1;
if (this_urb->status == -EINPROGRESS) {
- /* dbg ("%s - already writing", __FUNCTION__); */
+ /* dbg ("%s - already writing", __func__); */
mdelay(5);
return(-1);
}
@@ -2508,7 +2509,7 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
if (d_details->calculate_baud_rate
(p_priv->baud, d_details->baudclk, &msg.baudHi,
&msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE ) {
- dbg("%s - Invalid baud rate %d requested, using 9600.", __FUNCTION__,
+ dbg("%s - Invalid baud rate %d requested, using 9600.", __func__,
p_priv->baud);
msg.baudLo = 0;
msg.baudHi = 125; /* Values for 9600 baud */
@@ -2601,9 +2602,9 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
- dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__,
+ dbg("%s - usb_submit_urb(setup) failed (%d)", __func__,
err);
- return (0);
+ return 0;
}
static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
@@ -2612,7 +2613,7 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
struct keyspan_serial_private *s_priv;
const struct keyspan_device_details *d_details;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
s_priv = usb_get_serial_data(serial);
d_details = s_priv->device_details;
@@ -2647,20 +2648,20 @@ static int keyspan_startup (struct usb_serial *serial)
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
if (d_details->product_id == le16_to_cpu(serial->dev->descriptor.idProduct))
break;
if (d_details == NULL) {
- dev_err(&serial->dev->dev, "%s - unknown product id %x\n", __FUNCTION__, le16_to_cpu(serial->dev->descriptor.idProduct));
+ dev_err(&serial->dev->dev, "%s - unknown product id %x\n", __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
return 1;
}
/* Setup private data for serial driver */
s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
if (!s_priv) {
- dbg("%s - kmalloc for keyspan_serial_private failed.", __FUNCTION__);
+ dbg("%s - kmalloc for keyspan_serial_private failed.", __func__);
return -ENOMEM;
}
@@ -2672,7 +2673,7 @@ static int keyspan_startup (struct usb_serial *serial)
port = serial->port[i];
p_priv = kzalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
if (!p_priv) {
- dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __FUNCTION__, i);
+ dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i);
return (1);
}
p_priv->device_details = d_details;
@@ -2685,18 +2686,18 @@ static int keyspan_startup (struct usb_serial *serial)
s_priv->instat_urb->dev = serial->dev;
err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
if (err != 0)
- dbg("%s - submit instat urb failed %d", __FUNCTION__,
+ dbg("%s - submit instat urb failed %d", __func__,
err);
}
if (s_priv->indat_urb != NULL) {
s_priv->indat_urb->dev = serial->dev;
err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
if (err != 0)
- dbg("%s - submit indat urb failed %d", __FUNCTION__,
+ dbg("%s - submit indat urb failed %d", __func__,
err);
}
- return (0);
+ return 0;
}
static void keyspan_shutdown (struct usb_serial *serial)
@@ -2706,7 +2707,7 @@ static void keyspan_shutdown (struct usb_serial *serial)
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
s_priv = usb_get_serial_data(serial);
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 74ce8bca3e66..8d6ed0293bfa 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -636,10 +636,6 @@ static struct usb_serial_driver keyspan_pre_device = {
},
.description = "Keyspan - (without firmware)",
.id_table = keyspan_pre_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_interrupt_out = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.attach = keyspan_fake_startup,
};
@@ -651,10 +647,6 @@ static struct usb_serial_driver keyspan_1port_device = {
},
.description = "Keyspan 1 port adapter",
.id_table = keyspan_1port_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_interrupt_out = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.open = keyspan_open,
.close = keyspan_close,
@@ -679,10 +671,6 @@ static struct usb_serial_driver keyspan_2port_device = {
},
.description = "Keyspan 2 port adapter",
.id_table = keyspan_2port_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_interrupt_out = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 2,
.open = keyspan_open,
.close = keyspan_close,
@@ -707,10 +695,6 @@ static struct usb_serial_driver keyspan_4port_device = {
},
.description = "Keyspan 4 port adapter",
.id_table = keyspan_4port_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_interrupt_out = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 4,
.open = keyspan_open,
.close = keyspan_close,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index b1fa5a376e96..ff54203944ca 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -208,13 +208,13 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
2000);
if (result < 0)
dbg("%s - error %d from usb_control_msg",
- __FUNCTION__, result);
+ __func__, result);
}
static void keyspan_pda_rx_interrupt (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty = port->tty;
unsigned char *data = urb->transfer_buffer;
int i;
@@ -232,11 +232,11 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
@@ -274,7 +274,7 @@ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __func__, retval);
}
@@ -358,7 +358,7 @@ static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state
value, 0, NULL, 0, 2000);
if (result < 0)
dbg("%s - error %d from usb_control_msg",
- __FUNCTION__, result);
+ __func__, result);
/* there is something funky about this.. the TCSBRK that 'cu' performs
ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
seconds apart, but it feels like the break sent isn't as long as it
@@ -608,7 +608,7 @@ exit:
static void keyspan_pda_write_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct keyspan_pda_private *priv;
port->write_urb_busy = 0;
@@ -636,14 +636,19 @@ static int keyspan_pda_write_room (struct usb_serial_port *port)
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
struct keyspan_pda_private *priv;
+ unsigned long flags;
+ int ret = 0;
priv = usb_get_serial_port_data(port);
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
+
+ spin_lock_irqsave(&port->lock, flags);
if (port->write_urb_busy || priv->tx_throttled)
- return 256;
- return 0;
+ ret = 256;
+ spin_unlock_irqrestore(&port->lock, flags);
+ return ret;
}
@@ -665,11 +670,11 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
1,
2000);
if (rc < 0) {
- dbg("%s - roomquery failed", __FUNCTION__);
+ dbg("%s - roomquery failed", __func__);
goto error;
}
if (rc == 0) {
- dbg("%s - roomquery returned 0 bytes", __FUNCTION__);
+ dbg("%s - roomquery returned 0 bytes", __func__);
rc = -EIO;
goto error;
}
@@ -688,7 +693,7 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
port->interrupt_in_urb->dev = serial->dev;
rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (rc) {
- dbg("%s - usb_submit_urb(read int) failed", __FUNCTION__);
+ dbg("%s - usb_submit_urb(read int) failed", __func__);
goto error;
}
@@ -732,7 +737,7 @@ static int keyspan_pda_fake_startup (struct usb_serial *serial)
record = &xircom_pgs_firmware[0];
#endif
if (record == NULL) {
- err("%s: unknown vendor, aborting.", __FUNCTION__);
+ err("%s: unknown vendor, aborting.", __func__);
return -ENODEV;
}
@@ -779,7 +784,7 @@ static int keyspan_pda_startup (struct usb_serial *serial)
static void keyspan_pda_shutdown (struct usb_serial *serial)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
kfree(usb_get_serial_port_data(serial->port[0]));
}
@@ -793,9 +798,6 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
.description = "Keyspan PDA - (prerenumeration)",
.usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.attach = keyspan_pda_fake_startup,
};
@@ -810,9 +812,6 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
.description = "Xircom / Entregra PGS - (prerenumeration)",
.usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake_xircom,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.attach = keyspan_pda_fake_startup,
};
@@ -826,9 +825,6 @@ static struct usb_serial_driver keyspan_pda_device = {
.description = "Keyspan PDA",
.usb_driver = &keyspan_pda_driver,
.id_table = id_table_std,
- .num_interrupt_in = 1,
- .num_bulk_in = 0,
- .num_bulk_out = 1,
.num_ports = 1,
.open = keyspan_pda_open,
.close = keyspan_pda_close,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 55736df7d2f4..f328948d74e3 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -54,6 +54,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <asm/uaccess.h>
+#include <asm/unaligned.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include "kl5kusb105.h"
@@ -126,9 +127,6 @@ static struct usb_serial_driver kl5kusb105d_device = {
.description = "KL5KUSB105D / PalmConnect",
.usb_driver = &kl5kusb105d_driver,
.id_table = id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = klsi_105_open,
.close = klsi_105_close,
@@ -194,7 +192,7 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port,
if (rc < 0)
err("Change port settings failed (error = %d)", rc);
info("%s - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
- __FUNCTION__,
+ __func__,
settings->pktlen,
settings->baudrate, settings->databits,
settings->unknown1, settings->unknown2);
@@ -225,7 +223,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
__u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1};
__u16 status;
- info("%s - sending SIO Poll request", __FUNCTION__);
+ info("%s - sending SIO Poll request", __func__);
rc = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
KL5KUSB105A_SIO_POLL,
@@ -238,9 +236,9 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
if (rc < 0)
err("Reading line status failed (error = %d)", rc);
else {
- status = le16_to_cpu(*(u16 *)status_buf);
+ status = le16_to_cpu(get_unaligned((__le16 *)status_buf));
- info("%s - read status %x %x", __FUNCTION__,
+ info("%s - read status %x %x", __func__,
status_buf[0], status_buf[1]);
*line_state_p = klsi_105_status2linestate(status);
@@ -268,7 +266,7 @@ static int klsi_105_startup (struct usb_serial *serial)
priv = kmalloc(sizeof(struct klsi_105_private),
GFP_KERNEL);
if (!priv) {
- dbg("%skmalloc for klsi_105_private failed.", __FUNCTION__);
+ dbg("%skmalloc for klsi_105_private failed.", __func__);
i--;
goto err_cleanup;
}
@@ -298,7 +296,7 @@ static int klsi_105_startup (struct usb_serial *serial)
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("%s - out of memory for urb buffers.", __FUNCTION__);
+ err("%s - out of memory for urb buffers.", __func__);
goto err_cleanup;
}
}
@@ -328,7 +326,7 @@ static void klsi_105_shutdown (struct usb_serial *serial)
{
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
@@ -373,7 +371,7 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
struct klsi_105_port_settings cfg;
unsigned long flags;
- dbg("%s port %d", __FUNCTION__, port->number);
+ dbg("%s port %d", __func__, port->number);
/* force low_latency on so that our tty_push actually forces
* the data through
@@ -419,7 +417,7 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (rc) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, rc);
+ err("%s - failed submitting read urb, error %d", __func__, rc);
retval = rc;
goto exit;
}
@@ -437,14 +435,14 @@ static int klsi_105_open (struct usb_serial_port *port, struct file *filp)
err("Enabling read failed (error = %d)", rc);
retval = rc;
} else
- dbg("%s - enabled reading", __FUNCTION__);
+ dbg("%s - enabled reading", __func__);
rc = klsi_105_get_line_state(port, &line_state);
if (rc >= 0) {
spin_lock_irqsave (&priv->lock, flags);
priv->line_state = line_state;
spin_unlock_irqrestore (&priv->lock, flags);
- dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
+ dbg("%s - read line state 0x%lx", __func__, line_state);
retval = 0;
} else
retval = rc;
@@ -459,7 +457,7 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
struct klsi_105_private *priv = usb_get_serial_port_data(port);
int rc;
- dbg("%s port %d", __FUNCTION__, port->number);
+ dbg("%s port %d", __func__, port->number);
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
@@ -502,7 +500,7 @@ static int klsi_105_write (struct usb_serial_port *port,
int result, size;
int bytes_sent=0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
while (count > 0) {
/* try to find a free urb (write 0 bytes if none) */
@@ -514,21 +512,21 @@ static int klsi_105_write (struct usb_serial_port *port,
for (i=0; i<NUM_URBS; i++) {
if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
urb = priv->write_urb_pool[i];
- dbg("%s - using pool URB %d", __FUNCTION__, i);
+ dbg("%s - using pool URB %d", __func__, i);
break;
}
}
spin_unlock_irqrestore (&priv->lock, flags);
if (urb==NULL) {
- dbg("%s - no more free urbs", __FUNCTION__);
+ dbg("%s - no more free urbs", __func__);
goto exit;
}
if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
if (urb->transfer_buffer == NULL) {
- err("%s - no more kernel memory...", __FUNCTION__);
+ err("%s - no more kernel memory...", __func__);
goto exit;
}
}
@@ -554,7 +552,7 @@ static int klsi_105_write (struct usb_serial_port *port,
/* send the data out the bulk port */
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
goto exit;
}
buf += size;
@@ -570,13 +568,13 @@ exit:
static void klsi_105_write_bulk_callback ( struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
+ dbg("%s - nonzero write bulk status received: %d", __func__,
status);
return;
}
@@ -603,7 +601,7 @@ static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
spin_unlock_irqrestore (&priv->lock, flags);
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return (chars);
}
@@ -623,7 +621,7 @@ static int klsi_105_write_room (struct usb_serial_port *port)
spin_unlock_irqrestore (&priv->lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return (room);
}
@@ -631,18 +629,18 @@ static int klsi_105_write_room (struct usb_serial_port *port)
static void klsi_105_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct klsi_105_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int rc;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* The urb might have been killed. */
if (status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
+ dbg("%s - nonzero read bulk status received: %d", __func__,
status);
return;
}
@@ -652,12 +650,12 @@ static void klsi_105_read_bulk_callback (struct urb *urb)
*/
if (urb->actual_length == 0) {
/* empty urbs seem to happen, we ignore them */
- /* dbg("%s - emtpy URB", __FUNCTION__); */
+ /* dbg("%s - emtpy URB", __func__); */
;
} else if (urb->actual_length <= 2) {
- dbg("%s - size %d URB not understood", __FUNCTION__,
+ dbg("%s - size %d URB not understood", __func__,
urb->actual_length);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
} else {
int bytes_sent = ((__u8 *) data)[0] +
@@ -669,12 +667,12 @@ static void klsi_105_read_bulk_callback (struct urb *urb)
* intermixed tty_flip_buffer_push()s
* FIXME
*/
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
if (bytes_sent + 2 > urb->actual_length) {
dbg("%s - trying to read more data than available"
- " (%d vs. %d)", __FUNCTION__,
+ " (%d vs. %d)", __func__,
bytes_sent+2, urb->actual_length);
/* cap at implied limit */
bytes_sent = urb->actual_length - 2;
@@ -697,7 +695,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb)
port);
rc = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (rc)
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, rc);
+ err("%s - failed resubmitting read urb, error %d", __func__, rc);
} /* klsi_105_read_bulk_callback */
@@ -705,12 +703,14 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
struct ktermios *old_termios)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
- unsigned int iflag = port->tty->termios->c_iflag;
+ struct tty_struct *tty = port->tty;
+ unsigned int iflag = tty->termios->c_iflag;
unsigned int old_iflag = old_termios->c_iflag;
- unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int cflag = tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
struct klsi_105_port_settings cfg;
unsigned long flags;
+ speed_t baud;
/* lock while we are modifying the settings */
spin_lock_irqsave (&priv->lock, flags);
@@ -718,10 +718,12 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
/*
* Update baud rate
*/
+ baud = tty_get_baud_rate(tty);
+
if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
/* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag & CBAUD) == B0 ) {
- dbg("%s: baud was B0", __FUNCTION__);
+ dbg("%s: baud was B0", __func__);
#if 0
priv->control_state |= TIOCM_DTR;
/* don't set RTS if using hardware flow control */
@@ -731,8 +733,8 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
}
-
- switch(tty_get_baud_rate(port->tty)) {
+ }
+ switch(baud) {
case 0: /* handled below */
break;
case 1200:
@@ -760,35 +762,36 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
- err("KLSI USB->Serial converter:"
+ dbg("KLSI USB->Serial converter:"
" unsupported baudrate request, using default"
" of 9600");
priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+ baud = 9600;
break;
- }
- if ((cflag & CBAUD) == B0 ) {
- dbg("%s: baud is B0", __FUNCTION__);
- /* Drop RTS and DTR */
- /* maybe this should be simulated by sending read
- * disable and read enable messages?
- */
- ;
+ }
+ if ((cflag & CBAUD) == B0 ) {
+ dbg("%s: baud is B0", __func__);
+ /* Drop RTS and DTR */
+ /* maybe this should be simulated by sending read
+ * disable and read enable messages?
+ */
+ ;
#if 0
- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- mct_u232_set_modem_ctrl(serial, priv->control_state);
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
#endif
- }
}
+ tty_encode_baud_rate(tty, baud, baud);
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
/* set the number of data bits */
switch (cflag & CSIZE) {
case CS5:
- dbg("%s - 5 bits/byte not supported", __FUNCTION__);
+ dbg("%s - 5 bits/byte not supported", __func__);
spin_unlock_irqrestore (&priv->lock, flags);
return ;
case CS6:
- dbg("%s - 6 bits/byte not supported", __FUNCTION__);
+ dbg("%s - 6 bits/byte not supported", __func__);
spin_unlock_irqrestore (&priv->lock, flags);
return ;
case CS7:
@@ -810,6 +813,8 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
|| (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
+ /* Not currently supported */
+ tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB);
#if 0
priv->last_lcr = 0;
@@ -837,6 +842,8 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
|| (iflag & IXON) != (old_iflag & IXON)
|| (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) {
+ /* Not currently supported */
+ tty->termios->c_cflag &= ~CRTSCTS;
/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
@@ -862,7 +869,7 @@ static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
unsigned char lcr = priv->last_lcr;
- dbg("%sstate=%d", __FUNCTION__, break_state);
+ dbg("%sstate=%d", __func__, break_state);
if (break_state)
lcr |= MCT_U232_SET_BREAK;
@@ -877,7 +884,7 @@ static int klsi_105_tiocmget (struct usb_serial_port *port, struct file *file)
unsigned long flags;
int rc;
unsigned long line_state;
- dbg("%s - request, just guessing", __FUNCTION__);
+ dbg("%s - request, just guessing", __func__);
rc = klsi_105_get_line_state(port, &line_state);
if (rc < 0) {
@@ -889,7 +896,7 @@ static int klsi_105_tiocmget (struct usb_serial_port *port, struct file *file)
spin_lock_irqsave (&priv->lock, flags);
priv->line_state = line_state;
spin_unlock_irqrestore (&priv->lock, flags);
- dbg("%s - read line state 0x%lx", __FUNCTION__, line_state);
+ dbg("%s - read line state 0x%lx", __func__, line_state);
return (int)line_state;
}
@@ -898,7 +905,7 @@ static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file,
{
int retval = -EINVAL;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* if this ever gets implemented, it should be done something like this:
struct usb_serial *serial = port->serial;
@@ -924,7 +931,7 @@ static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file,
static void klsi_105_throttle (struct usb_serial_port *port)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->read_urb);
}
@@ -932,12 +939,12 @@ static void klsi_105_unthrottle (struct usb_serial_port *port)
{
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed submitting read urb, error %d", __FUNCTION__,
+ err("%s - failed submitting read urb, error %d", __func__,
result);
}
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 17b3baead4ad..693f00da7c03 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -113,10 +113,6 @@ static struct usb_serial_driver kobil_device = {
.description = "KOBIL USB smart card terminal",
.usb_driver = &kobil_driver,
.id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_interrupt_out = NUM_DONT_CARE,
- .num_bulk_in = 0,
- .num_bulk_out = 0,
.num_ports = 1,
.attach = kobil_startup,
.shutdown = kobil_shutdown,
@@ -139,7 +135,6 @@ struct kobil_private {
int filled; // index of the last char in buf
int cur_pos; // index of the next char to send in buf
__u16 device_type;
- int line_state;
};
@@ -161,7 +156,6 @@ static int kobil_startup (struct usb_serial *serial)
priv->filled = 0;
priv->cur_pos = 0;
priv->device_type = le16_to_cpu(serial->dev->descriptor.idProduct);
- priv->line_state = 0;
switch (priv->device_type){
case KOBIL_ADAPTER_B_PRODUCT_ID:
@@ -189,11 +183,11 @@ static int kobil_startup (struct usb_serial *serial)
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
endpoint = &altsetting->endpoint[i];
if (usb_endpoint_is_int_out(&endpoint->desc)) {
- dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress);
+ dbg("%s Found interrupt out endpoint. Address: %d", __func__, endpoint->desc.bEndpointAddress);
priv->write_int_endpoint_address = endpoint->desc.bEndpointAddress;
}
if (usb_endpoint_is_int_in(&endpoint->desc)) {
- dbg("%s Found interrupt in endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress);
+ dbg("%s Found interrupt in endpoint. Address: %d", __func__, endpoint->desc.bEndpointAddress);
priv->read_int_endpoint_address = endpoint->desc.bEndpointAddress;
}
}
@@ -204,7 +198,7 @@ static int kobil_startup (struct usb_serial *serial)
static void kobil_shutdown (struct usb_serial *serial)
{
int i;
- dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
+ dbg("%s - port %d", __func__, serial->port[0]->number);
for (i=0; i < serial->num_ports; ++i) {
while (serial->port[i]->open_count > 0) {
@@ -224,9 +218,8 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
int transfer_buffer_length = 8;
int write_urb_transfer_buffer_length = 8;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
priv = usb_get_serial_port_data(port);
- priv->line_state = 0;
// someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev;
@@ -252,10 +245,10 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
// allocate write_urb
if (!port->write_urb) {
- dbg("%s - port %d Allocating port->write_urb", __FUNCTION__, port->number);
+ dbg("%s - port %d Allocating port->write_urb", __func__, port->number);
port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->write_urb) {
- dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);
+ dbg("%s - port %d usb_alloc_urb failed", __func__, port->number);
kfree(transfer_buffer);
return -ENOMEM;
}
@@ -281,7 +274,7 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
transfer_buffer_length,
KOBIL_TIMEOUT
);
- dbg("%s - port %d Send get_HW_version URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send get_HW_version URB returns: %i", __func__, port->number, result);
dbg("Harware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
// get firmware version
@@ -295,7 +288,7 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
transfer_buffer_length,
KOBIL_TIMEOUT
);
- dbg("%s - port %d Send get_FW_version URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send get_FW_version URB returns: %i", __func__, port->number, result);
dbg("Firmware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
@@ -310,7 +303,7 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
0,
KOBIL_TIMEOUT
);
- dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send set_baudrate URB returns: %i", __func__, port->number, result);
// reset all queues
result = usb_control_msg( port->serial->dev,
@@ -323,13 +316,13 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
0,
KOBIL_TIMEOUT
);
- dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send reset_all_queues URB returns: %i", __func__, port->number, result);
}
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
// start reading (Adapter B 'cause PNP string)
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC );
- dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send read URB returns: %i", __func__, port->number, result);
}
kfree(transfer_buffer);
@@ -339,7 +332,7 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
static void kobil_close (struct usb_serial_port *port, struct file *filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (port->write_urb) {
usb_kill_urb(port->write_urb);
@@ -359,11 +352,11 @@ static void kobil_read_int_callback(struct urb *urb)
int status = urb->status;
// char *dbg_data;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - port %d Read int status not zero: %d",
- __FUNCTION__, port->number, status);
+ __func__, port->number, status);
return;
}
@@ -393,7 +386,7 @@ static void kobil_read_int_callback(struct urb *urb)
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send read URB returns: %i", __func__, port->number, result);
}
@@ -411,21 +404,21 @@ static int kobil_write (struct usb_serial_port *port,
struct kobil_private * priv;
if (count == 0) {
- dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number);
+ dbg("%s - port %d write request of 0 bytes", __func__, port->number);
return 0;
}
priv = usb_get_serial_port_data(port);
if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
- dbg("%s - port %d Error: write request bigger than buffer size", __FUNCTION__, port->number);
+ dbg("%s - port %d Error: write request bigger than buffer size", __func__, port->number);
return -ENOMEM;
}
// Copy data to buffer
memcpy (priv->buf + priv->filled, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, priv->buf + priv->filled);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, priv->buf + priv->filled);
priv->filled = priv->filled + count;
@@ -457,7 +450,7 @@ static int kobil_write (struct usb_serial_port *port,
priv->cur_pos = priv->cur_pos + length;
result = usb_submit_urb( port->write_urb, GFP_NOIO );
- dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send write URB returns: %i", __func__, port->number, result);
todo = priv->filled - priv->cur_pos;
if (todo > 0) {
@@ -478,7 +471,7 @@ static int kobil_write (struct usb_serial_port *port,
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb( port->interrupt_in_urb, GFP_NOIO );
- dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send read URB returns: %i", __func__, port->number, result);
}
}
return count;
@@ -487,7 +480,7 @@ static int kobil_write (struct usb_serial_port *port,
static int kobil_write_room (struct usb_serial_port *port)
{
- //dbg("%s - port %d", __FUNCTION__, port->number);
+ //dbg("%s - port %d", __func__, port->number);
return 8;
}
@@ -522,16 +515,13 @@ static int kobil_tiocmget(struct usb_serial_port *port, struct file *file)
KOBIL_TIMEOUT);
dbg("%s - port %d Send get_status_line_state URB returns: %i. Statusline: %02x",
- __FUNCTION__, port->number, result, transfer_buffer[0]);
-
- if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) {
- priv->line_state |= TIOCM_DSR;
- } else {
- priv->line_state &= ~TIOCM_DSR;
- }
+ __func__, port->number, result, transfer_buffer[0]);
+ result = 0;
+ if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0)
+ result = TIOCM_DSR;
kfree(transfer_buffer);
- return priv->line_state;
+ return result;
}
static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
@@ -544,6 +534,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
+ /* FIXME: locking ? */
priv = usb_get_serial_port_data(port);
if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
// This device doesn't support ioctl calls
@@ -567,9 +558,9 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
if (dtr != 0)
- dbg("%s - port %d Setting DTR", __FUNCTION__, port->number);
+ dbg("%s - port %d Setting DTR", __func__, port->number);
else
- dbg("%s - port %d Clearing DTR", __FUNCTION__, port->number);
+ dbg("%s - port %d Clearing DTR", __func__, port->number);
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
SUSBCRequest_SetStatusLinesOrQueues,
@@ -581,9 +572,9 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
KOBIL_TIMEOUT);
} else {
if (rts != 0)
- dbg("%s - port %d Setting RTS", __FUNCTION__, port->number);
+ dbg("%s - port %d Setting RTS", __func__, port->number);
else
- dbg("%s - port %d Clearing RTS", __FUNCTION__, port->number);
+ dbg("%s - port %d Clearing RTS", __func__, port->number);
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
SUSBCRequest_SetStatusLinesOrQueues,
@@ -594,7 +585,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
0,
KOBIL_TIMEOUT);
}
- dbg("%s - port %d Send set_status_line URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send set_status_line URB returns: %i", __func__, port->number, result);
kfree(transfer_buffer);
return (result < 0) ? result : 0;
}
@@ -687,7 +678,7 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigne
KOBIL_TIMEOUT
);
- dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
+ dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result);
kfree(transfer_buffer);
return (result < 0) ? -EFAULT : 0;
default:
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index fc1cea4aba13..5fc2cef30e39 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -143,9 +143,6 @@ static struct usb_serial_driver mct_u232_device = {
.description = "MCT U232",
.usb_driver = &mct_u232_driver,
.id_table = id_table_combined,
- .num_interrupt_in = 2,
- .num_bulk_in = 0,
- .num_bulk_out = 1,
.num_ports = 1,
.open = mct_u232_open,
.close = mct_u232_close,
@@ -402,7 +399,7 @@ static void mct_u232_shutdown (struct usb_serial *serial)
struct mct_u232_private *priv;
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i=0; i < serial->num_ports; ++i) {
/* My special items, the standard routines free my urbs */
@@ -424,7 +421,7 @@ static int mct_u232_open (struct usb_serial_port *port, struct file *filp)
unsigned char last_lcr;
unsigned char last_msr;
- dbg("%s port %d", __FUNCTION__, port->number);
+ dbg("%s port %d", __func__, port->number);
/* Compensate for a hardware bug: although the Sitecom U232-P25
* device reports a maximum output packet size of 32 bytes,
@@ -489,7 +486,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
unsigned int c_cflag;
unsigned int control_state;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- dbg("%s port %d", __FUNCTION__, port->number);
+ dbg("%s port %d", __func__, port->number);
if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
@@ -517,7 +514,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
static void mct_u232_read_int_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
struct tty_struct *tty;
@@ -535,21 +532,21 @@ static void mct_u232_read_int_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
if (!serial) {
- dbg("%s - bad serial pointer, exiting", __FUNCTION__);
+ dbg("%s - bad serial pointer, exiting", __func__);
return;
}
- dbg("%s - port %d", __FUNCTION__, port->number);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ dbg("%s - port %d", __func__, port->number);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
/*
* Work-a-round: handle the 'usual' bulk-in pipe here
@@ -606,7 +603,7 @@ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __func__, retval);
} /* mct_u232_read_int_callback */
static void mct_u232_set_termios (struct usb_serial_port *port,
@@ -636,7 +633,7 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
/* reassert DTR and RTS on transition from B0 */
if ((old_cflag & CBAUD) == B0) {
- dbg("%s: baud was B0", __FUNCTION__);
+ dbg("%s: baud was B0", __func__);
control_state |= TIOCM_DTR | TIOCM_RTS;
mct_u232_set_modem_ctrl(serial, control_state);
}
@@ -644,7 +641,7 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
mct_u232_set_baud_rate(serial, port, tty_get_baud_rate(port->tty));
if ((cflag & CBAUD) == B0 ) {
- dbg("%s: baud is B0", __FUNCTION__);
+ dbg("%s: baud is B0", __func__);
/* Drop RTS and DTR */
control_state &= ~(TIOCM_DTR | TIOCM_RTS);
mct_u232_set_modem_ctrl(serial, control_state);
@@ -699,7 +696,7 @@ static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
unsigned char lcr;
unsigned long flags;
- dbg("%sstate=%d", __FUNCTION__, break_state);
+ dbg("%sstate=%d", __func__, break_state);
spin_lock_irqsave(&priv->lock, flags);
lcr = priv->last_lcr;
@@ -718,7 +715,7 @@ static int mct_u232_tiocmget (struct usb_serial_port *port, struct file *file)
unsigned int control_state;
unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -735,7 +732,7 @@ static int mct_u232_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int control_state;
unsigned long flags;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -757,7 +754,7 @@ static int mct_u232_tiocmset (struct usb_serial_port *port, struct file *file,
static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
unsigned int cmd, unsigned long arg)
{
- dbg("%scmd=0x%x", __FUNCTION__, cmd);
+ dbg("%scmd=0x%x", __func__, cmd);
/* Based on code from acm.c and others */
switch (cmd) {
@@ -772,7 +769,7 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
return 0;
default:
- dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
+ dbg("%s: arg not supported - 0x%04x", __func__,cmd);
return(-ENOIOCTLCMD);
break;
}
@@ -787,7 +784,7 @@ static void mct_u232_throttle (struct usb_serial_port *port)
struct tty_struct *tty;
tty = port->tty;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->rx_flags |= THROTTLED;
@@ -809,7 +806,7 @@ static void mct_u232_unthrottle (struct usb_serial_port *port)
unsigned int control_state;
struct tty_struct *tty;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
tty = port->tty;
spin_lock_irqsave(&priv->lock, flags);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 40f3a0188807..50f1fe263338 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -118,11 +118,11 @@ static void mos7720_interrupt_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ dbg("%s - urb shutting down with status: %d", __func__,
status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ dbg("%s - nonzero urb status received: %d", __func__,
status);
goto exit;
}
@@ -183,7 +183,7 @@ exit:
if (result)
dev_err(&urb->dev->dev,
"%s - Error %d submitting control urb\n",
- __FUNCTION__, result);
+ __func__, result);
return;
}
@@ -214,7 +214,7 @@ static void mos7720_bulk_in_callback(struct urb *urb)
port = mos7720_port->port;
- dbg("Entering...%s", __FUNCTION__);
+ dbg("Entering...%s", __func__);
data = urb->transfer_buffer;
@@ -362,7 +362,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
- err("%s-out of memory for urb buffers.", __FUNCTION__);
+ err("%s-out of memory for urb buffers.", __func__);
usb_free_urb(mos7720_port->write_urb_pool[j]);
mos7720_port->write_urb_pool[j] = NULL;
continue;
@@ -479,7 +479,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
if (response)
dev_err(&port->dev,
"%s - Error %d submitting control urb\n",
- __FUNCTION__, response);
+ __func__, response);
}
/* set up our bulk in urb */
@@ -492,7 +492,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
response = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (response)
dev_err(&port->dev,
- "%s - Error %d submitting read urb\n", __FUNCTION__, response);
+ "%s - Error %d submitting read urb\n", __func__, response);
/* initialize our icount structure */
memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
@@ -521,11 +521,11 @@ static int mos7720_chars_in_buffer(struct usb_serial_port *port)
int chars = 0;
struct moschip_port *mos7720_port;
- dbg("%s:entering ...........", __FUNCTION__);
+ dbg("%s:entering ...........", __func__);
mos7720_port = usb_get_serial_port_data(port);
if (mos7720_port == NULL) {
- dbg("%s:leaving ...........", __FUNCTION__);
+ dbg("%s:leaving ...........", __func__);
return -ENODEV;
}
@@ -533,7 +533,7 @@ static int mos7720_chars_in_buffer(struct usb_serial_port *port)
if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
chars += URB_TRANSFER_BUFFER_SIZE;
}
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return chars;
}
@@ -585,7 +585,7 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
mutex_unlock(&serial->disc_mutex);
mos7720_port->open = 0;
- dbg("Leaving %s", __FUNCTION__);
+ dbg("Leaving %s", __func__);
}
static void mos7720_break(struct usb_serial_port *port, int break_state)
@@ -594,7 +594,7 @@ static void mos7720_break(struct usb_serial_port *port, int break_state)
struct usb_serial *serial;
struct moschip_port *mos7720_port;
- dbg("Entering %s", __FUNCTION__);
+ dbg("Entering %s", __func__);
serial = port->serial;
@@ -627,20 +627,21 @@ static int mos7720_write_room(struct usb_serial_port *port)
int room = 0;
int i;
- dbg("%s:entering ...........", __FUNCTION__);
+ dbg("%s:entering ...........", __func__);
mos7720_port = usb_get_serial_port_data(port);
if (mos7720_port == NULL) {
- dbg("%s:leaving ...........", __FUNCTION__);
+ dbg("%s:leaving ...........", __func__);
return -ENODEV;
}
+ /* FIXME: Locking */
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
room += URB_TRANSFER_BUFFER_SIZE;
}
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -657,7 +658,7 @@ static int mos7720_write(struct usb_serial_port *port,
struct urb *urb;
const unsigned char *current_position = data;
- dbg("%s:entering ...........", __FUNCTION__);
+ dbg("%s:entering ...........", __func__);
serial = port->serial;
@@ -679,7 +680,7 @@ static int mos7720_write(struct usb_serial_port *port,
}
if (urb == NULL) {
- dbg("%s - no more free urbs", __FUNCTION__);
+ dbg("%s - no more free urbs", __func__);
goto exit;
}
@@ -687,14 +688,14 @@ static int mos7720_write(struct usb_serial_port *port,
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (urb->transfer_buffer == NULL) {
- err("%s no more kernel memory...", __FUNCTION__);
+ err("%s no more kernel memory...", __func__);
goto exit;
}
}
transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
memcpy(urb->transfer_buffer, current_position, transfer_size);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size,
+ usb_serial_debug_data(debug, &port->dev, __func__, transfer_size,
urb->transfer_buffer);
/* fill urb with data and submit */
@@ -708,7 +709,7 @@ static int mos7720_write(struct usb_serial_port *port,
status = usb_submit_urb(urb,GFP_ATOMIC);
if (status) {
err("%s - usb_submit_urb(write bulk) failed with status = %d",
- __FUNCTION__, status);
+ __func__, status);
bytes_sent = status;
goto exit;
}
@@ -724,7 +725,7 @@ static void mos7720_throttle(struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- dbg("%s- port %d\n", __FUNCTION__, port->number);
+ dbg("%s- port %d\n", __func__, port->number);
mos7720_port = usb_get_serial_port_data(port);
@@ -736,11 +737,11 @@ static void mos7720_throttle(struct usb_serial_port *port)
return;
}
- dbg("%s: Entering ..........", __FUNCTION__);
+ dbg("%s: Entering ..........", __func__);
tty = port->tty;
if (!tty) {
- dbg("%s - no tty available", __FUNCTION__);
+ dbg("%s - no tty available", __func__);
return;
}
@@ -773,15 +774,15 @@ static void mos7720_unthrottle(struct usb_serial_port *port)
return;
if (!mos7720_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
- dbg("%s: Entering ..........", __FUNCTION__);
+ dbg("%s: Entering ..........", __func__);
tty = port->tty;
if (!tty) {
- dbg("%s - no tty available", __FUNCTION__);
+ dbg("%s - no tty available", __func__);
return;
}
@@ -922,7 +923,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor)
__u16 round;
- dbg("%s - %d", __FUNCTION__, baudrate);
+ dbg("%s - %d", __func__, baudrate);
for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
if (divisor_table[i].baudrate == baudrate) {
@@ -973,15 +974,15 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
port = mos7720_port->port;
serial = port->serial;
- dbg("%s: Entering ..........", __FUNCTION__);
+ dbg("%s: Entering ..........", __func__);
number = port->number - port->serial->minor;
- dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate);
+ dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate);
/* Calculate the Divisor */
status = calc_baud_rate_divisor(baudrate, &divisor);
if (status) {
- err("%s - bad baud rate", __FUNCTION__);
+ err("%s - bad baud rate", __func__);
return status;
}
@@ -1034,16 +1035,16 @@ static void change_port_settings(struct moschip_port *mos7720_port,
serial = port->serial;
port_number = port->number - port->serial->minor;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!mos7720_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
tty = mos7720_port->port->tty;
- dbg("%s: Entering ..........", __FUNCTION__);
+ dbg("%s: Entering ..........", __func__);
lData = UART_LCR_WLEN8;
lStop = 0x00; /* 1 stop bit */
@@ -1078,14 +1079,14 @@ static void change_port_settings(struct moschip_port *mos7720_port,
if (cflag & PARENB) {
if (cflag & PARODD) {
lParity = UART_LCR_PARITY;
- dbg("%s - parity = odd", __FUNCTION__);
+ dbg("%s - parity = odd", __func__);
} else {
lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
- dbg("%s - parity = even", __FUNCTION__);
+ dbg("%s - parity = even", __func__);
}
} else {
- dbg("%s - parity = none", __FUNCTION__);
+ dbg("%s - parity = none", __func__);
}
if (cflag & CMSPAR)
@@ -1094,10 +1095,10 @@ static void change_port_settings(struct moschip_port *mos7720_port,
/* Change the Stop bit */
if (cflag & CSTOPB) {
lStop = UART_LCR_STOP;
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
} else {
lStop = 0x00;
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
}
#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
@@ -1171,7 +1172,7 @@ static void change_port_settings(struct moschip_port *mos7720_port,
return;
}
- dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ dbg("%s - baud rate = %d", __func__, baud);
status = send_cmd_write_baud_rate(mos7720_port, baud);
/* FIXME: needs to write actual resulting baud back not just
blindly do so */
@@ -1217,7 +1218,7 @@ static void mos7720_set_termios(struct usb_serial_port *port,
if (!mos7720_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
@@ -1225,15 +1226,15 @@ static void mos7720_set_termios(struct usb_serial_port *port,
cflag = tty->termios->c_cflag;
- dbg("%s - cflag %08x iflag %08x", __FUNCTION__,
+ dbg("%s - cflag %08x iflag %08x", __func__,
tty->termios->c_cflag,
RELEVANT_IFLAG(tty->termios->c_iflag));
- dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__,
+ dbg("%s - old cflag %08x old iflag %08x", __func__,
old_termios->c_cflag,
RELEVANT_IFLAG(old_termios->c_iflag));
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* change the port settings to the new ones specified */
change_port_settings(mos7720_port, old_termios);
@@ -1271,7 +1272,7 @@ static int get_lsr_info(struct moschip_port *mos7720_port,
count = mos7720_chars_in_buffer(mos7720_port->port);
if (count == 0) {
- dbg("%s -- Empty", __FUNCTION__);
+ dbg("%s -- Empty", __func__);
result = TIOCSER_TEMT;
}
@@ -1296,7 +1297,7 @@ static int get_number_bytes_avail(struct moschip_port *mos7720_port,
result = tty->read_cnt;
- dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result);
+ dbg("%s(%d) = %d", __func__, mos7720_port->port->number, result);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -1374,7 +1375,7 @@ static int get_modem_info(struct moschip_port *mos7720_port,
| ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
- dbg("%s -- %x", __FUNCTION__, result);
+ dbg("%s -- %x", __func__, result);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -1418,45 +1419,45 @@ static int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
if (mos7720_port == NULL)
return -ENODEV;
- dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
switch (cmd) {
case TIOCINQ:
/* return number of bytes available */
- dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
+ 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", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
return get_lsr_info(mos7720_port, (unsigned int __user *)arg);
return 0;
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
- dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__,
port->number);
return set_modem_info(mos7720_port, cmd,
(unsigned int __user *)arg);
case TIOCMGET:
- dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCMGET", __func__, port->number);
return get_modem_info(mos7720_port,
(unsigned int __user *)arg);
case TIOCGSERIAL:
- dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
return get_serial_info(mos7720_port,
(struct serial_struct __user *)arg);
case TIOCSSERIAL:
- dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
break;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
cprev = mos7720_port->icount;
while (1) {
if (signal_pending(current))
@@ -1490,7 +1491,7 @@ static int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
- dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
port->number, icount.rx, icount.tx );
if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
return -EFAULT;
@@ -1508,7 +1509,7 @@ static int mos7720_startup(struct usb_serial *serial)
int i;
char data;
- dbg("%s: Entering ..........", __FUNCTION__);
+ dbg("%s: Entering ..........", __func__);
if (!serial) {
dbg("Invalid Handler");
@@ -1520,7 +1521,7 @@ static int mos7720_startup(struct usb_serial *serial)
/* create our private serial structure */
mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
if (mos7720_serial == NULL) {
- err("%s - Out of memory", __FUNCTION__);
+ err("%s - Out of memory", __func__);
return -ENOMEM;
}
@@ -1533,7 +1534,7 @@ static int mos7720_startup(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
if (mos7720_port == NULL) {
- err("%s - Out of memory", __FUNCTION__);
+ err("%s - Out of memory", __func__);
usb_set_serial_data(serial, NULL);
kfree(mos7720_serial);
return -ENOMEM;
@@ -1596,9 +1597,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.description = "Moschip 2 port adapter",
.usb_driver = &usb_driver,
.id_table = moschip_port_id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 2,
- .num_bulk_out = 2,
.num_ports = 2,
.open = mos7720_open,
.close = mos7720_close,
@@ -1620,7 +1618,7 @@ static int __init moschip7720_init(void)
{
int retval;
- dbg("%s: Entering ..........", __FUNCTION__);
+ dbg("%s: Entering ..........", __func__);
/* Register with the usb serial */
retval = usb_serial_register(&moschip7720_2port_driver);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index aeeb9cb20999..6bcb82d3911a 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -403,7 +403,7 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
{
struct async_icount *icount;
- dbg("%s - %02x", __FUNCTION__, new_lsr);
+ dbg("%s - %02x", __func__, new_lsr);
if (new_lsr & SERIAL_LSR_BI) {
//
@@ -449,7 +449,7 @@ static void mos7840_control_callback(struct urb *urb)
int result = 0;
int status = urb->status;
- mos7840_port = (struct moschip_port *)urb->context;
+ mos7840_port = urb->context;
switch (status) {
case 0:
@@ -459,21 +459,21 @@ static void mos7840_control_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ dbg("%s - urb shutting down with status: %d", __func__,
status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ dbg("%s - nonzero urb status received: %d", __func__,
status);
goto exit;
}
- dbg("%s urb buffer size is %d\n", __FUNCTION__, urb->actual_length);
- dbg("%s mos7840_port->MsrLsr is %d port %d\n", __FUNCTION__,
+ dbg("%s urb buffer size is %d\n", __func__, urb->actual_length);
+ dbg("%s mos7840_port->MsrLsr is %d port %d\n", __func__,
mos7840_port->MsrLsr, mos7840_port->port_num);
data = urb->transfer_buffer;
regval = (__u8) data[0];
- dbg("%s data is %x\n", __FUNCTION__, regval);
+ dbg("%s data is %x\n", __func__, regval);
if (mos7840_port->MsrLsr == 0)
mos7840_handle_new_msr(mos7840_port, regval);
else if (mos7840_port->MsrLsr == 1)
@@ -487,7 +487,7 @@ exit:
if (result) {
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
- __FUNCTION__, result);
+ __func__, result);
}
}
@@ -542,11 +542,11 @@ static void mos7840_interrupt_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ dbg("%s - urb shutting down with status: %d", __func__,
status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ dbg("%s - nonzero urb status received: %d", __func__,
status);
goto exit;
}
@@ -554,7 +554,7 @@ static void mos7840_interrupt_callback(struct urb *urb)
length = urb->actual_length;
data = urb->transfer_buffer;
- serial = (struct usb_serial *)urb->context;
+ serial = urb->context;
/* Moschip get 5 bytes
* Byte 1 IIR Port 1 (port.number is 0)
@@ -614,7 +614,7 @@ exit:
if (result) {
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
- __FUNCTION__, result);
+ __func__, result);
}
}
@@ -685,19 +685,19 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
- mos7840_port = (struct moschip_port *)urb->context;
+ mos7840_port = urb->context;
if (!mos7840_port) {
dbg("%s", "NULL mos7840_port pointer \n");
return;
}
port = (struct usb_serial_port *)mos7840_port->port;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
return;
}
- serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ serial = mos7840_get_usb_serial(port, __func__);
if (!serial) {
dbg("%s\n", "Bad serial pointer ");
return;
@@ -752,7 +752,7 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
int status = urb->status;
int i;
- mos7840_port = (struct moschip_port *)urb->context;
+ mos7840_port = urb->context;
spin_lock(&mos7840_port->pool_lock);
for (i = 0; i < NUM_URBS; i++) {
if (urb == mos7840_port->write_urb_pool[i]) {
@@ -767,7 +767,7 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
return;
}
- if (mos7840_port_paranoia_check(mos7840_port->port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
return;
}
@@ -815,14 +815,14 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
struct moschip_port *mos7840_port;
struct moschip_port *port0;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
return -ENODEV;
}
serial = port->serial;
- if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ if (mos7840_serial_paranoia_check(serial, __func__)) {
dbg("%s", "Serial Paranoia failed \n");
return -ENODEV;
}
@@ -851,7 +851,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
if (!urb->transfer_buffer) {
usb_free_urb(urb);
mos7840_port->write_urb_pool[j] = NULL;
- err("%s-out of memory for urb buffers.", __FUNCTION__);
+ err("%s-out of memory for urb buffers.", __func__);
continue;
}
}
@@ -1039,7 +1039,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
GFP_KERNEL);
if (response) {
err("%s - Error %d submitting interrupt urb",
- __FUNCTION__, response);
+ __func__, response);
}
}
@@ -1072,7 +1072,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp)
port->bulk_in_endpointAddress);
response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (response) {
- err("%s - Error %d submitting control urb", __FUNCTION__,
+ err("%s - Error %d submitting control urb", __func__,
response);
}
@@ -1116,7 +1116,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return -1;
}
@@ -1134,7 +1134,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
}
}
spin_unlock_irqrestore(&mos7840_port->pool_lock,flags);
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return chars;
}
@@ -1171,7 +1171,7 @@ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
/* No activity.. count down section */
wait--;
if (wait == 0) {
- dbg("%s - TIMEOUT", __FUNCTION__);
+ dbg("%s - TIMEOUT", __func__);
return;
} else {
/* Reset timeout value back to seconds */
@@ -1195,12 +1195,12 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
dbg("%s\n", "mos7840_close:entering...");
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
return;
}
- serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ serial = mos7840_get_usb_serial(port, __func__);
if (!serial) {
dbg("%s", "Serial Paranoia failed \n");
return;
@@ -1314,7 +1314,7 @@ static void mos7840_block_until_chase_response(struct moschip_port
/* No activity.. count down section */
wait--;
if (wait == 0) {
- dbg("%s - TIMEOUT", __FUNCTION__);
+ dbg("%s - TIMEOUT", __func__);
return;
} else {
/* Reset timeout value back to seconds */
@@ -1337,12 +1337,12 @@ static void mos7840_break(struct usb_serial_port *port, int break_state)
dbg("%s \n", "Entering ...........");
dbg("mos7840_break: Start\n");
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
return;
}
- serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ serial = mos7840_get_usb_serial(port, __func__);
if (!serial) {
dbg("%s", "Serial Paranoia failed \n");
return;
@@ -1392,7 +1392,7 @@ static int mos7840_write_room(struct usb_serial_port *port)
dbg("%s \n", " mos7840_write_room:entering ...........");
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
dbg("%s \n", " mos7840_write_room:leaving ...........");
return -1;
@@ -1413,7 +1413,7 @@ static int mos7840_write_room(struct usb_serial_port *port)
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -1480,13 +1480,13 @@ static int mos7840_write(struct usb_serial_port *port,
status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
#endif
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
return -1;
}
serial = port->serial;
- if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ if (mos7840_serial_paranoia_check(serial, __func__)) {
dbg("%s", "Serial Paranoia failed \n");
return -1;
}
@@ -1512,7 +1512,7 @@ static int mos7840_write(struct usb_serial_port *port,
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
if (urb == NULL) {
- dbg("%s - no more free urbs", __FUNCTION__);
+ dbg("%s - no more free urbs", __func__);
goto exit;
}
@@ -1521,7 +1521,7 @@ static int mos7840_write(struct usb_serial_port *port,
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (urb->transfer_buffer == NULL) {
- err("%s no more kernel memory...", __FUNCTION__);
+ err("%s no more kernel memory...", __func__);
goto exit;
}
}
@@ -1547,7 +1547,7 @@ static int mos7840_write(struct usb_serial_port *port,
if (status) {
mos7840_port->busy[i] = 0;
err("%s - usb_submit_urb(write bulk) failed with status = %d",
- __FUNCTION__, status);
+ __func__, status);
bytes_sent = status;
goto exit;
}
@@ -1573,7 +1573,7 @@ static void mos7840_throttle(struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return;
}
@@ -1594,7 +1594,7 @@ static void mos7840_throttle(struct usb_serial_port *port)
tty = port->tty;
if (!tty) {
- dbg("%s - no tty available", __FUNCTION__);
+ dbg("%s - no tty available", __func__);
return;
}
@@ -1634,7 +1634,7 @@ static void mos7840_unthrottle(struct usb_serial_port *port)
int status;
struct moschip_port *mos7840_port = mos7840_get_port_private(port);
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return;
}
@@ -1643,7 +1643,7 @@ static void mos7840_unthrottle(struct usb_serial_port *port)
return;
if (!mos7840_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
@@ -1651,7 +1651,7 @@ static void mos7840_unthrottle(struct usb_serial_port *port)
tty = port->tty;
if (!tty) {
- dbg("%s - no tty available", __FUNCTION__);
+ dbg("%s - no tty available", __func__);
return;
}
@@ -1688,7 +1688,7 @@ static int mos7840_tiocmget(struct usb_serial_port *port, struct file *file)
int status = 0;
mos7840_port = mos7840_get_port_private(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (mos7840_port == NULL)
return -ENODEV;
@@ -1703,7 +1703,7 @@ static int mos7840_tiocmget(struct usb_serial_port *port, struct file *file)
| ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
| ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
- dbg("%s - 0x%04X", __FUNCTION__, result);
+ dbg("%s - 0x%04X", __func__, result);
return result;
}
@@ -1715,13 +1715,14 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int mcr;
unsigned int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
mos7840_port = mos7840_get_port_private(port);
if (mos7840_port == NULL)
return -ENODEV;
+ /* FIXME: What locks the port registers ? */
mcr = mos7840_port->shadowMCR;
if (clear & TIOCM_RTS)
mcr &= ~MCR_RTS;
@@ -1758,7 +1759,7 @@ static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
__u16 * clk_sel_val)
{
- dbg("%s - %d", __FUNCTION__, baudRate);
+ dbg("%s - %d", __func__, baudRate);
if (baudRate <= 115200) {
*divisor = 115200 / baudRate;
@@ -1841,12 +1842,12 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
return -1;
port = (struct usb_serial_port *)mos7840_port->port;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return -1;
}
- if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
+ if (mos7840_serial_paranoia_check(port->serial, __func__)) {
dbg("%s", "Invalid Serial \n");
return -1;
}
@@ -1855,7 +1856,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
number = mos7840_port->port->number - mos7840_port->port->serial->minor;
- dbg("%s - port = %d, baud = %d", __FUNCTION__,
+ dbg("%s - port = %d, baud = %d", __func__,
mos7840_port->port->number, baudRate);
//reset clk_uart_sel in spregOffset
if (baudRate > 115200) {
@@ -1915,7 +1916,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
/* Calculate the Divisor */
if (status) {
- err("%s - bad baud rate", __FUNCTION__);
+ err("%s - bad baud rate", __func__);
dbg("%s\n", "bad baud rate");
return status;
}
@@ -1969,22 +1970,22 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
port = (struct usb_serial_port *)mos7840_port->port;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return;
}
- if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
+ if (mos7840_serial_paranoia_check(port->serial, __func__)) {
dbg("%s", "Invalid Serial \n");
return;
}
serial = port->serial;
- dbg("%s - port %d", __FUNCTION__, mos7840_port->port->number);
+ dbg("%s - port %d", __func__, mos7840_port->port->number);
if (!mos7840_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
@@ -2023,14 +2024,14 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
if (cflag & PARENB) {
if (cflag & PARODD) {
lParity = LCR_PAR_ODD;
- dbg("%s - parity = odd", __FUNCTION__);
+ dbg("%s - parity = odd", __func__);
} else {
lParity = LCR_PAR_EVEN;
- dbg("%s - parity = even", __FUNCTION__);
+ dbg("%s - parity = even", __func__);
}
} else {
- dbg("%s - parity = none", __FUNCTION__);
+ dbg("%s - parity = none", __func__);
}
if (cflag & CMSPAR) {
@@ -2040,10 +2041,10 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
/* Change the Stop bit */
if (cflag & CSTOPB) {
lStop = LCR_STOP_2;
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
} else {
lStop = LCR_STOP_1;
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
}
/* Update the LCR with the correct value */
@@ -2100,7 +2101,7 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
baud = 9600;
}
- dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ dbg("%s - baud rate = %d", __func__, baud);
status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
/* Enable Interrupts */
@@ -2140,14 +2141,14 @@ static void mos7840_set_termios(struct usb_serial_port *port,
struct moschip_port *mos7840_port;
struct tty_struct *tty;
dbg("mos7840_set_termios: START\n");
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return;
}
serial = port->serial;
- if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ if (mos7840_serial_paranoia_check(serial, __func__)) {
dbg("%s", "Invalid Serial \n");
return;
}
@@ -2160,7 +2161,7 @@ static void mos7840_set_termios(struct usb_serial_port *port,
tty = port->tty;
if (!mos7840_port->open) {
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
return;
}
@@ -2168,11 +2169,11 @@ static void mos7840_set_termios(struct usb_serial_port *port,
cflag = tty->termios->c_cflag;
- dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ dbg("%s - clfag %08x iflag %08x", __func__,
tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* change the port settings to the new ones specified */
@@ -2213,7 +2214,7 @@ static int mos7840_get_lsr_info(struct moschip_port *mos7840_port,
count = mos7840_chars_in_buffer(mos7840_port->port);
if (count == 0) {
- dbg("%s -- Empty", __FUNCTION__);
+ dbg("%s -- Empty", __func__);
result = TIOCSER_TEMT;
}
@@ -2240,7 +2241,7 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
return -1;
port = (struct usb_serial_port *)mos7840_port->port;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return -1;
}
@@ -2314,7 +2315,7 @@ static int mos7840_get_modem_info(struct moschip_port *mos7840_port,
|((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
|((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
- dbg("%s -- %x", __FUNCTION__, result);
+ dbg("%s -- %x", __func__, result);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -2371,7 +2372,7 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
struct serial_icounter_struct icount;
int mosret = 0;
- if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port \n");
return -1;
}
@@ -2383,39 +2384,39 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
tty = mos7840_port->port->tty;
- dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
switch (cmd) {
/* return number of bytes available */
case TIOCSERGETLSR:
- dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
return mos7840_get_lsr_info(mos7840_port, argp);
return 0;
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
- dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__,
port->number);
mosret =
mos7840_set_modem_info(mos7840_port, cmd, argp);
return mosret;
case TIOCMGET:
- dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCMGET", __func__, port->number);
return mos7840_get_modem_info(mos7840_port, argp);
case TIOCGSERIAL:
- dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
return mos7840_get_serial_info(mos7840_port, argp);
case TIOCSSERIAL:
- dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
break;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
cprev = mos7840_port->icount;
while (1) {
//interruptible_sleep_on(&mos7840_port->delta_msr_wait);
@@ -2458,7 +2459,7 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
- dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
port->number, icount.rx, icount.tx);
if (copy_to_user(argp, &icount, sizeof(icount)))
return -EFAULT;
@@ -2521,7 +2522,7 @@ static int mos7840_startup(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
if (mos7840_port == NULL) {
- err("%s - Out of memory", __FUNCTION__);
+ err("%s - Out of memory", __func__);
status = -ENOMEM;
i--; /* don't follow NULL pointer cleaning up */
goto error;
@@ -2799,12 +2800,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
.description = DRIVER_DESC,
.usb_driver = &io_driver,
.id_table = moschip_port_id_table,
- .num_interrupt_in = 1, //NUM_DONT_CARE,//1,
-#ifdef check
- .num_bulk_in = 4,
- .num_bulk_out = 4,
.num_ports = 4,
-#endif
.open = mos7840_open,
.close = mos7840_close,
.write = mos7840_write,
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 7f337c9aeb5f..43c8894353bf 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -6,6 +6,10 @@
* 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.
+ *
+ * TODO:
+ * Add termios method that uses copy_hw but also kills all echo
+ * flags as the navman is rx only so cannot echo.
*/
#include <linux/kernel.h>
@@ -49,15 +53,15 @@ static void navman_read_int_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
tty = port->tty;
@@ -72,29 +76,29 @@ exit:
if (result)
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
- __FUNCTION__, result);
+ __func__, result);
}
static int navman_open(struct usb_serial_port *port, struct file *filp)
{
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (port->interrupt_in_urb) {
- dbg("%s - adding interrupt input for treo", __FUNCTION__);
+ dbg("%s - adding interrupt input for treo", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed submitting interrupt urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
}
return result;
}
static void navman_close(struct usb_serial_port *port, struct file *filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -102,16 +106,12 @@ static void navman_close(struct usb_serial_port *port, struct file *filp)
static int navman_write(struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* This device can't write any data, only read from the device
- * so we just silently eat all data sent to us and say it was
- * successfully sent.
- * Evil, I know, but do you have a better idea?
*/
-
- return count;
+ return -EOPNOTSUPP;
}
static struct usb_serial_driver navman_device = {
@@ -121,9 +121,6 @@ static struct usb_serial_driver navman_device = {
},
.id_table = id_table,
.usb_driver = &navman_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.open = navman_open,
.close = navman_close,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index ee94d9616d82..7b7422f49478 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -95,9 +95,6 @@ static struct usb_serial_driver zyxel_omninet_device = {
.description = "ZyXEL - omni.net lcd plus usb",
.usb_driver = &omninet_driver,
.id_table = id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 2,
.num_ports = 1,
.attach = omninet_attach,
.open = omninet_open,
@@ -153,7 +150,7 @@ static int omninet_attach (struct usb_serial *serial)
od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
if( !od ) {
- err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
+ err("%s- kmalloc(%Zd) failed.", __func__, sizeof(struct omninet_data));
return -ENOMEM;
}
usb_set_serial_port_data(port, od);
@@ -166,7 +163,7 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial_port *wport;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
wport = serial->port[1];
wport->tty = port->tty;
@@ -178,7 +175,7 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
omninet_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting read urb, error %d", __func__, result);
}
return result;
@@ -186,7 +183,7 @@ static int omninet_open (struct usb_serial_port *port, struct file *filp)
static void omninet_close (struct usb_serial_port *port, struct file * filp)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->read_urb);
}
@@ -197,18 +194,18 @@ static void omninet_close (struct usb_serial_port *port, struct file * filp)
static void omninet_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
struct omninet_header *header = (struct omninet_header *) &data[0];
int status = urb->status;
int i;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -236,7 +233,7 @@ static void omninet_read_bulk_callback (struct urb *urb)
omninet_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed resubmitting read urb, error %d", __func__, result);
return;
}
@@ -251,17 +248,17 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return (0);
}
spin_lock_bh(&wport->lock);
if (wport->write_urb_busy) {
spin_unlock_bh(&wport->lock);
- dbg("%s - already writing", __FUNCTION__);
+ dbg("%s - already writing", __func__);
return 0;
}
wport->write_urb_busy = 1;
@@ -271,7 +268,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, wport->write_urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, wport->write_urb->transfer_buffer);
header->oh_seq = od->od_outseq++;
header->oh_len = count;
@@ -285,7 +282,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) {
wport->write_urb_busy = 0;
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
} else
result = count;
@@ -298,12 +295,13 @@ static int omninet_write_room (struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport = serial->port[1];
- int room = 0; // Default: no room
+ int room = 0; /* Default: no room */
+ /* FIXME: no consistent locking for write_urb_busy */
if (wport->write_urb_busy)
room = wport->bulk_out_size - OMNINET_HEADERLEN;
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return (room);
}
@@ -311,15 +309,15 @@ static int omninet_write_room (struct usb_serial_port *port)
static void omninet_write_bulk_callback (struct urb *urb)
{
/* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %0x\n", __FUNCTION__, port->number);
+ dbg("%s - port %0x\n", __func__, port->number);
port->write_urb_busy = 0;
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -331,7 +329,7 @@ static void omninet_shutdown (struct usb_serial *serial)
{
struct usb_serial_port *wport = serial->port[1];
struct usb_serial_port *port = serial->port[0];
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
usb_kill_urb(wport->write_urb);
kfree(usb_get_serial_port_data(port));
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index d101025a4c63..e4be2d442b1e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -28,7 +28,7 @@
device features.
*/
-#define DRIVER_VERSION "v0.7.1"
+#define DRIVER_VERSION "v0.7.2"
#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
#define DRIVER_DESC "USB Driver for GSM modems"
@@ -325,9 +325,6 @@ static struct usb_serial_driver option_1port_device = {
.description = "GSM modem (1-port)",
.usb_driver = &option_driver,
.id_table = option_ids,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.open = option_open,
.close = option_close,
@@ -411,24 +408,24 @@ module_exit(option_exit);
static void option_rx_throttle(struct usb_serial_port *port)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static void option_rx_unthrottle(struct usb_serial_port *port)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static void option_break_ctl(struct usb_serial_port *port, int break_state)
{
/* Unfortunately, I don't know how to send a break */
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static void option_set_termios(struct usb_serial_port *port,
struct ktermios *old_termios)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Doesn't support option setting */
tty_termios_copy_hw(port->tty->termios, old_termios);
option_send_setup(port);
@@ -458,6 +455,7 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file,
portdata = usb_get_serial_port_data(port);
+ /* FIXME: what locks portdata fields ? */
if (set & TIOCM_RTS)
portdata->rts_state = 1;
if (set & TIOCM_DTR)
@@ -488,7 +486,7 @@ static int option_write(struct usb_serial_port *port,
portdata = usb_get_serial_port_data(port);
- dbg("%s: write (%d chars)", __FUNCTION__, count);
+ dbg("%s: write (%d chars)", __func__, count);
i = 0;
left = count;
@@ -509,7 +507,7 @@ static int option_write(struct usb_serial_port *port,
dbg("usb_write %p failed (err=%d)",
this_urb, this_urb->status);
- dbg("%s: endpoint %d buf %d", __FUNCTION__,
+ dbg("%s: endpoint %d buf %d", __func__,
usb_pipeendpoint(this_urb->pipe), i);
/* send the data */
@@ -531,7 +529,7 @@ static int option_write(struct usb_serial_port *port,
}
count -= left;
- dbg("%s: wrote (did %d)", __FUNCTION__, count);
+ dbg("%s: wrote (did %d)", __func__, count);
return count;
}
@@ -544,14 +542,14 @@ static void option_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s: %p", __FUNCTION__, urb);
+ dbg("%s: %p", __func__, urb);
endpoint = usb_pipeendpoint(urb->pipe);
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
if (status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
- __FUNCTION__, status, endpoint);
+ __func__, status, endpoint);
} else {
tty = port->tty;
if (urb->actual_length) {
@@ -559,7 +557,7 @@ static void option_indat_callback(struct urb *urb)
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
} else {
- dbg("%s: empty read urb received", __FUNCTION__);
+ dbg("%s: empty read urb received", __func__);
}
/* Resubmit urb so we continue receiving */
@@ -567,7 +565,7 @@ static void option_indat_callback(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
printk(KERN_ERR "%s: resubmit read urb failed. "
- "(%d)", __FUNCTION__, err);
+ "(%d)", __func__, err);
}
}
return;
@@ -579,9 +577,9 @@ static void option_outdat_callback(struct urb *urb)
struct option_port_private *portdata;
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
usb_serial_port_softint(port);
@@ -599,19 +597,19 @@ static void option_instat_callback(struct urb *urb)
{
int err;
int status = urb->status;
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct option_port_private *portdata = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
- dbg("%s", __FUNCTION__);
- dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+ dbg("%s", __func__);
+ dbg("%s: urb %p port %p has data %p", __func__,urb,port,portdata);
if (status == 0) {
struct usb_ctrlrequest *req_pkt =
(struct usb_ctrlrequest *)urb->transfer_buffer;
if (!req_pkt) {
- dbg("%s: NULL req_pkt\n", __FUNCTION__);
+ dbg("%s: NULL req_pkt\n", __func__);
return;
}
if ((req_pkt->bRequestType == 0xA1) &&
@@ -621,7 +619,7 @@ static void option_instat_callback(struct urb *urb)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
- dbg("%s: signal x%x", __FUNCTION__, signals);
+ dbg("%s: signal x%x", __func__, signals);
old_dcd_state = portdata->dcd_state;
portdata->cts_state = 1;
@@ -633,11 +631,11 @@ static void option_instat_callback(struct urb *urb)
old_dcd_state && !portdata->dcd_state)
tty_hangup(port->tty);
} else {
- dbg("%s: type %x req %x", __FUNCTION__,
+ dbg("%s: type %x req %x", __func__,
req_pkt->bRequestType,req_pkt->bRequest);
}
} else
- dbg("%s: error %d", __FUNCTION__, status);
+ dbg("%s: error %d", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN) {
@@ -645,7 +643,7 @@ static void option_instat_callback(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dbg("%s: resubmit intr urb failed. (%d)",
- __FUNCTION__, err);
+ __func__, err);
}
}
@@ -658,13 +656,14 @@ static int option_write_room(struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
+
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
if (this_urb && !test_bit(i, &portdata->out_busy))
data_len += OUT_BUFLEN;
}
- dbg("%s: %d", __FUNCTION__, data_len);
+ dbg("%s: %d", __func__, data_len);
return data_len;
}
@@ -679,10 +678,12 @@ static int option_chars_in_buffer(struct usb_serial_port *port)
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
+ /* FIXME: This locking is insufficient as this_urb may
+ go unused during the test */
if (this_urb && test_bit(i, &portdata->out_busy))
data_len += this_urb->transfer_buffer_length;
}
- dbg("%s: %d", __FUNCTION__, data_len);
+ dbg("%s: %d", __func__, data_len);
return data_len;
}
@@ -695,7 +696,7 @@ static int option_open(struct usb_serial_port *port, struct file *filp)
portdata = usb_get_serial_port_data(port);
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Set some sane defaults */
portdata->rts_state = 1;
@@ -707,7 +708,7 @@ static int option_open(struct usb_serial_port *port, struct file *filp)
if (! urb)
continue;
if (urb->dev != serial->dev) {
- dbg("%s: dev %p != %p", __FUNCTION__,
+ dbg("%s: dev %p != %p", __func__,
urb->dev, serial->dev);
continue;
}
@@ -721,7 +722,7 @@ static int option_open(struct usb_serial_port *port, struct file *filp)
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
dbg("%s: submit urb %d failed (%d) %d",
- __FUNCTION__, i, err,
+ __func__, i, err,
urb->transfer_buffer_length);
}
}
@@ -749,7 +750,7 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
struct option_port_private *portdata;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
@@ -782,7 +783,7 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (urb == NULL) {
- dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
+ dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
return NULL;
}
@@ -801,7 +802,7 @@ static void option_setup_urbs(struct usb_serial *serial)
struct usb_serial_port *port;
struct option_port_private *portdata;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -823,15 +824,18 @@ static void option_setup_urbs(struct usb_serial *serial)
}
}
+
+/** send RTS/DTR state to the port.
+ *
+ * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN
+ * CDC.
+*/
static int option_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct option_port_private *portdata;
-
- dbg("%s", __FUNCTION__);
-
- if (port->number != 0)
- return 0;
+ int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+ dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
@@ -844,7 +848,7 @@ static int option_send_setup(struct usb_serial_port *port)
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
- 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ 0x22,0x21,val,ifNum,NULL,0,USB_CTRL_SET_TIMEOUT);
}
return 0;
@@ -857,7 +861,7 @@ static int option_startup(struct usb_serial *serial)
struct option_port_private *portdata;
u8 *buffer;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
@@ -865,7 +869,7 @@ static int option_startup(struct usb_serial *serial)
portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
if (!portdata) {
dbg("%s: kmalloc for option_port_private (%d) failed!.",
- __FUNCTION__, i);
+ __func__, i);
return (1);
}
@@ -890,7 +894,7 @@ static int option_startup(struct usb_serial *serial)
err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (err)
dbg("%s: submit irq_in urb failed %d",
- __FUNCTION__, err);
+ __func__, err);
}
option_setup_urbs(serial);
@@ -914,7 +918,7 @@ static void option_shutdown(struct usb_serial *serial)
struct usb_serial_port *port;
struct option_port_private *portdata;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Stop reading/writing urbs */
for (i = 0; i < serial->num_ports; ++i) {
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index a3847d6c946e..a9625c180dc3 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -98,7 +98,7 @@ struct oti6858_buf {
/* format of the control packet */
struct oti6858_control_pkt {
- u16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */
+ __le16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */
#define OTI6858_MAX_BAUD_RATE 3000000
u8 frame_fmt;
#define FMT_STOP_BITS_MASK 0xc0
@@ -179,9 +179,6 @@ static struct usb_serial_driver oti6858_device = {
.name = "oti6858",
},
.id_table = id_table,
- .num_interrupt_in = 1,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = oti6858_open,
.close = oti6858_close,
@@ -214,7 +211,7 @@ struct oti6858_private {
struct delayed_work delayed_write_work;
struct {
- u16 divisor;
+ __le16 divisor;
u8 frame_fmt;
u8 control;
} pending_setup;
@@ -238,10 +235,10 @@ static void setup_line(struct work_struct *work)
unsigned long flags;
int result;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
if ((new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) {
- dev_err(&port->dev, "%s(): out of memory!\n", __FUNCTION__);
+ dev_err(&port->dev, "%s(): out of memory!\n", __func__);
/* we will try again */
schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2));
return;
@@ -256,7 +253,7 @@ static void setup_line(struct work_struct *work)
100);
if (result != OTI6858_CTRL_PKT_SIZE) {
- dev_err(&port->dev, "%s(): error reading status\n", __FUNCTION__);
+ dev_err(&port->dev, "%s(): error reading status\n", __func__);
kfree(new_setup);
/* we will try again */
schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2));
@@ -289,12 +286,12 @@ static void setup_line(struct work_struct *work)
priv->setup_done = 1;
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ dbg("%s(): submitting interrupt urb", __func__);
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
- " with error %d\n", __FUNCTION__, result);
+ " with error %d\n", __func__, result);
}
}
@@ -306,7 +303,7 @@ void send_data(struct work_struct *work)
unsigned long flags;
unsigned char allow;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
if (priv->flags.write_urb_in_use) {
@@ -334,12 +331,12 @@ void send_data(struct work_struct *work)
if (count == 0) {
priv->flags.write_urb_in_use = 0;
- dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ dbg("%s(): submitting interrupt urb", __func__);
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
- " with error %d\n", __FUNCTION__, result);
+ " with error %d\n", __func__, result);
}
return;
}
@@ -353,7 +350,7 @@ void send_data(struct work_struct *work)
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
- " with error %d\n", __FUNCTION__, result);
+ " with error %d\n", __func__, result);
priv->flags.write_urb_in_use = 0;
}
@@ -404,7 +401,7 @@ static int oti6858_write(struct usb_serial_port *port,
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s(port = %d, count = %d)", __FUNCTION__, port->number, count);
+ dbg("%s(port = %d, count = %d)", __func__, port->number, count);
if (!count)
return count;
@@ -422,7 +419,7 @@ static int oti6858_write_room(struct usb_serial_port *port)
int room = 0;
unsigned long flags;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
room = oti6858_buf_space_avail(priv->buf);
@@ -437,7 +434,7 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port)
int chars = 0;
unsigned long flags;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
chars = oti6858_buf_data_avail(priv->buf);
@@ -453,13 +450,13 @@ static void oti6858_set_termios(struct usb_serial_port *port,
unsigned long flags;
unsigned int cflag;
u8 frame_fmt, control;
- u16 divisor;
+ __le16 divisor;
int br;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
if (!port->tty || !port->tty->termios) {
- dbg("%s(): no tty structures", __FUNCTION__);
+ dbg("%s(): no tty structures", __func__);
return;
}
@@ -508,11 +505,12 @@ static void oti6858_set_termios(struct usb_serial_port *port,
divisor = 0;
} else {
int real_br;
+ int new_divisor;
br = min(br, OTI6858_MAX_BAUD_RATE);
- divisor = (96000000 + 8 * br) / (16 * br);
- real_br = 96000000 / (16 * divisor);
- divisor = cpu_to_le16(divisor);
+ new_divisor = (96000000 + 8 * br) / (16 * br);
+ real_br = 96000000 / (16 * new_divisor);
+ divisor = cpu_to_le16(new_divisor);
tty_encode_baud_rate(port->tty, real_br, real_br);
}
@@ -575,7 +573,7 @@ static int oti6858_open(struct usb_serial_port *port, struct file *filp)
unsigned long flags;
int result;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -584,7 +582,7 @@ static int oti6858_open(struct usb_serial_port *port, struct file *filp)
return 0;
if ((buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) {
- dev_err(&port->dev, "%s(): out of memory!\n", __FUNCTION__);
+ dev_err(&port->dev, "%s(): out of memory!\n", __func__);
return -ENOMEM;
}
@@ -613,12 +611,12 @@ static int oti6858_open(struct usb_serial_port *port, struct file *filp)
spin_unlock_irqrestore(&priv->lock, flags);
kfree(buf);
- dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ dbg("%s(): submitting interrupt urb", __func__);
port->interrupt_in_urb->dev = serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
- " with error %d\n", __FUNCTION__, result);
+ " with error %d\n", __func__, result);
oti6858_close(port, NULL);
return -EPROTO;
}
@@ -637,14 +635,14 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
long timeout;
wait_queue_t wait;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
/* wait for data to drain from the buffer */
spin_lock_irqsave(&priv->lock, flags);
timeout = 30 * HZ; /* PL2303_CLOSING_WAIT */
init_waitqueue_entry(&wait, current);
add_wait_queue(&port->tty->write_wait, &wait);
- dbg("%s(): entering wait loop", __FUNCTION__);
+ dbg("%s(): entering wait loop", __func__);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (oti6858_buf_data_avail(priv->buf) == 0
@@ -657,7 +655,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->tty->write_wait, &wait);
- dbg("%s(): after wait loop", __FUNCTION__);
+ dbg("%s(): after wait loop", __func__);
/* clear out any remaining data in the buffer */
oti6858_buf_clear(priv->buf);
@@ -678,7 +676,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
*/
timeout = 2*HZ;
schedule_timeout_interruptible(timeout);
- dbg("%s(): after schedule_timeout_interruptible()", __FUNCTION__);
+ dbg("%s(): after schedule_timeout_interruptible()", __func__);
/* cancel scheduled setup */
cancel_delayed_work(&priv->delayed_setup_work);
@@ -686,7 +684,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
flush_scheduled_work();
/* shutdown our urbs */
- dbg("%s(): shutting down urbs", __FUNCTION__);
+ dbg("%s(): shutting down urbs", __func__);
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
@@ -709,7 +707,7 @@ static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file,
u8 control;
dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)",
- __FUNCTION__, port->number, set, clear);
+ __func__, port->number, set, clear);
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
@@ -741,7 +739,7 @@ static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file)
unsigned pin_state;
unsigned result = 0;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
@@ -764,7 +762,7 @@ static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file)
if ((pin_state & PIN_DCD) != 0)
result |= TIOCM_CD;
- dbg("%s() = 0x%08x", __FUNCTION__, result);
+ dbg("%s() = 0x%08x", __func__, result);
return result;
}
@@ -811,13 +809,9 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int x;
dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)",
- __FUNCTION__, port->number, cmd, arg);
+ __func__, port->number, cmd, arg);
switch (cmd) {
- case TCFLSH:
- /* FIXME */
- return 0;
-
case TIOCMBIS:
if (copy_from_user(&x, user_arg, sizeof(x)))
return -EFAULT;
@@ -829,11 +823,11 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
return oti6858_tiocmset(port, NULL, 0, x);
case TIOCMIWAIT:
- dbg("%s(): TIOCMIWAIT", __FUNCTION__);
+ dbg("%s(): TIOCMIWAIT", __func__);
return wait_modem_info(port, arg);
default:
- dbg("%s(): 0x%04x not supported", __FUNCTION__, cmd);
+ dbg("%s(): 0x%04x not supported", __func__, cmd);
break;
}
@@ -844,10 +838,10 @@ static void oti6858_break_ctl(struct usb_serial_port *port, int break_state)
{
int state;
- dbg("%s(port = %d)", __FUNCTION__, port->number);
+ dbg("%s(port = %d)", __func__, port->number);
state = (break_state == 0) ? 0 : 1;
- dbg("%s(): turning break %s", __FUNCTION__, state ? "on" : "off");
+ dbg("%s(): turning break %s", __func__, state ? "on" : "off");
/* FIXME */
/*
@@ -855,7 +849,7 @@ static void oti6858_break_ctl(struct usb_serial_port *port, int break_state)
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
if (result != 0)
- dbg("%s(): error sending break", __FUNCTION__);
+ dbg("%s(): error sending break", __func__);
*/
}
@@ -864,7 +858,7 @@ static void oti6858_shutdown(struct usb_serial *serial)
struct oti6858_private *priv;
int i;
- dbg("%s()", __FUNCTION__);
+ dbg("%s()", __func__);
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
@@ -878,13 +872,13 @@ static void oti6858_shutdown(struct usb_serial *serial)
static void oti6858_read_int_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct oti6858_private *priv = usb_get_serial_port_data(port);
int transient = 0, can_recv = 0, resubmit = 1;
int status = urb->status;
dbg("%s(port = %d, status = %d)",
- __FUNCTION__, port->number, status);
+ __func__, port->number, status);
switch (status) {
case 0:
@@ -895,11 +889,11 @@ static void oti6858_read_int_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s(): urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s(): nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
break;
}
@@ -916,7 +910,7 @@ static void oti6858_read_int_callback(struct urb *urb)
priv->setup_done = 0;
resubmit = 0;
dbg("%s(): scheduling setup_line()",
- __FUNCTION__);
+ __func__);
schedule_delayed_work(&priv->delayed_setup_work, 0);
}
}
@@ -931,7 +925,7 @@ static void oti6858_read_int_callback(struct urb *urb)
priv->setup_done = 0;
resubmit = 0;
dbg("%s(): scheduling setup_line()",
- __FUNCTION__);
+ __func__);
schedule_delayed_work(&priv->delayed_setup_work, 0);
}
}
@@ -960,7 +954,7 @@ static void oti6858_read_int_callback(struct urb *urb)
if (result != 0) {
priv->flags.read_urb_in_use = 0;
dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
} else {
resubmit = 0;
}
@@ -979,20 +973,20 @@ static void oti6858_read_int_callback(struct urb *urb)
if (resubmit) {
int result;
-// dbg("%s(): submitting interrupt urb", __FUNCTION__);
+// dbg("%s(): submitting interrupt urb", __func__);
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result != 0) {
dev_err(&urb->dev->dev,
"%s(): usb_submit_urb() failed with"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
}
}
}
static void oti6858_read_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct oti6858_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
@@ -1001,7 +995,7 @@ static void oti6858_read_bulk_callback(struct urb *urb)
int result;
dbg("%s(port = %d, status = %d)",
- __FUNCTION__, port->number, status);
+ __func__, port->number, status);
spin_lock_irqsave(&priv->lock, flags);
priv->flags.read_urb_in_use = 0;
@@ -1009,20 +1003,20 @@ static void oti6858_read_bulk_callback(struct urb *urb)
if (status != 0) {
if (!port->open_count) {
- dbg("%s(): port is closed, exiting", __FUNCTION__);
+ dbg("%s(): port is closed, exiting", __func__);
return;
}
/*
if (status == -EPROTO) {
// PL2303 mysteriously fails with -EPROTO reschedule the read
- dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
+ dbg("%s - caught -EPROTO, resubmitting the urb", __func__);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
return;
}
*/
- dbg("%s(): unable to handle the error, exiting", __FUNCTION__);
+ dbg("%s(): unable to handle the error, exiting", __func__);
return;
}
@@ -1038,20 +1032,20 @@ static void oti6858_read_bulk_callback(struct urb *urb)
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
}
}
}
static void oti6858_write_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct oti6858_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
int result;
dbg("%s(port = %d, status = %d)",
- __FUNCTION__, port->number, status);
+ __func__, port->number, status);
switch (status) {
case 0:
@@ -1062,21 +1056,21 @@ static void oti6858_write_bulk_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s(): urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
priv->flags.write_urb_in_use = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
dbg("%s(): nonzero write bulk status received: %d",
- __FUNCTION__, status);
- dbg("%s(): overflow in write", __FUNCTION__);
+ __func__, status);
+ dbg("%s(): overflow in write", __func__);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
} else {
return;
}
@@ -1086,11 +1080,11 @@ static void oti6858_write_bulk_callback(struct urb *urb)
// schedule the interrupt urb if we are still open */
port->interrupt_in_urb->dev = port->serial->dev;
- dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ dbg("%s(): submitting interrupt urb", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result != 0) {
dev_err(&port->dev, "%s(): failed submitting int urb,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
}
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 2af778555bdc..c605fb68f807 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -410,7 +410,7 @@ static int set_control_lines(struct usb_device *dev, u8 value)
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
- dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
+ dbg("%s - value = %d, retval = %d", __func__, value, retval);
return retval;
}
@@ -420,7 +420,7 @@ static void pl2303_send(struct usb_serial_port *port)
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
@@ -441,7 +441,7 @@ static void pl2303_send(struct usb_serial_port *port)
spin_unlock_irqrestore(&priv->lock, flags);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
+ usb_serial_debug_data(debug, &port->dev, __func__, count,
port->write_urb->transfer_buffer);
port->write_urb->transfer_buffer_length = count;
@@ -449,7 +449,7 @@ static void pl2303_send(struct usb_serial_port *port)
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev, "%s - failed submitting write urb,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
priv->write_urb_in_use = 0;
// TODO: reschedule pl2303_send
}
@@ -463,7 +463,7 @@ static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+ dbg("%s - port %d, %d bytes", __func__, port->number, count);
if (!count)
return count;
@@ -483,13 +483,13 @@ static int pl2303_write_room(struct usb_serial_port *port)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
room = pl2303_buf_space_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -499,13 +499,13 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
chars = pl2303_buf_data_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return chars;
}
@@ -521,7 +521,7 @@ static void pl2303_set_termios(struct usb_serial_port *port,
int i;
u8 control;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
@@ -545,7 +545,9 @@ static void pl2303_set_termios(struct usb_serial_port *port,
buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
- dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - out of memory.\n", __func__);
+ /* Report back no change occurred */
+ *port->tty->termios = *old_termios;
return;
}
@@ -563,11 +565,11 @@ static void pl2303_set_termios(struct usb_serial_port *port,
default:
case CS8: buf[6] = 8; break;
}
- dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
+ dbg("%s - data bits = %d", __func__, buf[6]);
}
baud = tty_get_baud_rate(port->tty);;
- dbg("%s - baud = %d", __FUNCTION__, baud);
+ dbg("%s - baud = %d", __func__, baud);
if (baud) {
buf[0] = baud & 0xff;
buf[1] = (baud >> 8) & 0xff;
@@ -580,10 +582,10 @@ static void pl2303_set_termios(struct usb_serial_port *port,
/* For reference buf[4]=2 is 2 stop bits */
if (cflag & CSTOPB) {
buf[4] = 2;
- dbg("%s - stop bits = 2", __FUNCTION__);
+ dbg("%s - stop bits = 2", __func__);
} else {
buf[4] = 0;
- dbg("%s - stop bits = 1", __FUNCTION__);
+ dbg("%s - stop bits = 1", __func__);
}
if (cflag & PARENB) {
@@ -594,14 +596,14 @@ static void pl2303_set_termios(struct usb_serial_port *port,
/* For reference buf[5]=4 is space parity */
if (cflag & PARODD) {
buf[5] = 1;
- dbg("%s - parity = odd", __FUNCTION__);
+ dbg("%s - parity = odd", __func__);
} else {
buf[5] = 2;
- dbg("%s - parity = even", __FUNCTION__);
+ dbg("%s - parity = even", __func__);
}
} else {
buf[5] = 0;
- dbg("%s - parity = none", __FUNCTION__);
+ dbg("%s - parity = none", __func__);
}
i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -657,7 +659,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp)
long timeout;
wait_queue_t wait;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from the buffer */
spin_lock_irqsave(&priv->lock, flags);
@@ -695,7 +697,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp)
schedule_timeout_interruptible(timeout);
/* shutdown our urbs */
- dbg("%s - shutting down urbs", __FUNCTION__);
+ dbg("%s - shutting down urbs", __func__);
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
@@ -719,7 +721,7 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
struct pl2303_private *priv = usb_get_serial_port_data(port);
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (priv->type != HX) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
@@ -737,22 +739,22 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
//FIXME: need to assert RTS and DTR if CRTSCTS off
- dbg("%s - submitting read urb", __FUNCTION__);
+ dbg("%s - submitting read urb", __func__);
port->read_urb->dev = serial->dev;
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
pl2303_close(port, NULL);
return -EPROTO;
}
- dbg("%s - submitting interrupt urb", __FUNCTION__);
+ dbg("%s - submitting interrupt urb", __func__);
port->interrupt_in_urb->dev = serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
- " error %d\n", __FUNCTION__, result);
+ " error %d\n", __func__, result);
pl2303_close(port, NULL);
return -EPROTO;
}
@@ -792,7 +794,7 @@ static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
unsigned int status;
unsigned int result;
- dbg("%s (%d)", __FUNCTION__, port->number);
+ dbg("%s (%d)", __func__, port->number);
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
@@ -809,7 +811,7 @@ static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
| ((status & UART_RING) ? TIOCM_RI : 0)
| ((status & UART_DCD) ? TIOCM_CD : 0);
- dbg("%s - result = %x", __FUNCTION__, result);
+ dbg("%s - result = %x", __func__, result);
return result;
}
@@ -853,15 +855,15 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
- dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
+ dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
switch (cmd) {
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
return wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
+ dbg("%s not supported = 0x%04x", __func__, cmd);
break;
}
@@ -874,19 +876,19 @@ static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
u16 state;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (break_state == 0)
state = BREAK_OFF;
else
state = BREAK_ON;
- dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
+ dbg("%s - turning break %s", __func__, state==BREAK_OFF ? "off" : "on");
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
if (result)
- dbg("%s - error sending break = %d", __FUNCTION__, result);
+ dbg("%s - error sending break = %d", __func__, result);
}
static void pl2303_shutdown(struct usb_serial *serial)
@@ -894,7 +896,7 @@ static void pl2303_shutdown(struct usb_serial *serial)
int i;
struct pl2303_private *priv;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
@@ -943,13 +945,13 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
static void pl2303_read_int_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
unsigned int actual_length = urb->actual_length;
int status = urb->status;
int retval;
- dbg("%s (%d)", __FUNCTION__, port->number);
+ dbg("%s (%d)", __func__, port->number);
switch (status) {
case 0:
@@ -959,16 +961,16 @@ static void pl2303_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ dbg("%s - urb shutting down with status: %d", __func__,
status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ dbg("%s - nonzero urb status received: %d", __func__,
status);
goto exit;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, urb->transfer_buffer);
pl2303_update_line_status(port, data, actual_length);
@@ -978,12 +980,12 @@ exit:
if (retval)
dev_err(&urb->dev->dev,
"%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
static void pl2303_read_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
@@ -994,32 +996,32 @@ static void pl2303_read_bulk_callback(struct urb *urb)
u8 line_status;
char tty_flag;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
- dbg("%s - urb status = %d", __FUNCTION__, status);
+ dbg("%s - urb status = %d", __func__, status);
if (!port->open_count) {
- dbg("%s - port is closed, exiting.", __FUNCTION__);
+ dbg("%s - port is closed, exiting.", __func__);
return;
}
if (status == -EPROTO) {
/* PL2303 mysteriously fails with -EPROTO reschedule
* the read */
dbg("%s - caught -EPROTO, resubmitting the urb",
- __FUNCTION__);
+ __func__);
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed"
" resubmitting read urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
return;
}
- dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
+ dbg("%s - unable to handle the error, exiting.", __func__);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
/* get tty_flag from status */
@@ -1039,7 +1041,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
+ dbg("%s - tty_flag = %d", __func__, tty_flag);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -1058,7 +1060,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting"
- " read urb, error %d\n", __FUNCTION__, result);
+ " read urb, error %d\n", __func__, result);
}
return;
@@ -1066,12 +1068,12 @@ static void pl2303_read_bulk_callback(struct urb *urb)
static void pl2303_write_bulk_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
int result;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
switch (status) {
case 0:
@@ -1081,21 +1083,21 @@ static void pl2303_write_bulk_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ dbg("%s - urb shutting down with status: %d", __func__,
status);
priv->write_urb_in_use = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __FUNCTION__);
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
+ dbg("%s - Overflow in write", __func__);
+ dbg("%s - nonzero write bulk status received: %d", __func__,
status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting write"
- " urb, error %d\n", __FUNCTION__, result);
+ " urb, error %d\n", __func__, result);
else
return;
}
@@ -1114,9 +1116,6 @@ static struct usb_serial_driver pl2303_device = {
},
.id_table = id_table,
.usb_driver = &pl2303_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = pl2303_open,
.close = pl2303_close,
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 4e6dcc199be9..94bddf06ea4f 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -195,18 +195,17 @@ static __u16 __inline__ fcs_compute10 (unsigned char *sp, int len, __u16 fcs)
static void safe_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
unsigned char length = urb->actual_length;
- int i;
int result;
int status = urb->status;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -227,28 +226,20 @@ static void safe_read_bulk_callback (struct urb *urb)
if (safe) {
__u16 fcs;
if (!(fcs = fcs_compute10 (data, length, CRC10_INITFCS))) {
-
int actual_length = data[length - 2] >> 2;
-
if (actual_length <= (length - 2)) {
-
- info ("%s - actual: %d", __FUNCTION__, actual_length);
-
- for (i = 0; i < actual_length; i++) {
- tty_insert_flip_char (port->tty, data[i], 0);
- }
+ info ("%s - actual: %d", __func__, actual_length);
+ tty_insert_flip_string(port->tty, data, actual_length);
tty_flip_buffer_push (port->tty);
} else {
- err ("%s - inconsistent lengths %d:%d", __FUNCTION__,
+ err ("%s - inconsistent lengths %d:%d", __func__,
actual_length, length);
}
} else {
- err ("%s - bad CRC %x", __FUNCTION__, fcs);
+ err ("%s - bad CRC %x", __func__, fcs);
}
} else {
- for (i = 0; i < length; i++) {
- tty_insert_flip_char (port->tty, data[i], 0);
- }
+ tty_insert_flip_string(port->tty, data, length);
tty_flip_buffer_push (port->tty);
}
@@ -259,7 +250,8 @@ static void safe_read_bulk_callback (struct urb *urb)
safe_read_bulk_callback, port);
if ((result = usb_submit_urb (urb, GFP_ATOMIC))) {
- err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ err ("%s - failed resubmitting read urb, error %d", __func__, result);
+ /* FIXME: Need a mechanism to retry later if this happens */
}
}
@@ -274,25 +266,25 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
count);
if (!port->write_urb) {
- dbg ("%s - write urb NULL", __FUNCTION__);
- return (0);
+ dbg ("%s - write urb NULL", __func__);
+ return 0;
}
dbg ("safe_write write_urb: %d transfer_buffer_length",
port->write_urb->transfer_buffer_length);
if (!port->write_urb->transfer_buffer_length) {
- dbg ("%s - write urb transfer_buffer_length zero", __FUNCTION__);
- return (0);
+ dbg ("%s - write urb transfer_buffer_length zero", __func__);
+ return 0;
}
if (count == 0) {
- dbg ("%s - write request of 0 bytes", __FUNCTION__);
- return (0);
+ dbg ("%s - write request of 0 bytes", __func__);
+ return 0;
}
spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
spin_unlock_bh(&port->lock);
- dbg("%s - already writing", __FUNCTION__);
+ dbg("%s - already writing", __func__);
return 0;
}
port->write_urb_busy = 1;
@@ -332,7 +324,7 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
port->write_urb->transfer_buffer_length = count;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, port->write_urb->transfer_buffer);
#ifdef ECHO_TX
{
int i;
@@ -349,28 +341,31 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
port->write_urb->dev = port->serial->dev;
if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
port->write_urb_busy = 0;
- err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err ("%s - failed submitting write urb, error %d", __func__, result);
return 0;
}
- dbg ("%s urb: %p submitted", __FUNCTION__, port->write_urb);
+ dbg ("%s urb: %p submitted", __func__, port->write_urb);
return (count);
}
static int safe_write_room (struct usb_serial_port *port)
{
- int room = 0; // Default: no room
+ int room = 0; /* Default: no room */
+ unsigned long flags;
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
+ spin_lock_irqsave(&port->lock, flags);
if (port->write_urb_busy)
room = port->bulk_out_size - (safe ? 2 : 0);
+ spin_unlock_irqrestore(&port->lock, flags);
if (room) {
dbg ("safe_write_room returns %d", room);
}
- return (room);
+ return room;
}
static int safe_startup (struct usb_serial *serial)
@@ -394,9 +389,6 @@ static struct usb_serial_driver safe_device = {
},
.id_table = id_table,
.usb_driver = &safe_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.write = safe_write,
.write_room = safe_write_room,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index ed678811e6a6..29074c1ba22b 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
/*
USB Driver for Sierra Wireless
- Copyright (C) 2006, 2007, 2008 Kevin Lloyd <linux@sierrawireless.com>
+ Copyright (C) 2006, 2007, 2008 Kevin Lloyd <klloyd@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
@@ -14,8 +14,8 @@
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
*/
-#define DRIVER_VERSION "v.1.2.8"
-#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
+#define DRIVER_VERSION "v.1.2.9c"
+#define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
#include <linux/kernel.h>
@@ -31,7 +31,6 @@
#define SWIMS_USB_REQUEST_SetPower 0x00
#define SWIMS_USB_REQUEST_SetNmea 0x07
#define SWIMS_USB_REQUEST_SetMode 0x0B
-#define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40
#define SWIMS_SET_MODE_Modem 0x0001
/* per port private data */
@@ -55,7 +54,7 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetPower, /* __u8 request */
- SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ USB_TYPE_VENDOR, /* __u8 request type */
swiState, /* __u16 value */
0, /* __u16 index */
NULL, /* void *data */
@@ -70,7 +69,7 @@ static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetMode, /* __u8 request */
- SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ USB_TYPE_VENDOR, /* __u8 request type */
eSWocMode, /* __u16 value */
0x0000, /* __u16 index */
NULL, /* void *data */
@@ -85,7 +84,7 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
- SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ USB_TYPE_VENDOR, /* __u8 request type */
enable, /* __u16 value */
0x0000, /* __u16 index */
NULL, /* void *data */
@@ -109,6 +108,26 @@ static int sierra_calc_num_ports(struct usb_serial *serial)
return result;
}
+static int sierra_calc_interface(struct usb_serial *serial)
+{
+ int interface;
+ struct usb_interface *p_interface;
+ struct usb_host_interface *p_host_interface;
+
+ /* Get the interface structure pointer from the serial struct */
+ p_interface = serial->interface;
+
+ /* Get a pointer to the host interface structure */
+ p_host_interface = p_interface->cur_altsetting;
+
+ /* read the interface descriptor for this active altsetting
+ * to find out the interface number we are on
+ */
+ interface = p_host_interface->desc.bInterfaceNumber;
+
+ return interface;
+}
+
static int sierra_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
@@ -124,6 +143,22 @@ static int sierra_probe(struct usb_serial *serial,
ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
udev = serial->dev;
+ /* Figure out the interface number from the serial structure */
+ ifnum = sierra_calc_interface(serial);
+
+ /*
+ * If this interface supports more than 1 alternate
+ * select the 2nd one
+ */
+ if (serial->interface->num_altsetting == 2) {
+ dev_dbg(&udev->dev,
+ "Selecting alt setting for interface %d\n",
+ ifnum);
+
+ /* We know the alternate setting is 1 for the MC8785 */
+ usb_set_interface(udev, ifnum, 1);
+ }
+
/* Check if in installer mode */
if (truinstall && id->driver_info == DEVICE_INSTALLER) {
dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n");
@@ -156,7 +191,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
- { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) }, /* Sierra Wireless C597 */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
@@ -164,15 +199,20 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */
{ USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x03f0, 0x1e1d) }, /* HP hs2300 a.k.a MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */
{ USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
{ USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x683B), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless MC8785 Composite*/
{ USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
{ USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
{ USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
{ USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
{ USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */
{ USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
+ { USB_DEVICE(0x1199, 0x6859), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 885 E */
+ { USB_DEVICE(0x1199, 0x685A), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 885 E */
{ USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */
{ USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */
@@ -216,7 +256,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
struct sierra_port_private *portdata;
__u16 interface = 0;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
@@ -246,24 +286,24 @@ static int sierra_send_setup(struct usb_serial_port *port)
static void sierra_rx_throttle(struct usb_serial_port *port)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static void sierra_rx_unthrottle(struct usb_serial_port *port)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
{
/* Unfortunately, I don't know how to send a break */
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
}
static void sierra_set_termios(struct usb_serial_port *port,
struct ktermios *old_termios)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
tty_termios_copy_hw(port->tty->termios, old_termios);
sierra_send_setup(port);
}
@@ -317,14 +357,14 @@ static void sierra_outdat_callback(struct urb *urb)
int status = urb->status;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree(urb->transfer_buffer);
if (status)
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
spin_lock_irqsave(&portdata->lock, flags);
--portdata->outstanding_urbs;
@@ -346,12 +386,12 @@ static int sierra_write(struct usb_serial_port *port,
portdata = usb_get_serial_port_data(port);
- dbg("%s: write (%d chars)", __FUNCTION__, count);
+ dbg("%s: write (%d chars)", __func__, count);
spin_lock_irqsave(&portdata->lock, flags);
if (portdata->outstanding_urbs > N_OUT_URB) {
spin_unlock_irqrestore(&portdata->lock, flags);
- dbg("%s - write limit hit\n", __FUNCTION__);
+ dbg("%s - write limit hit\n", __func__);
return 0;
}
portdata->outstanding_urbs++;
@@ -373,7 +413,7 @@ static int sierra_write(struct usb_serial_port *port,
memcpy(buffer, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev,
@@ -384,7 +424,7 @@ static int sierra_write(struct usb_serial_port *port,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
- "with status = %d\n", __FUNCTION__, status);
+ "with status = %d\n", __func__, status);
count = status;
goto error;
}
@@ -414,14 +454,14 @@ static void sierra_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s: %p", __FUNCTION__, urb);
+ dbg("%s: %p", __func__, urb);
endpoint = usb_pipeendpoint(urb->pipe);
- port = (struct usb_serial_port *) urb->context;
+ port = urb->context;
if (status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
- __FUNCTION__, status, endpoint);
+ __func__, status, endpoint);
} else {
tty = port->tty;
if (urb->actual_length) {
@@ -429,7 +469,7 @@ static void sierra_indat_callback(struct urb *urb)
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
} else {
- dbg("%s: empty read urb received", __FUNCTION__);
+ dbg("%s: empty read urb received", __func__);
}
/* Resubmit urb so we continue receiving */
@@ -447,19 +487,19 @@ static void sierra_instat_callback(struct urb *urb)
{
int err;
int status = urb->status;
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
- dbg("%s", __FUNCTION__);
- dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+ dbg("%s", __func__);
+ dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
if (status == 0) {
struct usb_ctrlrequest *req_pkt =
(struct usb_ctrlrequest *)urb->transfer_buffer;
if (!req_pkt) {
- dbg("%s: NULL req_pkt\n", __FUNCTION__);
+ dbg("%s: NULL req_pkt\n", __func__);
return;
}
if ((req_pkt->bRequestType == 0xA1) &&
@@ -469,7 +509,7 @@ static void sierra_instat_callback(struct urb *urb)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
- dbg("%s: signal x%x", __FUNCTION__, signals);
+ dbg("%s: signal x%x", __func__, signals);
old_dcd_state = portdata->dcd_state;
portdata->cts_state = 1;
@@ -481,11 +521,11 @@ static void sierra_instat_callback(struct urb *urb)
old_dcd_state && !portdata->dcd_state)
tty_hangup(port->tty);
} else {
- dbg("%s: type %x req %x", __FUNCTION__,
- req_pkt->bRequestType,req_pkt->bRequest);
+ dbg("%s: type %x req %x", __func__,
+ req_pkt->bRequestType, req_pkt->bRequest);
}
} else
- dbg("%s: error %d", __FUNCTION__, status);
+ dbg("%s: error %d", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN) {
@@ -493,7 +533,7 @@ static void sierra_instat_callback(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dbg("%s: resubmit intr urb failed. (%d)",
- __FUNCTION__, err);
+ __func__, err);
}
}
@@ -502,14 +542,14 @@ static int sierra_write_room(struct usb_serial_port *port)
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* try to give a good number back based on if we have any free urbs at
* this point in time */
spin_lock_irqsave(&portdata->lock, flags);
if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) {
spin_unlock_irqrestore(&portdata->lock, flags);
- dbg("%s - write limit hit\n", __FUNCTION__);
+ dbg("%s - write limit hit\n", __func__);
return 0;
}
spin_unlock_irqrestore(&portdata->lock, flags);
@@ -519,13 +559,15 @@ static int sierra_write_room(struct usb_serial_port *port)
static int sierra_chars_in_buffer(struct usb_serial_port *port)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* We can't really account for how much data we
* have sent out, but hasn't made it through to the
* device as we can't see the backend here, so just
* tell the tty layer that everything is flushed.
+ *
+ * FIXME: should walk the outstanding urbs info
*/
return 0;
}
@@ -540,7 +582,7 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
portdata = usb_get_serial_port_data(port);
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Set some sane defaults */
portdata->rts_state = 1;
@@ -552,7 +594,7 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
if (!urb)
continue;
if (urb->dev != serial->dev) {
- dbg("%s: dev %p != %p", __FUNCTION__,
+ dbg("%s: dev %p != %p", __func__,
urb->dev, serial->dev);
continue;
}
@@ -590,7 +632,7 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
@@ -620,7 +662,7 @@ static int sierra_startup(struct usb_serial *serial)
int i;
int j;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* Set Device mode to D0 */
sierra_set_power_state(serial->dev, 0x0000);
@@ -635,7 +677,7 @@ static int sierra_startup(struct usb_serial *serial)
portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
if (!portdata) {
dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
- __FUNCTION__, i);
+ __func__, i);
return -ENOMEM;
}
spin_lock_init(&portdata->lock);
@@ -656,7 +698,7 @@ static int sierra_startup(struct usb_serial *serial)
urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL) {
dbg("%s: alloc for in port failed.",
- __FUNCTION__);
+ __func__);
continue;
}
/* Fill URB using supplied data. */
@@ -678,7 +720,7 @@ static void sierra_shutdown(struct usb_serial *serial)
struct usb_serial_port *port;
struct sierra_port_private *portdata;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -706,9 +748,6 @@ static struct usb_serial_driver sierra_device = {
.description = "Sierra USB modem",
.id_table = id_table,
.usb_driver = &sierra_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.calc_num_ports = sierra_calc_num_ports,
.probe = sierra_probe,
.open = sierra_open,
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
new file mode 100644
index 000000000000..55b2570b8b8b
--- /dev/null
+++ b/drivers/usb/serial/spcp8x5.c
@@ -0,0 +1,1073 @@
+/*
+ * spcp8x5 USB to serial adaptor driver
+ *
+ * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
+ * Copyright (C) 2006 S1 Corp.
+ *
+ * Original driver for 2.6.10 pl2303 driver by
+ * Greg Kroah-Hartman (greg@kroah.com)
+ * Changes for 2.6.20 by Harald Klein <hari@vt100.at>
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.04"
+#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
+
+static int debug;
+
+#define SPCP8x5_007_VID 0x04FC
+#define SPCP8x5_007_PID 0x0201
+#define SPCP8x5_008_VID 0x04fc
+#define SPCP8x5_008_PID 0x0235
+#define SPCP8x5_PHILIPS_VID 0x0471
+#define SPCP8x5_PHILIPS_PID 0x081e
+#define SPCP8x5_INTERMATIC_VID 0x04FC
+#define SPCP8x5_INTERMATIC_PID 0x0204
+#define SPCP8x5_835_VID 0x04fc
+#define SPCP8x5_835_PID 0x0231
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)},
+ { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
+ { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
+ { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
+ { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)},
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct spcp8x5_usb_ctrl_arg {
+ u8 type;
+ u8 cmd;
+ u8 cmd_type;
+ u16 value;
+ u16 index;
+ u16 length;
+};
+
+/* wait 30s before close */
+#define SPCP8x5_CLOSING_WAIT (30*HZ)
+
+#define SPCP8x5_BUF_SIZE 1024
+
+
+/* spcp8x5 spec register define */
+#define MCR_CONTROL_LINE_RTS 0x02
+#define MCR_CONTROL_LINE_DTR 0x01
+#define MCR_DTR 0x01
+#define MCR_RTS 0x02
+
+#define MSR_STATUS_LINE_DCD 0x80
+#define MSR_STATUS_LINE_RI 0x40
+#define MSR_STATUS_LINE_DSR 0x20
+#define MSR_STATUS_LINE_CTS 0x10
+
+/* verdor command here , we should define myself */
+#define SET_DEFAULT 0x40
+#define SET_DEFAULT_TYPE 0x20
+
+#define SET_UART_FORMAT 0x40
+#define SET_UART_FORMAT_TYPE 0x21
+#define SET_UART_FORMAT_SIZE_5 0x00
+#define SET_UART_FORMAT_SIZE_6 0x01
+#define SET_UART_FORMAT_SIZE_7 0x02
+#define SET_UART_FORMAT_SIZE_8 0x03
+#define SET_UART_FORMAT_STOP_1 0x00
+#define SET_UART_FORMAT_STOP_2 0x04
+#define SET_UART_FORMAT_PAR_NONE 0x00
+#define SET_UART_FORMAT_PAR_ODD 0x10
+#define SET_UART_FORMAT_PAR_EVEN 0x30
+#define SET_UART_FORMAT_PAR_MASK 0xD0
+#define SET_UART_FORMAT_PAR_SPACE 0x90
+
+#define GET_UART_STATUS_TYPE 0xc0
+#define GET_UART_STATUS 0x22
+#define GET_UART_STATUS_MSR 0x06
+
+#define SET_UART_STATUS 0x40
+#define SET_UART_STATUS_TYPE 0x23
+#define SET_UART_STATUS_MCR 0x0004
+#define SET_UART_STATUS_MCR_DTR 0x01
+#define SET_UART_STATUS_MCR_RTS 0x02
+#define SET_UART_STATUS_MCR_LOOP 0x10
+
+#define SET_WORKING_MODE 0x40
+#define SET_WORKING_MODE_TYPE 0x24
+#define SET_WORKING_MODE_U2C 0x00
+#define SET_WORKING_MODE_RS485 0x01
+#define SET_WORKING_MODE_PDMA 0x02
+#define SET_WORKING_MODE_SPP 0x03
+
+#define SET_FLOWCTL_CHAR 0x40
+#define SET_FLOWCTL_CHAR_TYPE 0x25
+
+#define GET_VERSION 0xc0
+#define GET_VERSION_TYPE 0x26
+
+#define SET_REGISTER 0x40
+#define SET_REGISTER_TYPE 0x27
+
+#define GET_REGISTER 0xc0
+#define GET_REGISTER_TYPE 0x28
+
+#define SET_RAM 0x40
+#define SET_RAM_TYPE 0x31
+
+#define GET_RAM 0xc0
+#define GET_RAM_TYPE 0x32
+
+/* how come ??? */
+#define UART_STATE 0x08
+#define UART_STATE_TRANSIENT_MASK 0x74
+#define UART_DCD 0x01
+#define UART_DSR 0x02
+#define UART_BREAK_ERROR 0x04
+#define UART_RING 0x08
+#define UART_FRAME_ERROR 0x10
+#define UART_PARITY_ERROR 0x20
+#define UART_OVERRUN_ERROR 0x40
+#define UART_CTS 0x80
+
+enum spcp8x5_type {
+ SPCP825_007_TYPE,
+ SPCP825_008_TYPE,
+ SPCP825_PHILIP_TYPE,
+ SPCP825_INTERMATIC_TYPE,
+ SPCP835_TYPE,
+};
+
+/* 1st in 1st out buffer 4 driver */
+struct ringbuf {
+ unsigned int buf_size;
+ char *buf_buf;
+ char *buf_get;
+ char *buf_put;
+};
+
+/* alloc the ring buf and alloc the buffer itself */
+static inline struct ringbuf *alloc_ringbuf(unsigned int size)
+{
+ struct ringbuf *pb;
+
+ if (size == 0)
+ return NULL;
+
+ pb = kmalloc(sizeof(*pb), GFP_KERNEL);
+ if (pb == NULL)
+ return NULL;
+
+ pb->buf_buf = kmalloc(size, GFP_KERNEL);
+ if (pb->buf_buf == NULL) {
+ kfree(pb);
+ return NULL;
+ }
+
+ pb->buf_size = size;
+ pb->buf_get = pb->buf_put = pb->buf_buf;
+
+ return pb;
+}
+
+/* free the ring buf and the buffer itself */
+static inline void free_ringbuf(struct ringbuf *pb)
+{
+ if (pb != NULL) {
+ kfree(pb->buf_buf);
+ kfree(pb);
+ }
+}
+
+/* clear pipo , juest repoint the pointer here */
+static inline void clear_ringbuf(struct ringbuf *pb)
+{
+ if (pb != NULL)
+ pb->buf_get = pb->buf_put;
+}
+
+/* get the number of data in the pipo */
+static inline unsigned int ringbuf_avail_data(struct ringbuf *pb)
+{
+ if (pb == NULL)
+ return 0;
+ return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
+}
+
+/* get the number of space in the pipo */
+static inline unsigned int ringbuf_avail_space(struct ringbuf *pb)
+{
+ if (pb == NULL)
+ return 0;
+ return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
+}
+
+/* put count data into pipo */
+static unsigned int put_ringbuf(struct ringbuf *pb, const char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = ringbuf_avail_space(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_put;
+ if (count > len) {
+ memcpy(pb->buf_put, buf, len);
+ memcpy(pb->buf_buf, buf+len, count - len);
+ pb->buf_put = pb->buf_buf + count - len;
+ } else {
+ memcpy(pb->buf_put, buf, count);
+ if (count < len)
+ pb->buf_put += count;
+ else /* count == len */
+ pb->buf_put = pb->buf_buf;
+ }
+ return count;
+}
+
+/* get count data from pipo */
+static unsigned int get_ringbuf(struct ringbuf *pb, char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL || buf == NULL)
+ return 0;
+
+ len = ringbuf_avail_data(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_get;
+ if (count > len) {
+ memcpy(buf, pb->buf_get, len);
+ memcpy(buf+len, pb->buf_buf, count - len);
+ pb->buf_get = pb->buf_buf + count - len;
+ } else {
+ memcpy(buf, pb->buf_get, count);
+ if (count < len)
+ pb->buf_get += count;
+ else /* count == len */
+ pb->buf_get = pb->buf_buf;
+ }
+
+ return count;
+}
+
+static struct usb_driver spcp8x5_driver = {
+ .name = "spcp8x5",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+
+struct spcp8x5_private {
+ spinlock_t lock;
+ struct ringbuf *buf;
+ int write_urb_in_use;
+ enum spcp8x5_type type;
+ wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+ u8 termios_initialized;
+};
+
+/* desc : when device plug in,this function would be called.
+ * thanks to usb_serial subsystem,then do almost every things for us. And what
+ * we should do just alloc the buffer */
+static int spcp8x5_startup(struct usb_serial *serial)
+{
+ struct spcp8x5_private *priv;
+ int i;
+ enum spcp8x5_type type = SPCP825_007_TYPE;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+
+ if (product == 0x0201)
+ type = SPCP825_007_TYPE;
+ else if (product == 0x0231)
+ type = SPCP835_TYPE;
+ else if (product == 0x0235)
+ type = SPCP825_008_TYPE;
+ else if (product == 0x0204)
+ type = SPCP825_INTERMATIC_TYPE;
+ else if (product == 0x0471 &&
+ serial->dev->descriptor.idVendor == cpu_to_le16(0x081e))
+ type = SPCP825_PHILIP_TYPE;
+ dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ priv = kzalloc(sizeof(struct spcp8x5_private), GFP_KERNEL);
+ if (!priv)
+ goto cleanup;
+
+ spin_lock_init(&priv->lock);
+ priv->buf = alloc_ringbuf(SPCP8x5_BUF_SIZE);
+ if (priv->buf == NULL)
+ goto cleanup2;
+
+ init_waitqueue_head(&priv->delta_msr_wait);
+ priv->type = type;
+ usb_set_serial_port_data(serial->port[i] , priv);
+
+ }
+
+ return 0;
+
+cleanup2:
+ kfree(priv);
+cleanup:
+ for (--i; i >= 0; --i) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ free_ringbuf(priv->buf);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i] , NULL);
+ }
+ return -ENOMEM;
+}
+
+/* call when the device plug out. free all the memory alloced by probe */
+static void spcp8x5_shutdown(struct usb_serial *serial)
+{
+ int i;
+ struct spcp8x5_private *priv;
+
+ for (i = 0; i < serial->num_ports; i++) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ if (priv) {
+ free_ringbuf(priv->buf);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i] , NULL);
+ }
+ }
+}
+
+/* set the modem control line of the device.
+ * NOTE spcp825-007 not supported this */
+static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value,
+ enum spcp8x5_type type)
+{
+ int retval;
+ u8 mcr = 0 ;
+
+ if (type == SPCP825_007_TYPE)
+ return -EPERM;
+
+ mcr = (unsigned short)value;
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ SET_UART_STATUS_TYPE, SET_UART_STATUS,
+ mcr, 0x04, NULL, 0, 100);
+ if (retval != 0)
+ dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval);
+ return retval;
+}
+
+/* get the modem status register of the device
+ * NOTE spcp825-007 not supported this */
+static int spcp8x5_get_msr(struct usb_device *dev, u8 *status,
+ enum spcp8x5_type type)
+{
+ u8 *status_buffer;
+ int ret;
+
+ /* I return Permited not support here but seem inval device
+ * is more fix */
+ if (type == SPCP825_007_TYPE)
+ return -EPERM;
+ if (status == NULL)
+ return -EINVAL;
+
+ status_buffer = kmalloc(1, GFP_KERNEL);
+ if (!status_buffer)
+ return -ENOMEM;
+ status_buffer[0] = status[0];
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ GET_UART_STATUS, GET_UART_STATUS_TYPE,
+ 0, GET_UART_STATUS_MSR, status_buffer, 1, 100);
+ if (ret < 0)
+ dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)",
+ status_buffer, ret);
+
+ dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer);
+ status[0] = status_buffer[0];
+ kfree(status_buffer);
+
+ return ret;
+}
+
+/* select the work mode.
+ * NOTE this function not supported by spcp825-007 */
+static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
+ u16 index, enum spcp8x5_type type)
+{
+ int ret;
+
+ /* I return Permited not support here but seem inval device
+ * is more fix */
+ if (type == SPCP825_007_TYPE)
+ return;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ SET_WORKING_MODE_TYPE, SET_WORKING_MODE,
+ value, index, NULL, 0, 100);
+ dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index);
+ if (ret < 0)
+ dev_dbg(&dev->dev,
+ "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
+}
+
+/* close the serial port. We should wait for data sending to device 1st and
+ * then kill all urb. */
+static void spcp8x5_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int c_cflag;
+ int bps;
+ long timeout;
+ wait_queue_t wait;
+ int result;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ /* wait for data to drain from the buffer */
+ spin_lock_irqsave(&priv->lock, flags);
+ timeout = SPCP8x5_CLOSING_WAIT;
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&port->tty->write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (ringbuf_avail_data(priv->buf) == 0 ||
+ timeout == 0 || signal_pending(current))
+ break;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irqsave(&priv->lock, flags);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->tty->write_wait, &wait);
+
+ /* clear out any remaining data in the buffer */
+ clear_ringbuf(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wait for characters to drain from the device (this is long enough
+ * for the entire all byte spcp8x5 hardware buffer to drain with no
+ * flow control for data rates of 1200 bps or more, for lower rates we
+ * should really know how much data is in the buffer to compute a delay
+ * that is not unnecessarily long) */
+ bps = tty_get_baud_rate(port->tty);
+ if (bps > 1200)
+ timeout = max((HZ*2560) / bps, HZ/10);
+ else
+ timeout = 2*HZ;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(timeout);
+
+ /* clear control lines */
+ if (port->tty) {
+ c_cflag = port->tty->termios->c_cflag;
+ if (c_cflag & HUPCL) {
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_control = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ spcp8x5_set_ctrlLine(port->serial->dev, 0 , priv->type);
+ }
+ }
+
+ /* kill urb */
+ if (port->write_urb != NULL) {
+ result = usb_unlink_urb(port->write_urb);
+ if (result)
+ dev_dbg(&port->dev,
+ "usb_unlink_urb(write_urb) = %d\n", result);
+ }
+ result = usb_unlink_urb(port->read_urb);
+ if (result)
+ dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
+}
+
+/* set the serial param for transfer. we should check if we really need to
+ * transfer. then if be set flow contorl we should do this too. */
+static void spcp8x5_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int old_cflag = old_termios->c_cflag;
+ unsigned short uartdata;
+ unsigned char buf[2] = {0, 0};
+ int baud;
+ int i;
+ u8 control;
+
+ if ((!port->tty) || (!port->tty->termios))
+ return;
+
+ /* for the 1st time call this function */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+ port->tty->termios->c_cflag = B115200 | CS8 | CREAD |
+ HUPCL | CLOCAL;
+ priv->termios_initialized = 1;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* check that they really want us to change something */
+ if (!tty_termios_hw_change(port->tty->termios, old_termios))
+ return;
+
+ /* set DTR/RTS active */
+ spin_lock_irqsave(&priv->lock, flags);
+ control = priv->line_control;
+ if ((old_cflag & CBAUD) == B0) {
+ priv->line_control |= MCR_DTR;
+ if (!(old_cflag & CRTSCTS))
+ priv->line_control |= MCR_RTS;
+ }
+ if (control != priv->line_control) {
+ control = priv->line_control;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ spcp8x5_set_ctrlLine(serial->dev, control , priv->type);
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ /* Set Baud Rate */
+ baud = tty_get_baud_rate(port->tty);;
+ switch (baud) {
+ case 300: buf[0] = 0x00; break;
+ case 600: buf[0] = 0x01; break;
+ case 1200: buf[0] = 0x02; break;
+ case 2400: buf[0] = 0x03; break;
+ case 4800: buf[0] = 0x04; break;
+ case 9600: buf[0] = 0x05; break;
+ case 19200: buf[0] = 0x07; break;
+ case 38400: buf[0] = 0x09; break;
+ case 57600: buf[0] = 0x0a; break;
+ case 115200: buf[0] = 0x0b; break;
+ case 230400: buf[0] = 0x0c; break;
+ case 460800: buf[0] = 0x0d; break;
+ case 921600: buf[0] = 0x0e; break;
+/* case 1200000: buf[0] = 0x0f; break; */
+/* case 2400000: buf[0] = 0x10; break; */
+ case 3000000: buf[0] = 0x11; break;
+/* case 6000000: buf[0] = 0x12; break; */
+ case 0:
+ case 1000000:
+ buf[0] = 0x0b; break;
+ default:
+ err("spcp825 driver does not support the baudrate "
+ "requested, using default of 9600.");
+ }
+
+ /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5:
+ buf[1] |= SET_UART_FORMAT_SIZE_5;
+ break;
+ case CS6:
+ buf[1] |= SET_UART_FORMAT_SIZE_6;
+ break;
+ case CS7:
+ buf[1] |= SET_UART_FORMAT_SIZE_7;
+ break;
+ default:
+ case CS8:
+ buf[1] |= SET_UART_FORMAT_SIZE_8;
+ break;
+ }
+ }
+
+ /* Set Stop bit2 : 0:1bit 1:2bit */
+ buf[1] |= (cflag & CSTOPB) ? SET_UART_FORMAT_STOP_2 :
+ SET_UART_FORMAT_STOP_1;
+
+ /* Set Parity bit3-4 01:Odd 11:Even */
+ if (cflag & PARENB) {
+ buf[1] |= (cflag & PARODD) ?
+ SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
+ } else
+ buf[1] |= SET_UART_FORMAT_PAR_NONE;
+
+ uartdata = buf[0] | buf[1]<<8;
+
+ i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ SET_UART_FORMAT_TYPE, SET_UART_FORMAT,
+ uartdata, 0, NULL, 0, 100);
+ if (i < 0)
+ err("Set UART format %#x failed (error = %d)", uartdata, i);
+ dbg("0x21:0x40:0:0 %d\n", i);
+
+ if (cflag & CRTSCTS) {
+ /* enable hardware flow control */
+ spcp8x5_set_workMode(serial->dev, 0x000a,
+ SET_WORKING_MODE_U2C, priv->type);
+ }
+ return;
+}
+
+/* open the serial port. do some usb system call. set termios and get the line
+ * status of the device. then submit the read urb */
+static int spcp8x5_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct ktermios tmp_termios;
+ struct usb_serial *serial = port->serial;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ int ret;
+ unsigned long flags;
+ u8 status = 0x30;
+ /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
+
+ dbg("%s - port %d", __func__, port->number);
+
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ 0x09, 0x00,
+ 0x01, 0x00, NULL, 0x00, 100);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (port->tty->termios->c_cflag & CBAUD)
+ priv->line_control = MCR_DTR | MCR_RTS;
+ else
+ priv->line_control = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
+
+ /* Setup termios */
+ if (port->tty)
+ spcp8x5_set_termios(port, &tmp_termios);
+
+ spcp8x5_get_msr(serial->dev, &status, priv->type);
+
+ /* may be we should update uart status here but now we did not do */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_status = status & 0xf0 ;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* FIXME: need to assert RTS and DTR if CRTSCTS off */
+
+ dbg("%s - submitting read urb", __func__);
+ port->read_urb->dev = serial->dev;
+ ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (ret) {
+ spcp8x5_close(port, NULL);
+ return -EPROTO;
+ }
+ return 0;
+}
+
+/* bulk read call back function. check the status of the urb. if transfer
+ * failed return. then update the status and the tty send data to tty subsys.
+ * submit urb again.
+ */
+static void spcp8x5_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ unsigned long flags;
+ int i;
+ int result;
+ u8 status = 0;
+ char tty_flag;
+
+ dev_dbg(&port->dev, "start, urb->status = %d, "
+ "urb->actual_length = %d\n,", urb->status, urb->actual_length);
+
+ /* check the urb status */
+ if (urb->status) {
+ if (!port->open_count)
+ return;
+ if (urb->status == -EPROTO) {
+ /* spcp8x5 mysteriously fails with -EPROTO */
+ /* reschedule the read */
+ urb->status = 0;
+ urb->dev = port->serial->dev;
+ result = usb_submit_urb(urb , GFP_ATOMIC);
+ if (result)
+ dev_dbg(&port->dev,
+ "failed submitting read urb %d\n",
+ result);
+ return;
+ }
+ dev_dbg(&port->dev, "unable to handle the error, exiting.\n");
+ return;
+ }
+
+ /* get tty_flag from status */
+ tty_flag = TTY_NORMAL;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+ priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /* wake up the wait for termios */
+ wake_up_interruptible(&priv->delta_msr_wait);
+
+ /* break takes precedence over parity, which takes precedence over
+ * framing errors */
+ if (status & UART_BREAK_ERROR)
+ tty_flag = TTY_BREAK;
+ else if (status & UART_PARITY_ERROR)
+ tty_flag = TTY_PARITY;
+ else if (status & UART_FRAME_ERROR)
+ tty_flag = TTY_FRAME;
+ dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ tty_buffer_request_room(tty, urb->actual_length + 1);
+ /* overrun is special, not associated with a char */
+ if (status & UART_OVERRUN_ERROR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ for (i = 0; i < urb->actual_length; ++i)
+ tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Schedule the next read _if_ we are still open */
+ if (port->open_count) {
+ urb->dev = port->serial->dev;
+ result = usb_submit_urb(urb , GFP_ATOMIC);
+ if (result)
+ dev_dbg(&port->dev, "failed submitting read urb %d\n",
+ result);
+ }
+
+ return;
+}
+
+/* get data from ring buffer and then write to usb bus */
+static void spcp8x5_send(struct usb_serial_port *port)
+{
+ int count, result;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->write_urb_in_use) {
+ dev_dbg(&port->dev, "write urb still used\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* send the 1st urb for writting */
+ memset(port->write_urb->transfer_buffer , 0x00 , port->bulk_out_size);
+ count = get_ringbuf(priv->buf, port->write_urb->transfer_buffer,
+ port->bulk_out_size);
+
+ if (count == 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* update the urb status */
+ priv->write_urb_in_use = 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ port->write_urb->transfer_buffer_length = count;
+ port->write_urb->dev = port->serial->dev;
+
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result) {
+ dev_dbg(&port->dev, "failed submitting write urb, error %d\n",
+ result);
+ priv->write_urb_in_use = 0;
+ /* TODO: reschedule spcp8x5_send */
+ }
+
+
+ schedule_work(&port->work);
+}
+
+/* this is the call back function for write urb. NOTE we should not sleep in
+ * this routine. check the urb return code and then submit the write urb again
+ * to hold the write loop */
+static void spcp8x5_write_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dev_dbg(&port->dev, "urb shutting down with status: %d\n",
+ urb->status);
+ priv->write_urb_in_use = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __func__);
+ dbg("%s - nonzero write bulk status received: %d",
+ __func__, urb->status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result)
+ dev_dbg(&port->dev,
+ "failed resubmitting write urb %d\n", result);
+ else
+ return;
+ }
+
+ priv->write_urb_in_use = 0;
+
+ /* send any buffered data */
+ spcp8x5_send(port);
+}
+
+/* write data to ring buffer. and then start the write transfer */
+static int spcp8x5_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dev_dbg(&port->dev, "%d bytes\n", count);
+
+ if (!count)
+ return count;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ count = put_ringbuf(priv->buf, buf, count);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ spcp8x5_send(port);
+
+ return count;
+}
+
+static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
+ unsigned int arg)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int prevstatus;
+ unsigned int status;
+ unsigned int changed;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ prevstatus = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+ /* wake up in bulk read */
+ interruptible_sleep_on(&priv->delta_msr_wait);
+
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ changed = prevstatus^status;
+
+ if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) ||
+ ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) ||
+ ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) ||
+ ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS)))
+ return 0;
+
+ prevstatus = status;
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+static int spcp8x5_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ switch (cmd) {
+ case TIOCMIWAIT:
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ return spcp8x5_wait_modem_info(port, arg);
+
+ default:
+ dbg("%s not supported = 0x%04x", __func__, cmd);
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int spcp8x5_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ u8 control;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (set & TIOCM_RTS)
+ priv->line_control |= MCR_RTS;
+ if (set & TIOCM_DTR)
+ priv->line_control |= MCR_DTR;
+ if (clear & TIOCM_RTS)
+ priv->line_control &= ~MCR_RTS;
+ if (clear & TIOCM_DTR)
+ priv->line_control &= ~MCR_DTR;
+ control = priv->line_control;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+}
+
+static int spcp8x5_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int mcr;
+ unsigned int status;
+ unsigned int result;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ mcr = priv->line_control;
+ status = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
+ | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
+ | ((status & MSR_STATUS_LINE_CTS) ? TIOCM_CTS : 0)
+ | ((status & MSR_STATUS_LINE_DSR) ? TIOCM_DSR : 0)
+ | ((status & MSR_STATUS_LINE_RI) ? TIOCM_RI : 0)
+ | ((status & MSR_STATUS_LINE_DCD) ? TIOCM_CD : 0);
+
+ return result;
+}
+
+/* get the avail space room in ring buffer */
+static int spcp8x5_write_room(struct usb_serial_port *port)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ int room = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ room = ringbuf_avail_space(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return room;
+}
+
+/* get the number of avail data in write ring buffer */
+static int spcp8x5_chars_in_buffer(struct usb_serial_port *port)
+{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ int chars = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ chars = ringbuf_avail_data(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return chars;
+}
+
+/* All of the device info needed for the spcp8x5 SIO serial converter */
+static struct usb_serial_driver spcp8x5_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "SPCP8x5",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+ .open = spcp8x5_open,
+ .close = spcp8x5_close,
+ .write = spcp8x5_write,
+ .set_termios = spcp8x5_set_termios,
+ .ioctl = spcp8x5_ioctl,
+ .tiocmget = spcp8x5_tiocmget,
+ .tiocmset = spcp8x5_tiocmset,
+ .write_room = spcp8x5_write_room,
+ .read_bulk_callback = spcp8x5_read_bulk_callback,
+ .write_bulk_callback = spcp8x5_write_bulk_callback,
+ .chars_in_buffer = spcp8x5_chars_in_buffer,
+ .attach = spcp8x5_startup,
+ .shutdown = spcp8x5_shutdown,
+};
+
+static int __init spcp8x5_init(void)
+{
+ int retval;
+ retval = usb_serial_register(&spcp8x5_device);
+ if (retval)
+ goto failed_usb_serial_register;
+ retval = usb_register(&spcp8x5_driver);
+ if (retval)
+ goto failed_usb_register;
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ return 0;
+failed_usb_register:
+ usb_serial_deregister(&spcp8x5_device);
+failed_usb_serial_register:
+ return retval;
+}
+
+static void __exit spcp8x5_exit(void)
+{
+ usb_deregister(&spcp8x5_driver);
+ usb_serial_deregister(&spcp8x5_device);
+}
+
+module_init(spcp8x5_init);
+module_exit(spcp8x5_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 3a3776677339..a1c8aef01417 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -264,9 +264,6 @@ static struct usb_serial_driver ti_1port_device = {
.description = "TI USB 3410 1 port adapter",
.usb_driver = &ti_usb_driver,
.id_table = ti_id_table_3410,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = 1,
.num_ports = 1,
.attach = ti_startup,
.shutdown = ti_shutdown,
@@ -295,9 +292,6 @@ static struct usb_serial_driver ti_2port_device = {
.description = "TI USB 5052 2 port adapter",
.usb_driver = &ti_usb_driver,
.id_table = ti_id_table_5052,
- .num_interrupt_in = 1,
- .num_bulk_in = 2,
- .num_bulk_out = 2,
.num_ports = 2,
.attach = ti_startup,
.shutdown = ti_shutdown,
@@ -414,14 +408,14 @@ static int ti_startup(struct usb_serial *serial)
dbg("%s - product 0x%4X, num configurations %d, configuration value %d",
- __FUNCTION__, le16_to_cpu(dev->descriptor.idProduct),
+ __func__, le16_to_cpu(dev->descriptor.idProduct),
dev->descriptor.bNumConfigurations,
dev->actconfig->desc.bConfigurationValue);
/* create device structure */
tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
if (tdev == NULL) {
- dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
mutex_init(&tdev->td_open_close_lock);
@@ -431,7 +425,7 @@ static int ti_startup(struct usb_serial *serial)
/* determine device type */
if (usb_match_id(serial->interface, ti_id_table_3410))
tdev->td_is_3410 = 1;
- dbg("%s - device type is %s", __FUNCTION__, tdev->td_is_3410 ? "3410" : "5052");
+ dbg("%s - device type is %s", __func__, tdev->td_is_3410 ? "3410" : "5052");
/* if we have only 1 configuration, download firmware */
if (dev->descriptor.bNumConfigurations == 1) {
@@ -465,7 +459,7 @@ static int ti_startup(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL);
if (tport == NULL) {
- dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
status = -ENOMEM;
goto free_tports;
}
@@ -477,7 +471,7 @@ static int ti_startup(struct usb_serial *serial)
init_waitqueue_head(&tport->tp_write_wait);
tport->tp_write_buf = ti_buf_alloc();
if (tport->tp_write_buf == NULL) {
- dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
kfree(tport);
status = -ENOMEM;
goto free_tports;
@@ -510,7 +504,7 @@ static void ti_shutdown(struct usb_serial *serial)
struct ti_device *tdev = usb_get_serial_data(serial);
struct ti_port *tport;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i=0; i < serial->num_ports; ++i) {
tport = usb_get_serial_port_data(serial->port[i]);
@@ -538,7 +532,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
TI_PIPE_TIMEOUT_ENABLE |
(TI_TRANSFER_TIMEOUT << 2));
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return -ENODEV;
@@ -563,10 +557,10 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
/* start interrupt urb the first time a port is opened on this device */
if (tdev->td_open_port_count == 0) {
- dbg("%s - start interrupt in urb", __FUNCTION__);
+ dbg("%s - start interrupt in urb", __func__);
urb = tdev->td_serial->port[0]->interrupt_in_urb;
if (!urb) {
- dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - no interrupt urb\n", __func__);
status = -EINVAL;
goto release_lock;
}
@@ -575,40 +569,40 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
urb->dev = dev;
status = usb_submit_urb(urb, GFP_KERNEL);
if (status) {
- dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __func__, status);
goto release_lock;
}
}
ti_set_termios(port, port->tty->termios);
- dbg("%s - sending TI_OPEN_PORT", __FUNCTION__);
+ dbg("%s - sending TI_OPEN_PORT", __func__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
(__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
if (status) {
- dev_err(&port->dev, "%s - cannot send open command, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot send open command, %d\n", __func__, status);
goto unlink_int_urb;
}
- dbg("%s - sending TI_START_PORT", __FUNCTION__);
+ dbg("%s - sending TI_START_PORT", __func__);
status = ti_command_out_sync(tdev, TI_START_PORT,
(__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
if (status) {
- dev_err(&port->dev, "%s - cannot send start command, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot send start command, %d\n", __func__, status);
goto unlink_int_urb;
}
- dbg("%s - sending TI_PURGE_PORT", __FUNCTION__);
+ dbg("%s - sending TI_PURGE_PORT", __func__);
status = ti_command_out_sync(tdev, TI_PURGE_PORT,
(__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0);
if (status) {
- dev_err(&port->dev, "%s - cannot clear input buffers, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot clear input buffers, %d\n", __func__, status);
goto unlink_int_urb;
}
status = ti_command_out_sync(tdev, TI_PURGE_PORT,
(__u8)(TI_UART1_PORT + port_number), TI_PURGE_OUTPUT, NULL, 0);
if (status) {
- dev_err(&port->dev, "%s - cannot clear output buffers, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot clear output buffers, %d\n", __func__, status);
goto unlink_int_urb;
}
@@ -619,27 +613,27 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
ti_set_termios(port, port->tty->termios);
- dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__);
+ dbg("%s - sending TI_OPEN_PORT (2)", __func__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
(__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
if (status) {
- dev_err(&port->dev, "%s - cannot send open command (2), %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot send open command (2), %d\n", __func__, status);
goto unlink_int_urb;
}
- dbg("%s - sending TI_START_PORT (2)", __FUNCTION__);
+ dbg("%s - sending TI_START_PORT (2)", __func__);
status = ti_command_out_sync(tdev, TI_START_PORT,
(__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
if (status) {
- dev_err(&port->dev, "%s - cannot send start command (2), %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot send start command (2), %d\n", __func__, status);
goto unlink_int_urb;
}
/* start read urb */
- dbg("%s - start read urb", __FUNCTION__);
+ dbg("%s - start read urb", __func__);
urb = port->read_urb;
if (!urb) {
- dev_err(&port->dev, "%s - no read urb\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - no read urb\n", __func__);
status = -EINVAL;
goto unlink_int_urb;
}
@@ -649,7 +643,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
urb->dev = dev;
status = usb_submit_urb(urb, GFP_KERNEL);
if (status) {
- dev_err(&port->dev, "%s - submit read urb failed, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - submit read urb failed, %d\n", __func__, status);
goto unlink_int_urb;
}
@@ -663,7 +657,7 @@ unlink_int_urb:
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
release_lock:
mutex_unlock(&tdev->td_open_close_lock);
- dbg("%s - exit %d", __FUNCTION__, status);
+ dbg("%s - exit %d", __func__, status);
return status;
}
@@ -676,7 +670,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
int status;
int do_unlock;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
tdev = usb_get_serial_data(port->serial);
tport = usb_get_serial_port_data(port);
@@ -693,11 +687,11 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
port_number = port->number - port->serial->minor;
- dbg("%s - sending TI_CLOSE_PORT", __FUNCTION__);
+ dbg("%s - sending TI_CLOSE_PORT", __func__);
status = ti_command_out_sync(tdev, TI_CLOSE_PORT,
(__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
if (status)
- dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __func__, status);
/* if mutex_lock is interrupted, continue anyway */
do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
@@ -710,7 +704,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
if (do_unlock)
mutex_unlock(&tdev->td_open_close_lock);
- dbg("%s - exit", __FUNCTION__);
+ dbg("%s - exit", __func__);
}
@@ -720,10 +714,10 @@ static int ti_write(struct usb_serial_port *port, const unsigned char *data,
struct ti_port *tport = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return 0;
}
@@ -746,7 +740,7 @@ static int ti_write_room(struct usb_serial_port *port)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return -ENODEV;
@@ -755,7 +749,7 @@ static int ti_write_room(struct usb_serial_port *port)
room = ti_buf_space_avail(tport->tp_write_buf);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return room;
}
@@ -766,7 +760,7 @@ static int ti_chars_in_buffer(struct usb_serial_port *port)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return -ENODEV;
@@ -775,7 +769,7 @@ static int ti_chars_in_buffer(struct usb_serial_port *port)
chars = ti_buf_data_avail(tport->tp_write_buf);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- dbg("%s - returns %d", __FUNCTION__, chars);
+ dbg("%s - returns %d", __func__, chars);
return chars;
}
@@ -785,14 +779,14 @@ static void ti_throttle(struct usb_serial_port *port)
struct ti_port *tport = usb_get_serial_port_data(port);
struct tty_struct *tty;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return;
tty = port->tty;
if (!tty) {
- dbg("%s - no tty", __FUNCTION__);
+ dbg("%s - no tty", __func__);
return;
}
@@ -808,21 +802,21 @@ static void ti_unthrottle(struct usb_serial_port *port)
struct tty_struct *tty;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return;
tty = port->tty;
if (!tty) {
- dbg("%s - no tty", __FUNCTION__);
+ dbg("%s - no tty", __func__);
return;
}
if (I_IXOFF(tty) || C_CRTSCTS(tty)) {
status = ti_restart_read(tport, tty);
if (status)
- dev_err(&port->dev, "%s - cannot restart read, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - cannot restart read, %d\n", __func__, status);
}
}
@@ -834,24 +828,24 @@ static int ti_ioctl(struct usb_serial_port *port, struct file *file,
struct async_icount cnow;
struct async_icount cprev;
- dbg("%s - port %d, cmd = 0x%04X", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd = 0x%04X", __func__, port->number, cmd);
if (tport == NULL)
return -ENODEV;
switch (cmd) {
case TIOCGSERIAL:
- dbg("%s - (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCGSERIAL", __func__, port->number);
return ti_get_serial_info(tport, (struct serial_struct __user *)arg);
break;
case TIOCSSERIAL:
- dbg("%s - (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
return ti_set_serial_info(tport, (struct serial_struct __user *)arg);
break;
case TIOCMIWAIT:
- dbg("%s - (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
cprev = tport->tp_icount;
while (1) {
interruptible_sleep_on(&tport->tp_msr_wait);
@@ -872,7 +866,7 @@ static int ti_ioctl(struct usb_serial_port *port, struct file *file,
break;
case TIOCGICOUNT:
- dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, port->number, tport->tp_icount.rx, tport->tp_icount.tx);
+ dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, port->number, tport->tp_icount.rx, tport->tp_icount.tx);
if (copy_to_user((void __user *)arg, &tport->tp_icount, sizeof(tport->tp_icount)))
return -EFAULT;
return 0;
@@ -894,20 +888,20 @@ static void ti_set_termios(struct usb_serial_port *port,
int port_number = port->number - port->serial->minor;
unsigned int mcr;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
- dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
- dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
+ dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag);
+ dbg("%s - old clfag %08x, old iflag %08x", __func__, old_termios->c_cflag, old_termios->c_iflag);
if (tport == NULL)
return;
config = kmalloc(sizeof(*config), GFP_KERNEL);
if (!config) {
- dev_err(&port->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - out of memory\n", __func__);
return;
}
@@ -991,7 +985,7 @@ static void ti_set_termios(struct usb_serial_port *port,
tty_encode_baud_rate(tty, baud, baud);
dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
- __FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
+ __func__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
cpu_to_be16s(&config->wBaudRate);
cpu_to_be16s(&config->wFlags);
@@ -1000,7 +994,7 @@ static void ti_set_termios(struct usb_serial_port *port,
(__u8)(TI_UART1_PORT + port_number), 0, (__u8 *)config,
sizeof(*config));
if (status)
- dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", __FUNCTION__, port_number, status);
+ dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", __func__, port_number, status);
/* SET_CONFIG asserts RTS and DTR, reset them correctly */
mcr = tport->tp_shadow_mcr;
@@ -1009,7 +1003,7 @@ static void ti_set_termios(struct usb_serial_port *port,
mcr &= ~(TI_MCR_DTR | TI_MCR_RTS);
status = ti_set_mcr(tport, mcr);
if (status)
- dev_err(&port->dev, "%s - cannot set modem control on port %d, %d\n", __FUNCTION__, port_number, status);
+ dev_err(&port->dev, "%s - cannot set modem control on port %d, %d\n", __func__, port_number, status);
kfree(config);
}
@@ -1021,14 +1015,17 @@ static int ti_tiocmget(struct usb_serial_port *port, struct file *file)
unsigned int result;
unsigned int msr;
unsigned int mcr;
+ unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return -ENODEV;
+ spin_lock_irqsave(&tport->tp_lock, flags);
msr = tport->tp_msr;
mcr = tport->tp_shadow_mcr;
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
result = ((mcr & TI_MCR_DTR) ? TIOCM_DTR : 0)
| ((mcr & TI_MCR_RTS) ? TIOCM_RTS : 0)
@@ -1038,7 +1035,7 @@ static int ti_tiocmget(struct usb_serial_port *port, struct file *file)
| ((msr & TI_MSR_RI) ? TIOCM_RI : 0)
| ((msr & TI_MSR_DSR) ? TIOCM_DSR : 0);
- dbg("%s - 0x%04X", __FUNCTION__, result);
+ dbg("%s - 0x%04X", __func__, result);
return result;
}
@@ -1049,12 +1046,14 @@ static int ti_tiocmset(struct usb_serial_port *port, struct file *file,
{
struct ti_port *tport = usb_get_serial_port_data(port);
unsigned int mcr;
+ unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (tport == NULL)
return -ENODEV;
+ spin_lock_irqsave(&tport->tp_lock, flags);
mcr = tport->tp_shadow_mcr;
if (set & TIOCM_RTS)
@@ -1070,6 +1069,7 @@ static int ti_tiocmset(struct usb_serial_port *port, struct file *file,
mcr &= ~TI_MCR_DTR;
if (clear & TIOCM_LOOP)
mcr &= ~TI_MCR_LOOP;
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
return ti_set_mcr(tport, mcr);
}
@@ -1080,7 +1080,7 @@ static void ti_break(struct usb_serial_port *port, int break_state)
struct ti_port *tport = usb_get_serial_port_data(port);
int status;
- dbg("%s - state = %d", __FUNCTION__, break_state);
+ dbg("%s - state = %d", __func__, break_state);
if (tport == NULL)
return;
@@ -1092,13 +1092,13 @@ static void ti_break(struct usb_serial_port *port, int break_state)
TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0);
if (status)
- dbg("%s - error setting break, %d", __FUNCTION__, status);
+ dbg("%s - error setting break, %d", __func__, status);
}
static void ti_interrupt_callback(struct urb *urb)
{
- struct ti_device *tdev = (struct ti_device *)urb->context;
+ struct ti_device *tdev = urb->context;
struct usb_serial_port *port;
struct usb_serial *serial = tdev->td_serial;
struct ti_port *tport;
@@ -1111,7 +1111,7 @@ static void ti_interrupt_callback(struct urb *urb)
int retval;
__u8 msr;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
switch (status) {
case 0:
@@ -1119,33 +1119,33 @@ static void ti_interrupt_callback(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("%s - urb shutting down, %d", __FUNCTION__, status);
+ dbg("%s - urb shutting down, %d", __func__, status);
tdev->td_urb_error = 1;
return;
default:
dev_err(dev, "%s - nonzero urb status, %d\n",
- __FUNCTION__, status);
+ __func__, status);
tdev->td_urb_error = 1;
goto exit;
}
if (length != 2) {
- dbg("%s - bad packet size, %d", __FUNCTION__, length);
+ dbg("%s - bad packet size, %d", __func__, length);
goto exit;
}
if (data[0] == TI_CODE_HARDWARE_ERROR) {
- dev_err(dev, "%s - hardware error, %d\n", __FUNCTION__, data[1]);
+ dev_err(dev, "%s - hardware error, %d\n", __func__, data[1]);
goto exit;
}
port_number = TI_GET_PORT_FROM_CODE(data[0]);
function = TI_GET_FUNC_FROM_CODE(data[0]);
- dbg("%s - port_number %d, function %d, data 0x%02X", __FUNCTION__, port_number, function, data[1]);
+ dbg("%s - port_number %d, function %d, data 0x%02X", __func__, port_number, function, data[1]);
if (port_number >= serial->num_ports) {
- dev_err(dev, "%s - bad port number, %d\n", __FUNCTION__, port_number);
+ dev_err(dev, "%s - bad port number, %d\n", __func__, port_number);
goto exit;
}
@@ -1157,17 +1157,17 @@ static void ti_interrupt_callback(struct urb *urb)
switch (function) {
case TI_CODE_DATA_ERROR:
- dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n", __FUNCTION__, port_number, data[1]);
+ dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n", __func__, port_number, data[1]);
break;
case TI_CODE_MODEM_STATUS:
msr = data[1];
- dbg("%s - port %d, msr 0x%02X", __FUNCTION__, port_number, msr);
+ dbg("%s - port %d, msr 0x%02X", __func__, port_number, msr);
ti_handle_new_msr(tport, msr);
break;
default:
- dev_err(dev, "%s - unknown interrupt code, 0x%02X\n", __FUNCTION__, data[1]);
+ dev_err(dev, "%s - unknown interrupt code, 0x%02X\n", __func__, data[1]);
break;
}
@@ -1175,19 +1175,19 @@ exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(dev, "%s - resubmit interrupt urb failed, %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
static void ti_bulk_in_callback(struct urb *urb)
{
- struct ti_port *tport = (struct ti_port *)urb->context;
+ struct ti_port *tport = urb->context;
struct usb_serial_port *port = tport->tp_port;
struct device *dev = &urb->dev->dev;
int status = urb->status;
int retval = 0;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
switch (status) {
case 0:
@@ -1195,13 +1195,13 @@ static void ti_bulk_in_callback(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("%s - urb shutting down, %d", __FUNCTION__, status);
+ dbg("%s - urb shutting down, %d", __func__, status);
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
return;
default:
dev_err(dev, "%s - nonzero urb status, %d\n",
- __FUNCTION__, status );
+ __func__, status );
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
}
@@ -1210,16 +1210,16 @@ static void ti_bulk_in_callback(struct urb *urb)
goto exit;
if (status) {
- dev_err(dev, "%s - stopping read!\n", __FUNCTION__);
+ dev_err(dev, "%s - stopping read!\n", __func__);
return;
}
if (port->tty && urb->actual_length) {
- usb_serial_debug_data(debug, dev, __FUNCTION__,
+ usb_serial_debug_data(debug, dev, __func__,
urb->actual_length, urb->transfer_buffer);
if (!tport->tp_is_open)
- dbg("%s - port closed, dropping data", __FUNCTION__);
+ dbg("%s - port closed, dropping data", __func__);
else
ti_recv(&urb->dev->dev, port->tty, urb->transfer_buffer,
urb->actual_length);
@@ -1241,18 +1241,18 @@ exit:
spin_unlock(&tport->tp_lock);
if (retval)
dev_err(dev, "%s - resubmit read urb failed, %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
}
static void ti_bulk_out_callback(struct urb *urb)
{
- struct ti_port *tport = (struct ti_port *)urb->context;
+ struct ti_port *tport = urb->context;
struct usb_serial_port *port = tport->tp_port;
struct device *dev = &urb->dev->dev;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
tport->tp_write_urb_in_use = 0;
@@ -1262,13 +1262,13 @@ static void ti_bulk_out_callback(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("%s - urb shutting down, %d", __FUNCTION__, status);
+ dbg("%s - urb shutting down, %d", __func__, status);
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
return;
default:
dev_err(dev, "%s - nonzero urb status, %d\n",
- __FUNCTION__, status);
+ __func__, status);
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
}
@@ -1286,7 +1286,7 @@ static void ti_recv(struct device *dev, struct tty_struct *tty,
do {
cnt = tty_buffer_request_room(tty, length);
if (cnt < length) {
- dev_err(dev, "%s - dropping data, %d bytes lost\n", __FUNCTION__, length - cnt);
+ dev_err(dev, "%s - dropping data, %d bytes lost\n", __func__, length - cnt);
if(cnt == 0)
break;
}
@@ -1307,7 +1307,7 @@ static void ti_send(struct ti_port *tport)
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&tport->tp_lock, flags);
@@ -1329,7 +1329,7 @@ static void ti_send(struct ti_port *tport)
spin_unlock_irqrestore(&tport->tp_lock, flags);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, port->write_urb->transfer_buffer);
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev,
@@ -1339,7 +1339,7 @@ static void ti_send(struct ti_port *tport)
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - submit write urb failed, %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - submit write urb failed, %d\n", __func__, result);
tport->tp_write_urb_in_use = 0;
/* TODO: reschedule ti_send */
} else {
@@ -1357,14 +1357,17 @@ static void ti_send(struct ti_port *tport)
static int ti_set_mcr(struct ti_port *tport, unsigned int mcr)
{
+ unsigned long flags;
int status;
status = ti_write_byte(tport->tp_tdev,
tport->tp_uart_base_addr + TI_UART_OFFSET_MCR,
TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr);
+ spin_lock_irqsave(&tport->tp_lock, flags);
if (!status)
tport->tp_shadow_mcr = mcr;
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
return status;
}
@@ -1378,23 +1381,23 @@ static int ti_get_lsr(struct ti_port *tport)
int port_number = port->number - port->serial->minor;
struct ti_port_status *data;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
size = sizeof(struct ti_port_status);
data = kmalloc(size, GFP_KERNEL);
if (!data) {
- dev_err(&port->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&port->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS,
(__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size);
if (status) {
- dev_err(&port->dev, "%s - get port status command failed, %d\n", __FUNCTION__, status);
+ dev_err(&port->dev, "%s - get port status command failed, %d\n", __func__, status);
goto free_data;
}
- dbg("%s - lsr 0x%02X", __FUNCTION__, data->bLSR);
+ dbg("%s - lsr 0x%02X", __func__, data->bLSR);
tport->tp_lsr = data->bLSR;
@@ -1455,7 +1458,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
struct tty_struct *tty;
unsigned long flags;
- dbg("%s - msr 0x%02X", __FUNCTION__, msr);
+ dbg("%s - msr 0x%02X", __func__, msr);
if (msr & TI_MSR_DELTA_MASK) {
spin_lock_irqsave(&tport->tp_lock, flags);
@@ -1493,7 +1496,7 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
struct usb_serial_port *port = tport->tp_port;
wait_queue_t wait;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irq(&tport->tp_lock);
@@ -1625,12 +1628,12 @@ static int ti_write_byte(struct ti_device *tdev, unsigned long addr,
struct ti_write_data_bytes *data;
struct device *dev = &tdev->td_serial->dev->dev;
- dbg("%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X", __FUNCTION__, addr, mask, byte);
+ dbg("%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X", __func__, addr, mask, byte);
size = sizeof(struct ti_write_data_bytes) + 2;
data = kmalloc(size, GFP_KERNEL);
if (!data) {
- dev_err(dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -1646,7 +1649,7 @@ static int ti_write_byte(struct ti_device *tdev, unsigned long addr,
(__u8 *)data, size);
if (status < 0)
- dev_err(dev, "%s - failed, %d\n", __FUNCTION__, status);
+ dev_err(dev, "%s - failed, %d\n", __func__, status);
kfree(data);
@@ -1673,7 +1676,7 @@ static int ti_download_firmware(struct ti_device *tdev,
buffer_size = TI_FIRMWARE_BUF_SIZE + sizeof(struct ti_firmware_header);
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!buffer) {
- dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -1687,7 +1690,7 @@ static int ti_download_firmware(struct ti_device *tdev,
header->wLength = cpu_to_le16((__u16)(buffer_size - sizeof(struct ti_firmware_header)));
header->bCheckSum = cs;
- dbg("%s - downloading firmware", __FUNCTION__);
+ dbg("%s - downloading firmware", __func__);
for (pos = 0; pos < buffer_size; pos += done) {
len = min(buffer_size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
status = usb_bulk_msg(dev, pipe, buffer+pos, len, &done, 1000);
@@ -1698,11 +1701,11 @@ static int ti_download_firmware(struct ti_device *tdev,
kfree(buffer);
if (status) {
- dev_err(&dev->dev, "%s - error downloading firmware, %d\n", __FUNCTION__, status);
+ dev_err(&dev->dev, "%s - error downloading firmware, %d\n", __func__, status);
return status;
}
- dbg("%s - download successful", __FUNCTION__);
+ dbg("%s - download successful", __func__);
return 0;
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 2138ba8aeb69..a9934a3f9845 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -81,7 +81,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
unsigned int i, j;
int good_spot;
- dbg("%s %d", __FUNCTION__, num_ports);
+ dbg("%s %d", __func__, num_ports);
*minor = 0;
mutex_lock(&table_lock);
@@ -101,7 +101,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
*minor = i;
j = 0;
- dbg("%s - minor base = %d", __FUNCTION__, *minor);
+ dbg("%s - minor base = %d", __func__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
serial_table[i] = serial;
serial->port[j++]->number = i;
@@ -117,7 +117,7 @@ static void return_serial(struct usb_serial *serial)
{
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (serial == NULL)
return;
@@ -135,7 +135,7 @@ static void destroy_serial(struct kref *kref)
serial = to_usb_serial(kref);
- dbg("%s - %s", __FUNCTION__, serial->type->description);
+ dbg("%s - %s", __func__, serial->type->description);
serial->type->shutdown(serial);
@@ -187,7 +187,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
unsigned int portNumber;
int retval;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index);
@@ -259,7 +259,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
if (!port)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
mutex_lock(&port->mutex);
@@ -299,11 +299,11 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
- dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
+ dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
if (!port->open_count) {
retval = -EINVAL;
- dbg("%s - port not opened", __FUNCTION__);
+ dbg("%s - port not opened", __func__);
goto exit;
}
@@ -322,10 +322,10 @@ static int serial_write_room (struct tty_struct *tty)
if (!port)
goto exit;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
goto exit;
}
@@ -344,10 +344,10 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
if (!port)
goto exit;
- dbg("%s = port %d", __FUNCTION__, port->number);
+ dbg("%s = port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
goto exit;
}
@@ -365,10 +365,10 @@ static void serial_throttle (struct tty_struct * tty)
if (!port)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg ("%s - port not open", __FUNCTION__);
+ dbg ("%s - port not open", __func__);
return;
}
@@ -384,10 +384,10 @@ static void serial_unthrottle (struct tty_struct * tty)
if (!port)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
return;
}
@@ -401,13 +401,15 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
+ lock_kernel();
if (!port)
goto exit;
- dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
+ /* Caution - port->open_count is BKL protected */
if (!port->open_count) {
- dbg ("%s - port not open", __FUNCTION__);
+ dbg ("%s - port not open", __func__);
goto exit;
}
@@ -416,8 +418,8 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
retval = port->serial->type->ioctl(port, file, cmd, arg);
else
retval = -ENOIOCTLCMD;
-
exit:
+ unlock_kernel();
return retval;
}
@@ -428,10 +430,10 @@ static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
if (!port)
return;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
return;
}
@@ -446,19 +448,24 @@ static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
+ lock_kernel();
+ if (!port) {
+ unlock_kernel();
return;
+ }
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
+ unlock_kernel();
return;
}
/* pass on to the driver specific version of this function if it is available */
if (port->serial->type->break_ctl)
port->serial->type->break_ctl(port, break_state);
+ unlock_kernel();
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
@@ -469,7 +476,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
off_t begin = 0;
char tmp[40];
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
length += sprintf (page, "usbserinfo:1.0 driver:2.0\n");
for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
serial = usb_serial_get_by_index(i);
@@ -515,10 +522,10 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file)
if (!port)
return -ENODEV;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
return -ENODEV;
}
@@ -536,10 +543,10 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
if (!port)
return -ENODEV;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->open_count) {
- dbg("%s - port not open", __FUNCTION__);
+ dbg("%s - port not open", __func__);
return -ENODEV;
}
@@ -565,7 +572,7 @@ static void usb_serial_port_work(struct work_struct *work)
container_of(work, struct usb_serial_port, work);
struct tty_struct *tty;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port)
return;
@@ -581,7 +588,7 @@ static void port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
- dbg ("%s - %s", __FUNCTION__, dev->bus_id);
+ dbg ("%s - %s", __func__, dev->bus_id);
port_free(port);
}
@@ -627,7 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
serial = kzalloc(sizeof(*serial), GFP_KERNEL);
if (!serial) {
- dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
return NULL;
}
serial->dev = usb_get_dev(dev);
@@ -722,7 +729,7 @@ int usb_serial_probe(struct usb_interface *interface,
serial = create_serial (dev, interface, type);
if (!serial) {
unlock_kernel();
- dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
+ dev_err(&interface->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -854,22 +861,6 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_interrupt_in = num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out;
-#if 0
- /* check that the device meets the driver's requirements */
- if ((type->num_interrupt_in != NUM_DONT_CARE &&
- type->num_interrupt_in != num_interrupt_in)
- || (type->num_interrupt_out != NUM_DONT_CARE &&
- type->num_interrupt_out != num_interrupt_out)
- || (type->num_bulk_in != NUM_DONT_CARE &&
- type->num_bulk_in != num_bulk_in)
- || (type->num_bulk_out != NUM_DONT_CARE &&
- type->num_bulk_out != num_bulk_out)) {
- dbg("wrong number of endpoints");
- kfree(serial);
- return -EIO;
- }
-#endif
-
/* found all that we need */
dev_info(&interface->dev, "%s converter detected\n",
type->description);
@@ -883,7 +874,7 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_port_pointers = max_endpoints;
unlock_kernel();
- dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
+ dbg("%s - setting up %d port structures for this device", __func__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
@@ -1031,7 +1022,7 @@ int usb_serial_probe(struct usb_interface *interface,
port->dev.release = &port_release;
snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
- dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
+ dbg ("%s - registering %s", __func__, port->dev.bus_id);
retval = device_register(&port->dev);
if (retval)
dev_err(&port->dev, "Error registering port device, "
@@ -1090,7 +1081,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
struct usb_serial_port *port;
usb_serial_console_disconnect(serial);
- dbg ("%s", __FUNCTION__);
+ dbg ("%s", __func__);
mutex_lock(&serial->disc_mutex);
usb_set_intfdata (interface, NULL);
@@ -1174,7 +1165,7 @@ static int __init usb_serial_init(void)
result = bus_register(&usb_serial_bus_type);
if (result) {
- err("%s - registering bus driver failed", __FUNCTION__);
+ err("%s - registering bus driver failed", __func__);
goto exit_bus;
}
@@ -1188,24 +1179,26 @@ static int __init usb_serial_init(void)
usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ usb_serial_tty_driver->init_termios.c_ispeed = 9600;
+ usb_serial_tty_driver->init_termios.c_ospeed = 9600;
tty_set_operations(usb_serial_tty_driver, &serial_ops);
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
- err("%s - tty_register_driver failed", __FUNCTION__);
+ err("%s - tty_register_driver failed", __func__);
goto exit_reg_driver;
}
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
- err("%s - usb_register failed", __FUNCTION__);
+ err("%s - usb_register failed", __func__);
goto exit_tty;
}
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
- err("%s - registering generic driver failed", __FUNCTION__);
+ err("%s - registering generic driver failed", __func__);
goto exit_generic;
}
@@ -1223,7 +1216,7 @@ exit_reg_driver:
bus_unregister(&usb_serial_bus_type);
exit_bus:
- err ("%s - returning with error %d", __FUNCTION__, result);
+ err ("%s - returning with error %d", __func__, result);
put_tty_driver(usb_serial_tty_driver);
return result;
}
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 257a5e436873..f9fc926b56d8 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -35,9 +35,6 @@ static struct usb_serial_driver debug_device = {
.name = "debug",
},
.id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
};
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index c2b01f7c3197..5fc20122145f 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -189,9 +189,6 @@ static struct usb_serial_driver handspring_device = {
.description = "Handspring Visor / Palm OS",
.usb_driver = &visor_driver,
.id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 2,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 2,
.open = visor_open,
.close = visor_close,
@@ -219,9 +216,6 @@ static struct usb_serial_driver clie_5_device = {
.description = "Sony Clie 5.0",
.usb_driver = &visor_driver,
.id_table = clie_id_5_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 2,
- .num_bulk_out = 2,
.num_ports = 2,
.open = visor_open,
.close = visor_close,
@@ -249,9 +243,6 @@ static struct usb_serial_driver clie_3_5_device = {
.description = "Sony Clie 3.5",
.usb_driver = &visor_driver,
.id_table = clie_id_3_5_table,
- .num_interrupt_in = 0,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
.num_ports = 1,
.open = visor_open,
.close = visor_close,
@@ -290,7 +281,7 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (!port->read_urb) {
/* this is needed for some brain dead Sony devices */
@@ -322,16 +313,16 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
goto exit;
}
if (port->interrupt_in_urb) {
- dbg("%s - adding interrupt input for treo", __FUNCTION__);
+ dbg("%s - adding interrupt input for treo", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n",
- __FUNCTION__, result);
+ __func__, result);
}
exit:
return result;
@@ -343,7 +334,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
struct visor_private *priv = usb_get_serial_port_data(port);
unsigned char *transfer_buffer;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/* shutdown our urbs */
usb_kill_urb(port->read_urb);
@@ -379,12 +370,12 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
unsigned long flags;
int status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __FUNCTION__);
+ dbg("%s - write limit hit\n", __func__);
return 0;
}
priv->outstanding_urbs++;
@@ -406,7 +397,7 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
memcpy (buffer, buf, count);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
usb_fill_bulk_urb (urb, serial->dev,
usb_sndbulkpipe (serial->dev,
@@ -418,7 +409,7 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
- __FUNCTION__, status);
+ __func__, status);
count = status;
goto error;
} else {
@@ -449,7 +440,7 @@ static int visor_write_room (struct usb_serial_port *port)
struct visor_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* We really can take anything the user throws at us
@@ -460,7 +451,7 @@ static int visor_write_room (struct usb_serial_port *port)
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
spin_unlock_irqrestore(&priv->lock, flags);
- dbg("%s - write limit hit\n", __FUNCTION__);
+ dbg("%s - write limit hit\n", __func__);
return 0;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -471,13 +462,15 @@ static int visor_write_room (struct usb_serial_port *port)
static int visor_chars_in_buffer (struct usb_serial_port *port)
{
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
/*
* We can't really account for how much data we
* have sent out, but hasn't made it through to the
* device, so just tell the tty layer that everything
* is flushed.
+ *
+ * FIXME: Should walk outstanding_urbs
*/
return 0;
}
@@ -485,7 +478,7 @@ static int visor_chars_in_buffer (struct usb_serial_port *port)
static void visor_write_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct visor_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
unsigned long flags;
@@ -493,11 +486,11 @@ static void visor_write_bulk_callback (struct urb *urb)
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status)
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
spin_lock_irqsave(&priv->lock, flags);
--priv->outstanding_urbs;
@@ -509,7 +502,7 @@ static void visor_write_bulk_callback (struct urb *urb)
static void visor_read_bulk_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct visor_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -517,15 +510,15 @@ static void visor_read_bulk_callback (struct urb *urb)
int result;
int available_room;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -551,7 +544,7 @@ static void visor_read_bulk_callback (struct urb *urb)
visor_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
} else {
priv->actually_throttled = 1;
}
@@ -560,7 +553,7 @@ static void visor_read_bulk_callback (struct urb *urb)
static void visor_read_int_callback (struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
int status = urb->status;
int result;
@@ -573,11 +566,11 @@ static void visor_read_int_callback (struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, status);
+ __func__, status);
goto exit;
}
@@ -588,14 +581,14 @@ static void visor_read_int_callback (struct urb *urb)
* Rumor has it this endpoint is used to notify when data
* is ready to be read from the bulk ones.
*/
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, urb->transfer_buffer);
exit:
result = usb_submit_urb (urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - Error %d submitting interrupt urb\n",
- __FUNCTION__, result);
+ __func__, result);
}
static void visor_throttle (struct usb_serial_port *port)
@@ -603,7 +596,7 @@ static void visor_throttle (struct usb_serial_port *port)
struct visor_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = 1;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -616,7 +609,7 @@ static void visor_unthrottle (struct usb_serial_port *port)
unsigned long flags;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = 0;
priv->actually_throttled = 0;
@@ -625,7 +618,7 @@ static void visor_unthrottle (struct usb_serial_port *port)
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __func__, result);
}
static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_id *id)
@@ -638,11 +631,11 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
int i;
int num_ports = 0;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
transfer_buffer = kmalloc (sizeof (*connection_info), GFP_KERNEL);
if (!transfer_buffer) {
- dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __FUNCTION__,
+ dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
sizeof(*connection_info));
return -ENOMEM;
}
@@ -655,7 +648,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
sizeof(*connection_info), 300);
if (retval < 0) {
dev_err(dev, "%s - error %d getting connection information\n",
- __FUNCTION__, retval);
+ __func__, retval);
goto exit;
}
@@ -715,7 +708,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
0x02, 300);
if (retval < 0)
dev_err(dev, "%s - error %d getting bytes available request\n",
- __FUNCTION__, retval);
+ __func__, retval);
retval = 0;
exit:
@@ -731,11 +724,11 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i
unsigned char *transfer_buffer;
int retval;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
transfer_buffer = kmalloc (sizeof (*connection_info), GFP_KERNEL);
if (!transfer_buffer) {
- dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __FUNCTION__,
+ dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
sizeof(*connection_info));
return -ENOMEM;
}
@@ -747,9 +740,9 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i
sizeof (*connection_info), 300);
if (retval < 0)
dev_err(dev, "%s - error %d getting connection info\n",
- __FUNCTION__, retval);
+ __func__, retval);
else
- usb_serial_debug_data(debug, &serial->dev->dev, __FUNCTION__,
+ usb_serial_debug_data(debug, &serial->dev->dev, __func__,
retval, transfer_buffer);
kfree (transfer_buffer);
@@ -762,7 +755,7 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id *i
int retval = 0;
int (*startup) (struct usb_serial *serial, const struct usb_device_id *id);
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
err("active config #%d != 1 ??",
@@ -816,7 +809,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
int result;
u8 data;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/*
* Note that PEG-300 series devices expect the following two calls.
@@ -827,11 +820,11 @@ static int clie_3_5_startup (struct usb_serial *serial)
USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
0, 0, &data, 1, 3000);
if (result < 0) {
- dev_err(dev, "%s: get config number failed: %d\n", __FUNCTION__, result);
+ dev_err(dev, "%s: get config number failed: %d\n", __func__, result);
return result;
}
if (result != 1) {
- dev_err(dev, "%s: get config number bad return length: %d\n", __FUNCTION__, result);
+ dev_err(dev, "%s: get config number bad return length: %d\n", __func__, result);
return -EIO;
}
@@ -841,11 +834,11 @@ static int clie_3_5_startup (struct usb_serial *serial)
USB_DIR_IN | USB_RECIP_INTERFACE,
0, 0, &data, 1, 3000);
if (result < 0) {
- dev_err(dev, "%s: get interface number failed: %d\n", __FUNCTION__, result);
+ dev_err(dev, "%s: get interface number failed: %d\n", __func__, result);
return result;
}
if (result != 1) {
- dev_err(dev, "%s: get interface number bad return length: %d\n", __FUNCTION__, result);
+ dev_err(dev, "%s: get interface number bad return length: %d\n", __func__, result);
return -EIO;
}
@@ -863,7 +856,7 @@ static int treo_attach (struct usb_serial *serial)
(serial->num_interrupt_in == 0))
goto generic_startup;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/*
* It appears that Treos and Kyoceras want to use the
@@ -894,7 +887,7 @@ generic_startup:
static int clie_5_attach (struct usb_serial *serial)
{
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* TH55 registers 2 ports.
Communication in from the UX50/TH55 uses bulk_in_endpointAddress from port 0
@@ -918,7 +911,7 @@ static void visor_shutdown (struct usb_serial *serial)
struct visor_private *priv;
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
for (i = 0; i < serial->num_ports; i++) {
priv = usb_get_serial_port_data(serial->port[i]);
@@ -931,7 +924,7 @@ static void visor_shutdown (struct usb_serial *serial)
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
- dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
return -ENOIOCTLCMD;
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 38726ef3132b..e96bf8663ffc 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -164,9 +164,6 @@ static struct usb_serial_driver whiteheat_fake_device = {
.description = "Connect Tech - WhiteHEAT - (prerenumeration)",
.usb_driver = &whiteheat_driver,
.id_table = id_table_prerenumeration,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.probe = whiteheat_firmware_download,
.attach = whiteheat_firmware_attach,
@@ -180,9 +177,6 @@ static struct usb_serial_driver whiteheat_device = {
.description = "Connect Tech - WhiteHEAT",
.usb_driver = &whiteheat_driver,
.id_table = id_table_std,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
.num_ports = 4,
.attach = whiteheat_attach,
.shutdown = whiteheat_shutdown,
@@ -225,7 +219,7 @@ struct whiteheat_urb_wrap {
struct whiteheat_private {
spinlock_t lock;
__u8 flags;
- __u8 mcr;
+ __u8 mcr; /* FIXME: no locking on mcr */
struct list_head rx_urbs_free;
struct list_head rx_urbs_submitted;
struct list_head rx_urb_q;
@@ -288,7 +282,7 @@ static int whiteheat_firmware_download (struct usb_serial *serial, const struct
int response;
const struct whiteheat_hex_record *record;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
response = ezusb_set_reset (serial, 1);
@@ -298,7 +292,7 @@ static int whiteheat_firmware_download (struct usb_serial *serial, const struct
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",
- __FUNCTION__, response, record->address, record->data, record->data_size);
+ __func__, response, record->address, record->data, record->data_size);
break;
}
++record;
@@ -315,7 +309,7 @@ static int whiteheat_firmware_download (struct usb_serial *serial, const struct
(unsigned char *)record->data, record->data_size, 0xa3);
if (response < 0) {
err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)",
- __FUNCTION__, response, record->address, record->data, record->data_size);
+ __func__, response, record->address, record->data, record->data_size);
break;
}
++record;
@@ -329,7 +323,7 @@ static int whiteheat_firmware_download (struct usb_serial *serial, const struct
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)",
- __FUNCTION__, response, record->address, record->data, record->data_size);
+ __func__, response, record->address, record->data, record->data_size);
break;
}
++record;
@@ -567,7 +561,7 @@ static void whiteheat_shutdown (struct usb_serial *serial)
struct list_head *tmp2;
int i;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
/* free up our private data for our command port */
command_port = serial->port[COMMAND_PORT];
@@ -604,7 +598,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
int retval = 0;
struct ktermios old_term;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
retval = start_command_port(port->serial);
if (retval)
@@ -637,14 +631,14 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
/* Start reading from the device */
retval = start_port_read(port);
if (retval) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
+ err("%s - failed submitting read urb, error %d", __func__, retval);
firm_close(port);
stop_command_port(port->serial);
goto exit;
}
exit:
- dbg("%s - exit, retval = %d", __FUNCTION__, retval);
+ dbg("%s - exit, retval = %d", __func__, retval);
return retval;
}
@@ -657,7 +651,7 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
struct list_head *tmp;
struct list_head *tmp2;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
mutex_lock(&port->serial->disc_mutex);
/* filp is NULL when called from usb_serial_disconnect */
@@ -732,10 +726,10 @@ static int whiteheat_write(struct usb_serial_port *port, const unsigned char *bu
unsigned long flags;
struct list_head *tmp;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (count == 0) {
- dbg("%s - write request of 0 bytes", __FUNCTION__);
+ dbg("%s - write request of 0 bytes", __func__);
return (0);
}
@@ -754,13 +748,13 @@ static int whiteheat_write(struct usb_serial_port *port, const unsigned char *bu
bytes = (count > port->bulk_out_size) ? port->bulk_out_size : count;
memcpy (urb->transfer_buffer, buf + sent, bytes);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, bytes, urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __func__, bytes, urb->transfer_buffer);
urb->dev = serial->dev;
urb->transfer_buffer_length = bytes;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ err("%s - failed submitting write urb, error %d", __func__, result);
sent = result;
spin_lock_irqsave(&info->lock, flags);
list_add(tmp, &info->tx_urbs_free);
@@ -786,7 +780,7 @@ static int whiteheat_write_room(struct usb_serial_port *port)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&info->lock, flags);
list_for_each(tmp, &info->tx_urbs_free)
@@ -794,7 +788,7 @@ static int whiteheat_write_room(struct usb_serial_port *port)
spin_unlock_irqrestore(&info->lock, flags);
room *= port->bulk_out_size;
- dbg("%s - returns %d", __FUNCTION__, room);
+ dbg("%s - returns %d", __func__, room);
return (room);
}
@@ -804,7 +798,7 @@ static int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file)
struct whiteheat_private *info = usb_get_serial_port_data(port);
unsigned int modem_signals = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
firm_get_dtr_rts(port);
if (info->mcr & UART_MCR_DTR)
@@ -821,7 +815,7 @@ static int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file,
{
struct whiteheat_private *info = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
@@ -844,7 +838,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un
struct serial_struct serstruct;
void __user *user_arg = (void __user *)arg;
- dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+ dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
switch (cmd) {
case TIOCGSERIAL:
@@ -886,7 +880,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un
static void whiteheat_set_termios(struct usb_serial_port *port, struct ktermios *old_termios)
{
- dbg("%s -port %d", __FUNCTION__, port->number);
+ dbg("%s -port %d", __func__, port->number);
firm_setup_port(port);
}
@@ -904,7 +898,7 @@ static int whiteheat_chars_in_buffer(struct usb_serial_port *port)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&info->lock, flags);
list_for_each(tmp, &info->tx_urbs_submitted) {
@@ -913,7 +907,7 @@ static int whiteheat_chars_in_buffer(struct usb_serial_port *port)
}
spin_unlock_irqrestore(&info->lock, flags);
- dbg ("%s - returns %d", __FUNCTION__, chars);
+ dbg ("%s - returns %d", __func__, chars);
return chars;
}
@@ -923,7 +917,7 @@ static void whiteheat_throttle (struct usb_serial_port *port)
struct whiteheat_private *info = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&info->lock, flags);
info->flags |= THROTTLED;
@@ -939,7 +933,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port)
int actually_throttled;
unsigned long flags;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&info->lock, flags);
actually_throttled = info->flags & ACTUALLY_THROTTLED;
@@ -960,7 +954,7 @@ static void command_port_write_callback(struct urb *urb)
{
int status = urb->status;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
if (status) {
dbg("nonzero urb status: %d", status);
@@ -971,28 +965,28 @@ static void command_port_write_callback(struct urb *urb)
static void command_port_read_callback(struct urb *urb)
{
- struct usb_serial_port *command_port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *command_port = urb->context;
struct whiteheat_command_private *command_info;
int status = urb->status;
unsigned char *data = urb->transfer_buffer;
int result;
- dbg("%s", __FUNCTION__);
+ dbg("%s", __func__);
command_info = usb_get_serial_port_data(command_port);
if (!command_info) {
- dbg ("%s - command_info is NULL, exiting.", __FUNCTION__);
+ dbg ("%s - command_info is NULL, exiting.", __func__);
return;
}
if (status) {
- dbg("%s - nonzero urb status: %d", __FUNCTION__, status);
+ dbg("%s - nonzero urb status: %d", __func__, status);
if (status != -ENOENT)
command_info->command_finished = WHITEHEAT_CMD_FAILURE;
wake_up(&command_info->wait_command);
return;
}
- usb_serial_debug_data(debug, &command_port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &command_port->dev, __func__, urb->actual_length, data);
if (data[0] == WHITEHEAT_CMD_COMPLETE) {
command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
@@ -1002,38 +996,38 @@ static void command_port_read_callback(struct urb *urb)
wake_up(&command_info->wait_command);
} else if (data[0] == WHITEHEAT_EVENT) {
/* These are unsolicited reports from the firmware, hence no waiting command to wakeup */
- dbg("%s - event received", __FUNCTION__);
+ dbg("%s - event received", __func__);
} else if (data[0] == WHITEHEAT_GET_DTR_RTS) {
memcpy(command_info->result_buffer, &data[1], urb->actual_length - 1);
command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
wake_up(&command_info->wait_command);
} else {
- dbg("%s - bad reply from firmware", __FUNCTION__);
+ dbg("%s - bad reply from firmware", __func__);
}
/* Continue trying to always read */
command_port->read_urb->dev = command_port->serial->dev;
result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
if (result)
- dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ dbg("%s - failed resubmitting read urb, error %d", __func__, result);
}
static void whiteheat_read_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct whiteheat_urb_wrap *wrap;
unsigned char *data = urb->transfer_buffer;
struct whiteheat_private *info = usb_get_serial_port_data(port);
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock(&info->lock);
wrap = urb_to_wrap(urb, &info->rx_urbs_submitted);
if (!wrap) {
spin_unlock(&info->lock);
- err("%s - Not my urb!", __FUNCTION__);
+ err("%s - Not my urb!", __func__);
return;
}
list_del(&wrap->list);
@@ -1041,14 +1035,14 @@ static void whiteheat_read_callback(struct urb *urb)
if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
spin_lock(&info->lock);
list_add(&wrap->list, &info->rx_urbs_free);
spin_unlock(&info->lock);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
spin_lock(&info->lock);
list_add_tail(&wrap->list, &info->rx_urb_q);
@@ -1065,18 +1059,18 @@ static void whiteheat_read_callback(struct urb *urb)
static void whiteheat_write_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial_port *port = urb->context;
struct whiteheat_private *info = usb_get_serial_port_data(port);
struct whiteheat_urb_wrap *wrap;
int status = urb->status;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __func__, port->number);
spin_lock(&info->lock);
wrap = urb_to_wrap(urb, &info->tx_urbs_submitted);
if (!wrap) {
spin_unlock(&info->lock);
- err("%s - Not my urb!", __FUNCTION__);
+ err("%s - Not my urb!", __func__);
return;
}
list_move(&wrap->list, &info->tx_urbs_free);
@@ -1084,7 +1078,7 @@ static void whiteheat_write_callback(struct urb *urb)
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
+ __func__, status);
return;
}
@@ -1104,7 +1098,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *d
int retval = 0;
int t;
- dbg("%s - command %d", __FUNCTION__, command);
+ dbg("%s - command %d", __func__, command);
command_port = port->serial->port[COMMAND_PORT];
command_info = usb_get_serial_port_data(command_port);
@@ -1118,7 +1112,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *d
command_port->write_urb->dev = port->serial->dev;
retval = usb_submit_urb (command_port->write_urb, GFP_NOIO);
if (retval) {
- dbg("%s - submit urb failed", __FUNCTION__);
+ dbg("%s - submit urb failed", __func__);
goto exit;
}
@@ -1129,19 +1123,19 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *d
usb_kill_urb(command_port->write_urb);
if (command_info->command_finished == false) {
- dbg("%s - command timed out.", __FUNCTION__);
+ dbg("%s - command timed out.", __func__);
retval = -ETIMEDOUT;
goto exit;
}
if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) {
- dbg("%s - command failed.", __FUNCTION__);
+ dbg("%s - command failed.", __func__);
retval = -EIO;
goto exit;
}
if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) {
- dbg("%s - command completed.", __FUNCTION__);
+ dbg("%s - command completed.", __func__);
switch (command) {
case WHITEHEAT_GET_DTR_RTS:
info = usb_get_serial_port_data(port);
@@ -1186,7 +1180,7 @@ static int firm_setup_port(struct usb_serial_port *port) {
default:
case CS8: port_settings.bits = 8; break;
}
- dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits);
+ dbg("%s - data bits = %d", __func__, port_settings.bits);
/* determine the parity */
if (cflag & PARENB)
@@ -1202,21 +1196,21 @@ static int firm_setup_port(struct usb_serial_port *port) {
port_settings.parity = WHITEHEAT_PAR_EVEN;
else
port_settings.parity = WHITEHEAT_PAR_NONE;
- dbg("%s - parity = %c", __FUNCTION__, port_settings.parity);
+ dbg("%s - parity = %c", __func__, port_settings.parity);
/* figure out the stop bits requested */
if (cflag & CSTOPB)
port_settings.stop = 2;
else
port_settings.stop = 1;
- dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop);
+ dbg("%s - stop bits = %d", __func__, port_settings.stop);
/* figure out the flow control settings */
if (cflag & CRTSCTS)
port_settings.hflow = (WHITEHEAT_HFLOW_CTS | WHITEHEAT_HFLOW_RTS);
else
port_settings.hflow = WHITEHEAT_HFLOW_NONE;
- dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__,
+ dbg("%s - hardware flow control = %s %s %s %s", __func__,
(port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "",
(port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "",
(port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "",
@@ -1227,15 +1221,15 @@ static int firm_setup_port(struct usb_serial_port *port) {
port_settings.sflow = WHITEHEAT_SFLOW_RXTX;
else
port_settings.sflow = WHITEHEAT_SFLOW_NONE;
- dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow);
+ dbg("%s - software flow control = %c", __func__, port_settings.sflow);
port_settings.xon = START_CHAR(port->tty);
port_settings.xoff = STOP_CHAR(port->tty);
- dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff);
+ dbg("%s - XON = %2x, XOFF = %2x", __func__, port_settings.xon, port_settings.xoff);
/* get the baud rate wanted */
port_settings.baud = tty_get_baud_rate(port->tty);
- dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud);
+ dbg("%s - baud rate = %d", __func__, port_settings.baud);
/* fixme: should set validated settings */
tty_encode_baud_rate(port->tty, port_settings.baud, port_settings.baud);
@@ -1318,7 +1312,7 @@ static int start_command_port(struct usb_serial *serial)
command_port->read_urb->dev = serial->dev;
retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
if (retval) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
+ err("%s - failed submitting read urb, error %d", __func__, retval);
goto exit;
}
}
@@ -1454,7 +1448,7 @@ static void rx_data_softint(struct work_struct *work)
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ err("%s - failed resubmitting read urb, error %d", __func__, result);
spin_lock_irqsave(&info->lock, flags);
list_add(tmp, &info->rx_urbs_free);
continue;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 7e53333be013..0f6d234d699b 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -32,8 +32,8 @@ config USB_STORAGE_DEBUG
verbose debugging messages.
config USB_STORAGE_DATAFAB
- bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ bool "Datafab Compact Flash Reader support"
+ depends on USB_STORAGE
help
Support for certain Datafab CompactFlash readers.
Datafab has a web page at <http://www.datafabusa.com/>.
@@ -69,8 +69,8 @@ config USB_STORAGE_DPCM
There is a web page at <http://www.ziocorp.com/products/>.
config USB_STORAGE_USBAT
- bool "USBAT/USBAT02-based storage support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ bool "USBAT/USBAT02-based storage support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support storage devices
based on the SCM/Shuttle USBAT/USBAT02 processors.
@@ -90,30 +90,30 @@ config USB_STORAGE_USBAT
- Sandisk ImageMate SDDR-05b
config USB_STORAGE_SDDR09
- bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ bool "SanDisk SDDR-09 (and other SmartMedia) support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
Also works for the Microtech Zio! SmartMedia reader.
config USB_STORAGE_SDDR55
- bool "SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ bool "SanDisk SDDR-55 SmartMedia support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-55
SmartMedia reader in the USB Mass Storage driver.
config USB_STORAGE_JUMPSHOT
- bool "Lexar Jumpshot Compact Flash Reader (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ bool "Lexar Jumpshot Compact Flash Reader"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Lexar Jumpshot
USB CompactFlash reader.
config USB_STORAGE_ALAUDA
- bool "Olympus MAUSB-10/Fuji DPC-R1 support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ bool "Olympus MAUSB-10/Fuji DPC-R1 support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Olympus MAUSB-10
and Fujifilm DPC-R1 USB Card reader/writer devices.
@@ -122,8 +122,8 @@ config USB_STORAGE_ALAUDA
XD and SmartMedia cards.
config USB_STORAGE_ONETOUCH
- bool "Support OneTouch Button on Maxtor Hard Drives (EXPERIMENTAL)"
- depends on USB_STORAGE && INPUT_EVDEV && EXPERIMENTAL && !PM
+ bool "Support OneTouch Button on Maxtor Hard Drives"
+ depends on USB_STORAGE && INPUT_EVDEV
help
Say Y here to include additional code to support the Maxtor OneTouch
USB hard drive's onetouch button.
@@ -145,6 +145,17 @@ config USB_STORAGE_KARMA
on the resulting scsi device node returns the Karma to normal
operation.
+config USB_STORAGE_CYPRESS_ATACB
+ bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+ depends on USB_STORAGE
+ ---help---
+ Say Y here if you want to use SAT (ata pass through) on devices based
+ on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+ to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+ If you say no here your device will still work with the standard usb
+ mass storage class.
+
config USB_LIBUSUAL
bool "The shared table of common (or usual) storage devices"
depends on USB
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 023969b4385b..4c596c766c53 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -21,6 +21,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
new file mode 100644
index 000000000000..d88824b3511c
--- /dev/null
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -0,0 +1,200 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ * on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.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, 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 <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+ unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+ if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+ usb_stor_transparent_scsi_command(srb, us);
+ return;
+ }
+
+ memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+ memset(srb->cmnd, 0, sizeof(srb->cmnd));
+
+ /* check if we support the command */
+ if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+ goto invalid_fld;
+ /* check protocol */
+ switch((save_cmnd[1] >> 1) & 0xf) {
+ case 3: /*no DATA */
+ case 4: /* PIO in */
+ case 5: /* PIO out */
+ break;
+ default:
+ goto invalid_fld;
+ }
+
+ /* first build the ATACB command */
+ srb->cmd_len = 16;
+
+ srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
+ this value can change, but most(all ?) manufacturers
+ keep the cypress default : 0x24 */
+ srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
+
+ srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
+ lba high, device, command are valid */
+ srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
+
+ if (save_cmnd[0] == ATA_16) {
+ srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
+ srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
+ srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
+ srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
+ srb->cmnd[10] = save_cmnd[12]; /* lba high */
+ srb->cmnd[11] = save_cmnd[13]; /* device */
+ srb->cmnd[12] = save_cmnd[14]; /* command */
+
+ if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+ /* this could be supported by atacb2 */
+ if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+ || save_cmnd[11])
+ goto invalid_fld;
+ }
+ }
+ else { /* ATA12 */
+ srb->cmnd[ 6] = save_cmnd[3]; /* features */
+ srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
+ srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
+ srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
+ srb->cmnd[10] = save_cmnd[7]; /* lba high */
+ srb->cmnd[11] = save_cmnd[8]; /* device */
+ srb->cmnd[12] = save_cmnd[9]; /* command */
+
+ }
+ /* Filter SET_FEATURES - XFER MODE command */
+ if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+ && (srb->cmnd[6] == SETFEATURES_XFER))
+ goto invalid_fld;
+
+ if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+ srb->cmnd[2] |= (1<<7); /* set IdentifyPacketDevice for these cmds */
+
+
+ usb_stor_transparent_scsi_command(srb, us);
+
+ /* if the device doesn't support ATACB
+ */
+ if (srb->result == SAM_STAT_CHECK_CONDITION &&
+ memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+ sizeof(usb_stor_sense_invalidCDB)) == 0) {
+ US_DEBUGP("cypress atacb not supported ???\n");
+ goto end;
+ }
+
+ /* if ck_cond flags is set, and there wasn't critical error,
+ * build the special sense
+ */
+ if ((srb->result != (DID_ERROR << 16) &&
+ srb->result != (DID_ABORT << 16)) &&
+ save_cmnd[2] & 0x20) {
+ struct scsi_eh_save ses;
+ unsigned char regs[8];
+ unsigned char *sb = srb->sense_buffer;
+ unsigned char *desc = sb + 8;
+ int tmp_result;
+
+ /* build the command for
+ * reading the ATA registers */
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
+ srb->sdb.length = sizeof(regs);
+ sg_init_one(&ses.sense_sgl, regs, srb->sdb.length);
+ srb->sdb.table.sgl = &ses.sense_sgl;
+ srb->sc_data_direction = DMA_FROM_DEVICE;
+ srb->sdb.table.nents = 1;
+ /* we use the same command as before, but we set
+ * the read taskfile bit, for not executing atacb command,
+ * but reading register selected in srb->cmnd[4]
+ */
+ srb->cmnd[2] = 1;
+
+ usb_stor_transparent_scsi_command(srb, us);
+ tmp_result = srb->result;
+ scsi_eh_restore_cmnd(srb, &ses);
+ /* we fail to get registers, report invalid command */
+ if (tmp_result != SAM_STAT_GOOD)
+ goto invalid_fld;
+
+ /* build the sense */
+ memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+ /* set sk, asc for a good command */
+ sb[1] = RECOVERED_ERROR;
+ sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+ sb[3] = 0x1D;
+
+ /* XXX we should generate sk, asc, ascq from status and error
+ * regs
+ * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+ * and ata_to_sense_error from libata.
+ */
+
+ /* Sense data is current and format is descriptor. */
+ sb[0] = 0x72;
+ desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+ /* set length of additional sense data */
+ sb[7] = 14;
+ desc[1] = 12;
+
+ /* Copy registers into sense buffer. */
+ desc[ 2] = 0x00;
+ desc[ 3] = regs[1]; /* features */
+ desc[ 5] = regs[2]; /* sector count */
+ desc[ 7] = regs[3]; /* lba low */
+ desc[ 9] = regs[4]; /* lba med */
+ desc[11] = regs[5]; /* lba high */
+ desc[12] = regs[6]; /* device */
+ desc[13] = regs[7]; /* command */
+
+ srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ }
+ goto end;
+invalid_fld:
+ srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ memcpy(srb->sense_buffer,
+ usb_stor_sense_invalidCDB,
+ sizeof(usb_stor_sense_invalidCDB));
+end:
+ memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+ if (srb->cmnd[0] == ATA_12)
+ srb->cmd_len = 12;
+}
diff --git a/drivers/usb/storage/cypress_atacb.h b/drivers/usb/storage/cypress_atacb.h
new file mode 100644
index 000000000000..fbada898d56b
--- /dev/null
+++ b/drivers/usb/storage/cypress_atacb.h
@@ -0,0 +1,25 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ * on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.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, 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 _CYPRESS_ATACB_H_
+#define _CYPRESS_ATACB_H_
+extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*);
+#endif
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index 55b952084f0c..a28d49122e7a 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -9,6 +9,7 @@
#include <linux/usb_usual.h>
#include <linux/vmalloc.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
/*
*/
@@ -30,7 +31,7 @@ static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS);
#define BIAS_NAME_SIZE (sizeof("usb-storage"))
static const char *bias_names[3] = { "none", "usb-storage", "ub" };
-static struct semaphore usu_init_notify;
+static DEFINE_MUTEX(usu_probe_mutex);
static DECLARE_COMPLETION(usu_end_notify);
static atomic_t total_threads = ATOMIC_INIT(0);
@@ -178,10 +179,7 @@ static int usu_probe_thread(void *arg)
int rc;
unsigned long flags;
- /* A completion does not work here because it's counted. */
- down(&usu_init_notify);
- up(&usu_init_notify);
-
+ mutex_lock(&usu_probe_mutex);
rc = request_module(bias_names[type]);
spin_lock_irqsave(&usu_lock, flags);
if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) {
@@ -194,6 +192,7 @@ static int usu_probe_thread(void *arg)
}
st->fls &= ~USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
+ mutex_unlock(&usu_probe_mutex);
complete_and_exit(&usu_end_notify, 0);
}
@@ -204,10 +203,9 @@ static int __init usb_usual_init(void)
{
int rc;
- sema_init(&usu_init_notify, 0);
-
+ mutex_lock(&usu_probe_mutex);
rc = usb_register(&usu_driver);
- up(&usu_init_notify);
+ mutex_unlock(&usu_probe_mutex);
return rc;
}
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 8c1e2954f3b9..3fcde9f0fa5f 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -73,6 +73,7 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_alloc (struct scsi_device *sdev)
{
struct us_data *us = host_to_us(sdev->host);
+ struct usb_host_endpoint *bulk_in_ep;
/*
* Set the INQUIRY transfer length to 36. We don't use any of
@@ -84,12 +85,13 @@ static int slave_alloc (struct scsi_device *sdev)
/* Scatter-gather buffers (all but the last) must have a length
* divisible by the bulk maxpacket size. Otherwise a data packet
* would end up being short, causing a premature end to the data
- * transfer. Since high-speed bulk pipes have a maxpacket size
- * of 512, we'll use that as the scsi device queue's DMA alignment
- * mask. Guaranteeing proper alignment of the first buffer will
- * have the desired effect because, except at the beginning and
- * the end, scatter-gather buffers follow page boundaries. */
- blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+ * transfer. We'll use the maxpacket value of the bulk-IN pipe
+ * to set the SCSI device queue's DMA alignment mask.
+ */
+ bulk_in_ep = us->pusb_dev->ep_in[usb_pipeendpoint(us->recv_bulk_pipe)];
+ blk_queue_update_dma_alignment(sdev->request_queue,
+ le16_to_cpu(bulk_in_ep->desc.wMaxPacketSize) - 1);
+ /* wMaxPacketSize must be a power of 2 */
/*
* The UFI spec treates the Peripheral Qualifier bits in an
@@ -132,7 +134,7 @@ static int slave_configure(struct scsi_device *sdev)
/* Disk-type devices use MODE SENSE(6) if the protocol
* (SubClass) is Transparent SCSI, otherwise they use
* MODE SENSE(10). */
- if (us->subclass != US_SC_SCSI)
+ if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB)
sdev->use_10_for_ms = 1;
/* Many disks only accept MODE SENSE transfer lengths of
@@ -226,12 +228,12 @@ static int queuecommand(struct scsi_cmnd *srb,
{
struct us_data *us = host_to_us(srb->device->host);
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
/* check for state-transition errors */
if (us->srb != NULL) {
printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
- __FUNCTION__, us->srb);
+ __func__, us->srb);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -260,7 +262,7 @@ static int command_abort(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock. */
@@ -297,7 +299,7 @@ static int device_reset(struct scsi_cmnd *srb)
struct us_data *us = host_to_us(srb->device->host);
int result;
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
/* lock the device pointers and do the reset */
mutex_lock(&(us->dev_mutex));
@@ -313,7 +315,7 @@ static int bus_reset(struct scsi_cmnd *srb)
struct us_data *us = host_to_us(srb->device->host);
int result;
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
result = usb_stor_port_reset(us);
return result < 0 ? FAILED : SUCCESS;
}
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index bdd4334bed5a..6610d2dd1e7f 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -110,7 +110,7 @@
*/
static void usb_stor_blocking_completion(struct urb *urb)
{
- struct completion *urb_done_ptr = (struct completion *)urb->context;
+ struct completion *urb_done_ptr = urb->context;
complete(urb_done_ptr);
}
@@ -198,7 +198,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
int status;
US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
- __FUNCTION__, request, requesttype,
+ __func__, request, requesttype,
value, index, size);
/* fill in the devrequest structure */
@@ -250,7 +250,7 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), 0);
- US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
+ US_DEBUGP("%s: result = %d\n", __func__, result);
return result;
}
@@ -332,7 +332,7 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
int result;
US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
- __FUNCTION__, request, requesttype,
+ __func__, request, requesttype,
value, index, size);
/* fill in the devrequest structure */
@@ -366,7 +366,7 @@ static int usb_stor_intr_transfer(struct us_data *us, void *buf,
unsigned int pipe = us->recv_intr_pipe;
unsigned int maxp;
- US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
+ US_DEBUGP("%s: xfer %u bytes\n", __func__, length);
/* calculate the max packet size */
maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
@@ -393,7 +393,7 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
{
int result;
- US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
+ US_DEBUGP("%s: xfer %u bytes\n", __func__, length);
/* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
@@ -424,7 +424,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */
- US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__,
+ US_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
length, num_sg);
result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, GFP_NOIO);
@@ -603,7 +603,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
/* FIXME: we must do the protocol translation here */
- if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+ if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
+ us->subclass == US_SC_CYP_ATACB)
srb->cmd_len = 6;
else
srb->cmd_len = 12;
@@ -700,7 +701,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Stop the current URB transfer */
void usb_stor_stop_transport(struct us_data *us)
{
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
/* If the state machine is blocked waiting for an URB,
* let's wake it up. The test_and_clear_bit() call
@@ -1134,7 +1135,7 @@ static int usb_stor_reset_common(struct us_data *us,
int usb_stor_CB_reset(struct us_data *us)
{
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE);
us->iobuf[0] = SEND_DIAGNOSTIC;
@@ -1149,7 +1150,7 @@ int usb_stor_CB_reset(struct us_data *us)
*/
int usb_stor_Bulk_reset(struct us_data *us)
{
- US_DEBUGP("%s called\n", __FUNCTION__);
+ US_DEBUGP("%s called\n", __func__);
return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 91252075e6e1..732bf52a775e 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1719,6 +1719,14 @@ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_CAPACITY_HEURISTICS),
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999,
+ "Cypress",
+ "Cypress AT2LP",
+ US_SC_CYP_ATACB, US_PR_BULK, NULL,
+ 0),
+#endif
+
/* Control/Bulk transport for all SubClass values */
USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index ac6114eea0c3..a856effad3bd 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -101,6 +101,9 @@
#ifdef CONFIG_USB_STORAGE_KARMA
#include "karma.h"
#endif
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+#include "cypress_atacb.h"
+#endif
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -187,7 +190,7 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __FUNCTION__);
+ US_DEBUGP("%s\n", __func__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
@@ -204,7 +207,7 @@ static int storage_resume(struct usb_interface *iface)
mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __FUNCTION__);
+ US_DEBUGP("%s\n", __func__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
@@ -216,7 +219,7 @@ static int storage_reset_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
+ US_DEBUGP("%s\n", __func__);
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset(us);
@@ -237,7 +240,7 @@ static int storage_pre_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
+ US_DEBUGP("%s\n", __func__);
/* Make sure no command runs during the reset */
mutex_lock(&us->dev_mutex);
@@ -248,7 +251,7 @@ static int storage_post_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
+ US_DEBUGP("%s\n", __func__);
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset(us);
@@ -434,7 +437,7 @@ SkipForAbort:
/* Associate our private data with the USB device */
static int associate_dev(struct us_data *us, struct usb_interface *intf)
{
- US_DEBUGP("-- %s\n", __FUNCTION__);
+ US_DEBUGP("-- %s\n", __func__);
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
@@ -708,6 +711,13 @@ static int get_protocol(struct us_data *us)
break;
#endif
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+ case US_SC_CYP_ATACB:
+ us->protocol_name = "Transparent SCSI with Cypress ATACB";
+ us->proto_handler = cypress_atacb_passthrough;
+ break;
+#endif
+
default:
return -EIO;
}
@@ -806,7 +816,7 @@ static int usb_stor_acquire_resources(struct us_data *us)
/* Release all our dynamic resources */
static void usb_stor_release_resources(struct us_data *us)
{
- US_DEBUGP("-- %s\n", __FUNCTION__);
+ US_DEBUGP("-- %s\n", __func__);
/* Tell the control thread to exit. The SCSI host must
* already have been removed so it won't try to queue
@@ -832,7 +842,7 @@ static void usb_stor_release_resources(struct us_data *us)
/* Dissociate from the USB device */
static void dissociate_dev(struct us_data *us)
{
- US_DEBUGP("-- %s\n", __FUNCTION__);
+ US_DEBUGP("-- %s\n", __func__);
kfree(us->sensebuf);
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index c815a40e167f..be76084c8d7e 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -88,7 +88,7 @@ static int skel_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
err ("%s - error, can't find device for minor %d",
- __FUNCTION__, subminor);
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -212,7 +212,7 @@ static void skel_write_bulk_callback(struct urb *urb)
{
struct usb_skel *dev;
- dev = (struct usb_skel *)urb->context;
+ dev = urb->context;
/* sync/async unlink faults aren't errors */
if (urb->status) {
@@ -220,7 +220,7 @@ static void skel_write_bulk_callback(struct urb *urb)
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
err("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __func__, urb->status);
spin_lock(&dev->err_lock);
dev->errors = urb->status;
@@ -301,7 +301,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
retval = usb_submit_urb(urb, GFP_KERNEL);
mutex_unlock(&dev->io_mutex);
if (retval) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
+ err("%s - failed submitting write urb, error %d", __func__, retval);
goto error_unanchor;
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1bd5fb30237d..a576dc261732 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -139,6 +139,30 @@ config FB_SYS_IMAGEBLIT
blitting. This is used by drivers that don't provide their own
(accelerated) version and the framebuffer is in system RAM.
+menuconfig FB_FOREIGN_ENDIAN
+ bool "Framebuffer foreign endianness support"
+ depends on FB
+ ---help---
+ This menu will let you enable support for the framebuffers with
+ non-native endianness (e.g. Little-Endian framebuffer on a
+ Big-Endian machine). Most probably you don't have such hardware,
+ so it's safe to say "n" here.
+
+choice
+ prompt "Choice endianness support"
+ depends on FB_FOREIGN_ENDIAN
+
+config FB_BOTH_ENDIAN
+ bool "Support for Big- and Little-Endian framebuffers"
+
+config FB_BIG_ENDIAN
+ bool "Support for Big-Endian framebuffers only"
+
+config FB_LITTLE_ENDIAN
+ bool "Support for Little-Endian framebuffers only"
+
+endchoice
+
config FB_SYS_FOPS
tristate
depends on FB
@@ -149,6 +173,16 @@ config FB_DEFERRED_IO
depends on FB
default y
+config FB_METRONOME
+ tristate
+ depends on FB
+ depends on FB_DEFERRED_IO
+
+config FB_HECUBA
+ tristate
+ depends on FB
+ depends on FB_DEFERRED_IO
+
config FB_SVGALIB
tristate
depends on FB
@@ -546,7 +580,7 @@ config FB_VGA16
config FB_BF54X_LQ043
tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)"
- depends on FB && (BF54x)
+ depends on FB && (BF54x) && !BF542
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -674,20 +708,18 @@ config FB_IMAC
help
This is the frame buffer device driver for the Intel-based Macintosh
-config FB_HECUBA
- tristate "Hecuba board support"
+config FB_N411
+ tristate "N411 Apollo/Hecuba devkit support"
depends on FB && X86 && MMU
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
+ select FB_HECUBA
help
- This enables support for the Hecuba board. This driver was tested
- with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO
- interface (8 bit data, 4 bit control). If you anticipate using
- this driver, say Y or M; otherwise say N. You must specify the
- GPIO IO address to be used for setting control and data.
+ This enables support for the Apollo display controller in its
+ Hecuba form using the n411 devkit.
config FB_HGA
tristate "Hercules mono graphics support"
@@ -1087,7 +1119,7 @@ config FB_CARILLO_RANCH
This driver supports the LE80578 (Carillo Ranch) board
config FB_INTEL
- tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)"
+ tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)"
depends on FB && EXPERIMENTAL && PCI && X86
select AGP
select AGP_INTEL
@@ -1097,7 +1129,7 @@ config FB_INTEL
select FB_CFB_IMAGEBLIT
help
This driver supports the on-board graphics built in to the Intel
- 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets.
+ 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
Say Y if you have and plan to use such a board.
If you say Y here and want DDC/I2C support you must first say Y to
@@ -1779,6 +1811,16 @@ config FB_MBX_DEBUG
If unsure, say N.
+config FB_FSL_DIU
+ tristate "Freescale DIU framebuffer support"
+ depends on FB && FSL_SOC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select PPC_LIB_RHEAP
+ ---help---
+ Framebuffer driver for the Freescale SoC DIU
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && PXA_SHARPSL
@@ -1893,19 +1935,18 @@ config FB_XILINX
framebuffer. ML300 carries a 640*480 LCD display on the board,
ML403 uses a standard DB15 VGA connector.
-config FB_METRONOME
- tristate "Metronome display controller support"
+config FB_AM200EPD
+ tristate "AM-200 E-Ink EPD devkit support"
depends on FB && ARCH_PXA && MMU
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
+ select FB_METRONOME
help
- This enables support for the Metronome display controller. Tested
- with an E-Ink 800x600 display and Gumstix Connex through an AMLCD
- interface. Please read <file:Documentation/fb/metronomefb.txt>
- for more information.
+ This enables support for the Metronome display controller used on
+ the E-Ink AM-200 EPD devkit.
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
@@ -1930,6 +1971,20 @@ config FB_VIRTUAL
If unsure, say N.
+config XEN_FBDEV_FRONTEND
+ tristate "Xen virtual frame buffer support"
+ depends on FB && XEN
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
+ default y
+ help
+ This driver implements the front-end of the Xen virtual
+ frame buffer driver. It communicates with a back-end
+ in another domain.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/backlight/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 11c0e5e05f21..04bca35403ff 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
# Hardware specific drivers go first
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
+obj-$(CONFIG_FB_AM200EPD) += am200epd.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
@@ -107,6 +108,7 @@ obj-$(CONFIG_FB_METRONOME) += metronomefb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
+obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
@@ -114,6 +116,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_FB_OMAP) += omap/
+obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c
new file mode 100644
index 000000000000..51e26c1f5e8b
--- /dev/null
+++ b/drivers/video/am200epd.c
@@ -0,0 +1,295 @@
+/*
+ * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * 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.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This work was made possible by help and equipment support from E-Ink
+ * Corporation. http://support.eink.com/community
+ *
+ * This driver is written to be used with the Metronome display controller.
+ * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600
+ * Vizplex EPD on a Gumstix board using the Lyre interface board.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+
+#include <video/metronomefb.h>
+
+#include <asm/arch/pxa-regs.h>
+
+/* register offsets for gpio control */
+#define LED_GPIO_PIN 51
+#define STDBY_GPIO_PIN 48
+#define RST_GPIO_PIN 49
+#define RDY_GPIO_PIN 32
+#define ERR_GPIO_PIN 17
+#define PCBPWR_GPIO_PIN 16
+
+#define AF_SEL_GPIO_N 0x3
+#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
+#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
+#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
+#define GPDR1_OFFSET(pin) (pin - 32)
+#define GPCR1_OFFSET(pin) (pin - 32)
+#define GPSR1_OFFSET(pin) (pin - 32)
+#define GPCR0_OFFSET(pin) (pin)
+#define GPSR0_OFFSET(pin) (pin)
+
+static void am200_set_gpio_output(int pin, int val)
+{
+ u8 index;
+
+ index = pin >> 4;
+
+ switch (index) {
+ case 1:
+ if (val)
+ GPSR0 |= (1 << GPSR0_OFFSET(pin));
+ else
+ GPCR0 |= (1 << GPCR0_OFFSET(pin));
+ break;
+ case 2:
+ break;
+ case 3:
+ if (val)
+ GPSR1 |= (1 << GPSR1_OFFSET(pin));
+ else
+ GPCR1 |= (1 << GPCR1_OFFSET(pin));
+ break;
+ default:
+ printk(KERN_ERR "unimplemented\n");
+ }
+}
+
+static void __devinit am200_init_gpio_pin(int pin, int dir)
+{
+ u8 index;
+ /* dir 0 is output, 1 is input
+ - do 2 things here:
+ - set gpio alternate function to standard gpio
+ - set gpio direction to input or output */
+
+ index = pin >> 4;
+ switch (index) {
+ case 1:
+ GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
+
+ if (dir)
+ GPDR0 &= ~(1 << pin);
+ else
+ GPDR0 |= (1 << pin);
+ break;
+ case 2:
+ GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
+
+ if (dir)
+ GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
+ else
+ GPDR1 |= (1 << GPDR1_OFFSET(pin));
+ break;
+ case 3:
+ GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
+
+ if (dir)
+ GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
+ else
+ GPDR1 |= (1 << GPDR1_OFFSET(pin));
+ break;
+ default:
+ printk(KERN_ERR "unimplemented\n");
+ }
+}
+
+static void am200_init_gpio_regs(struct metronomefb_par *par)
+{
+ am200_init_gpio_pin(LED_GPIO_PIN, 0);
+ am200_set_gpio_output(LED_GPIO_PIN, 0);
+
+ am200_init_gpio_pin(STDBY_GPIO_PIN, 0);
+ am200_set_gpio_output(STDBY_GPIO_PIN, 0);
+
+ am200_init_gpio_pin(RST_GPIO_PIN, 0);
+ am200_set_gpio_output(RST_GPIO_PIN, 0);
+
+ am200_init_gpio_pin(RDY_GPIO_PIN, 1);
+
+ am200_init_gpio_pin(ERR_GPIO_PIN, 1);
+
+ am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
+ am200_set_gpio_output(PCBPWR_GPIO_PIN, 0);
+}
+
+static void am200_disable_lcd_controller(struct metronomefb_par *par)
+{
+ LCSR = 0xffffffff; /* Clear LCD Status Register */
+ LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
+
+ /* we reset and just wait for things to settle */
+ msleep(200);
+}
+
+static void am200_enable_lcd_controller(struct metronomefb_par *par)
+{
+ LCSR = 0xffffffff;
+ FDADR0 = par->metromem_desc_dma;
+ LCCR0 |= LCCR0_ENB;
+}
+
+static void am200_init_lcdc_regs(struct metronomefb_par *par)
+{
+ /* here we do:
+ - disable the lcd controller
+ - setup lcd control registers
+ - setup dma descriptor
+ - reenable lcd controller
+ */
+
+ /* disable the lcd controller */
+ am200_disable_lcd_controller(par);
+
+ /* setup lcd control registers */
+ LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
+ | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
+
+ LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */
+ | (27 << 10) /* hsync pulse width - 1 */
+ | (33 << 16) /* eol pixel count */
+ | (33 << 24); /* bol pixel count */
+
+ LCCR2 = (par->info->var.yres - 1) /* lines per panel */
+ | (24 << 10) /* vsync pulse width - 1 */
+ | (2 << 16) /* eof pixel count */
+ | (0 << 24); /* bof pixel count */
+
+ LCCR3 = 2 /* pixel clock divisor */
+ | (24 << 8) /* AC Bias pin freq */
+ | LCCR3_16BPP /* BPP */
+ | LCCR3_PCP; /* PCP falling edge */
+
+}
+
+static void am200_post_dma_setup(struct metronomefb_par *par)
+{
+ par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
+ par->metromem_desc->mFSADR0 = par->metromem_dma;
+ par->metromem_desc->mFIDR0 = 0;
+ par->metromem_desc->mLDCMD0 = par->info->var.xres
+ * par->info->var.yres;
+ am200_enable_lcd_controller(par);
+}
+
+static void am200_free_irq(struct fb_info *info)
+{
+ free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
+}
+
+static irqreturn_t am200_handle_irq(int irq, void *dev_id)
+{
+ struct fb_info *info = dev_id;
+ struct metronomefb_par *par = info->par;
+
+ wake_up_interruptible(&par->waitq);
+ return IRQ_HANDLED;
+}
+
+static int am200_setup_irq(struct fb_info *info)
+{
+ int retval;
+
+ retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
+ IRQF_DISABLED, "AM200", info);
+ if (retval) {
+ printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval);
+ return retval;
+ }
+
+ return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
+}
+
+static void am200_set_rst(struct metronomefb_par *par, int state)
+{
+ am200_set_gpio_output(RST_GPIO_PIN, state);
+}
+
+static void am200_set_stdby(struct metronomefb_par *par, int state)
+{
+ am200_set_gpio_output(STDBY_GPIO_PIN, state);
+}
+
+static int am200_wait_event(struct metronomefb_par *par)
+{
+ return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
+}
+
+static int am200_wait_event_intr(struct metronomefb_par *par)
+{
+ return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
+}
+
+static struct metronome_board am200_board = {
+ .owner = THIS_MODULE,
+ .free_irq = am200_free_irq,
+ .setup_irq = am200_setup_irq,
+ .init_gpio_regs = am200_init_gpio_regs,
+ .init_lcdc_regs = am200_init_lcdc_regs,
+ .post_dma_setup = am200_post_dma_setup,
+ .set_rst = am200_set_rst,
+ .set_stdby = am200_set_stdby,
+ .met_wait_event = am200_wait_event,
+ .met_wait_event_intr = am200_wait_event_intr,
+};
+
+static struct platform_device *am200_device;
+
+static int __init am200_init(void)
+{
+ int ret;
+
+ /* request our platform independent driver */
+ request_module("metronomefb");
+
+ am200_device = platform_device_alloc("metronomefb", -1);
+ if (!am200_device)
+ return -ENOMEM;
+
+ platform_device_add_data(am200_device, &am200_board,
+ sizeof(am200_board));
+
+ /* this _add binds metronomefb to am200. metronomefb refcounts am200 */
+ ret = platform_device_add(am200_device);
+
+ if (ret)
+ platform_device_put(am200_device);
+
+ return ret;
+}
+
+static void __exit am200_exit(void)
+{
+ platform_device_unregister(am200_device);
+}
+
+module_init(am200_init);
+module_exit(am200_exit);
+
+MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 4c9ec3f58c52..e6492c1048bf 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -96,7 +96,7 @@
#endif
#ifdef DEBUG
-# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
index 8a1b07c74394..5001bd4ef466 100644
--- a/drivers/video/arkfb.c
+++ b/drivers/video/arkfb.c
@@ -101,7 +101,7 @@ static const struct svga_timing_regs ark_timing_regs = {
/* Module parameters */
-static char *mode = "640x480-8@60";
+static char *mode_option __devinitdata = "640x480-8@60";
#ifdef CONFIG_MTRR
static int mtrr = 1;
@@ -111,8 +111,10 @@ MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
-module_param(mode, charp, 0444);
-MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+module_param(mode_option, charp, 0444);
+MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
+module_param_named(mode, mode_option, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)");
#ifdef CONFIG_MTRR
module_param(mtrr, int, 0444);
@@ -941,7 +943,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_
}
/* Allocate and fill driver data structure */
- info = framebuffer_alloc(sizeof(struct arkfb_info), NULL);
+ info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev));
if (! info) {
dev_err(&(dev->dev), "cannot allocate memory\n");
return -ENOMEM;
@@ -956,20 +958,20 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_
/* Prepare PCI device */
rc = pci_enable_device(dev);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot enable PCI device\n");
+ dev_err(info->dev, "cannot enable PCI device\n");
goto err_enable_device;
}
rc = pci_request_regions(dev, "arkfb");
if (rc < 0) {
- dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ dev_err(info->dev, "cannot reserve framebuffer region\n");
goto err_request_regions;
}
par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info);
if (! par->dac) {
rc = -ENOMEM;
- dev_err(&(dev->dev), "RAMDAC initialization failed\n");
+ dev_err(info->dev, "RAMDAC initialization failed\n");
goto err_dac;
}
@@ -980,7 +982,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_
info->screen_base = pci_iomap(dev, 0, 0);
if (! info->screen_base) {
rc = -ENOMEM;
- dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ dev_err(info->dev, "iomap for framebuffer failed\n");
goto err_iomap;
}
@@ -999,22 +1001,22 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_
info->pseudo_palette = (void*) (par->pseudo_palette);
/* Prepare startup mode */
- rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
if (! ((rc == 1) || (rc == 2))) {
rc = -EINVAL;
- dev_err(&(dev->dev), "mode %s not found\n", mode);
+ dev_err(info->dev, "mode %s not found\n", mode_option);
goto err_find_mode;
}
rc = fb_alloc_cmap(&info->cmap, 256, 0);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot allocate colormap\n");
+ dev_err(info->dev, "cannot allocate colormap\n");
goto err_alloc_cmap;
}
rc = register_framebuffer(info);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot register framebugger\n");
+ dev_err(info->dev, "cannot register framebugger\n");
goto err_reg_fb;
}
@@ -1088,7 +1090,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
struct fb_info *info = pci_get_drvdata(dev);
struct arkfb_info *par = info->par;
- dev_info(&(dev->dev), "suspend\n");
+ dev_info(info->dev, "suspend\n");
acquire_console_sem();
mutex_lock(&(par->open_lock));
@@ -1119,7 +1121,7 @@ static int ark_pci_resume (struct pci_dev* dev)
struct fb_info *info = pci_get_drvdata(dev);
struct arkfb_info *par = info->par;
- dev_info(&(dev->dev), "resume\n");
+ dev_info(info->dev, "resume\n");
acquire_console_sem();
mutex_lock(&(par->open_lock));
@@ -1190,7 +1192,7 @@ static int __init arkfb_init(void)
return -ENODEV;
if (option && *option)
- mode = option;
+ mode_option = option;
#endif
pr_debug("arkfb: initializing\n");
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 5d4fbaa53a6c..dff35474b854 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -1270,7 +1270,7 @@ again:
gstart = (prescale / 2 + plen * left_margin) / prescale;
/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
- gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale;
+ gend1 = gstart + roundup(xres, align) * plen / prescale;
/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
gend2 = gstart + xres * plen / prescale;
par->HHT = plen * (left_margin + xres + right_margin) /
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index fc65c02306dd..8ffdf3578768 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -31,7 +31,8 @@
#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
#define ATMEL_LCDC_DMA_BURST_LEN 8
-#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9)
+#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || \
+ defined(CONFIG_ARCH_AT91SAM9RL)
#define ATMEL_LCDC_FIFO_SIZE 2048
#else
#define ATMEL_LCDC_FIFO_SIZE 512
@@ -250,6 +251,8 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
return -ENOMEM;
}
+ memset(info->screen_base, 0, info->fix.smem_len);
+
return 0;
}
@@ -336,19 +339,35 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
break;
case 15:
case 16:
- var->red.offset = 0;
+ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+ /* RGB:565 mode */
+ var->red.offset = 11;
+ var->blue.offset = 0;
+ var->green.length = 6;
+ } else {
+ /* BGR:555 mode */
+ var->red.offset = 0;
+ var->blue.offset = 10;
+ var->green.length = 5;
+ }
var->green.offset = 5;
- var->blue.offset = 10;
- var->red.length = var->green.length = var->blue.length = 5;
+ var->red.length = var->blue.length = 5;
break;
case 32:
var->transp.offset = 24;
var->transp.length = 8;
/* fall through */
case 24:
- var->red.offset = 0;
+ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+ /* RGB:888 mode */
+ var->red.offset = 16;
+ var->blue.offset = 0;
+ } else {
+ /* BGR:888 mode */
+ var->red.offset = 0;
+ var->blue.offset = 16;
+ }
var->green.offset = 8;
- var->blue.offset = 16;
var->red.length = var->green.length = var->blue.length = 8;
break;
default:
@@ -634,7 +653,6 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
struct fb_info *info = sinfo->info;
int ret = 0;
- memset_io(info->screen_base, 0, info->fix.smem_len);
info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
dev_info(info->device,
@@ -696,6 +714,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
sinfo->guard_time = pdata_sinfo->guard_time;
sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
+ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
} else {
dev_err(dev, "cannot get default configuration\n");
goto free_info;
@@ -764,6 +783,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
if (!info->screen_base)
goto release_intmem;
+
+ /*
+ * Don't clear the framebuffer -- someone may have set
+ * up a splash image.
+ */
} else {
/* alocate memory buffer */
ret = atmel_lcdfb_alloc_video_memory(sinfo);
@@ -903,10 +927,42 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+
+static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct atmel_lcdfb_info *sinfo = info->par;
+
+ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+ atmel_lcdfb_stop_clock(sinfo);
+ return 0;
+}
+
+static int atmel_lcdfb_resume(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct atmel_lcdfb_info *sinfo = info->par;
+
+ atmel_lcdfb_start_clock(sinfo);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
+ return 0;
+}
+
+#else
+#define atmel_lcdfb_suspend NULL
+#define atmel_lcdfb_resume NULL
+#endif
+
static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),
-
-// FIXME need suspend, resume
+ .suspend = atmel_lcdfb_suspend,
+ .resume = atmel_lcdfb_resume,
.driver = {
.name = "atmel_lcdfb",
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index cbd3308b6690..24ee96c4e9e9 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -91,7 +91,7 @@
#undef DEBUG
#ifdef DEBUG
-#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __FUNCTION__, ##args);
+#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args);
#else
#define DBG(fmt, args...)
#endif
@@ -1885,7 +1885,7 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
/* range check to make sure */
if (ent->driver_data < ARRAY_SIZE(r128_family))
- strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
+ strlcat(video_card, r128_family[ent->driver_data], sizeof(video_card));
printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 62f9c6e387cc..e4bcf5376a99 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2621,10 +2621,13 @@ static int __devinit aty_init(struct fb_info *info)
#endif /* CONFIG_FB_ATY_CT */
info->var = var;
- fb_alloc_cmap(&info->cmap, 256, 0);
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ goto aty_init_exit;
- if (register_framebuffer(info) < 0)
+ if (register_framebuffer(info) < 0) {
+ fb_dealloc_cmap(&info->cmap);
goto aty_init_exit;
+ }
fb_list = info;
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index cc9e9779b75f..c50c7cf26fe9 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -197,7 +197,7 @@ static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks;
#ifdef DEBUG
printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
- __FUNCTION__, pll->dsp_config, pll->dsp_on_off);
+ __func__, pll->dsp_config, pll->dsp_on_off);
#endif
return 0;
}
@@ -225,7 +225,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll
(par->ref_clk_per * pll->pll_ref_div);
#ifdef DEBUG
printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
- __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real);
+ __func__, pllvclk, pllvclk / pll->vclk_post_div_real);
#endif
pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
@@ -269,7 +269,7 @@ static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pl
}
#endif
#ifdef DEBUG
- printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret);
+ printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__, ret, ret);
#endif
return ret;
}
@@ -284,11 +284,11 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
#ifdef DEBUG
printk("atyfb(%s): about to program:\n"
"pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
- __FUNCTION__,
+ __func__,
pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl);
printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
- __FUNCTION__,
+ __func__,
par->clk_wr_offset, pll->ct.vclk_fb_div,
pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real);
#endif
@@ -428,7 +428,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
#ifdef DEBUG
printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
- __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
+ __func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
#endif
memcntl = aty_ld_le32(MEM_CNTL, par);
@@ -540,7 +540,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
(par->ref_clk_per * pll->ct.pll_ref_div);
printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
- __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
+ __func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
#endif
if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
@@ -581,7 +581,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
(par->ref_clk_per * pll->ct.pll_ref_div);
printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
- __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
+ __func__, pllsclk, pllsclk / sclk_post_div_real);
#endif
}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 62867cb63fef..72cd0d2f14ec 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -52,11 +52,14 @@
#define RADEON_VERSION "0.2.0"
+#include "radeonfb.h"
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -91,7 +94,6 @@
#include "../edid.h" // MOVE THAT TO include/video
#include "ati_ids.h"
-#include "radeonfb.h"
#define MAX_MAPPED_VRAM (2048*2048*4)
#define MIN_MAPPED_VRAM (1024*768*1)
@@ -1488,7 +1490,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
freq = rinfo->pll.ppll_max;
if (freq*12 < rinfo->pll.ppll_min)
freq = rinfo->pll.ppll_min / 12;
- RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n",
+ pr_debug("freq = %lu, PLL min = %u, PLL max = %u\n",
freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max);
for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
@@ -1509,7 +1511,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
post_div = &post_divs[post_div->bitvalue];
pll_output_freq = post_div->divider * freq;
}
- RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+ pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n",
rinfo->pll.ref_div, rinfo->pll.ref_clk,
pll_output_freq);
@@ -1519,7 +1521,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
post_div = &post_divs[post_div->bitvalue];
pll_output_freq = post_div->divider * freq;
}
- RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+ pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n",
rinfo->pll.ref_div, rinfo->pll.ref_clk,
pll_output_freq);
@@ -1528,9 +1530,9 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
regs->ppll_ref_div = rinfo->pll.ref_div;
regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16);
- RTRACE("post div = 0x%x\n", post_div->bitvalue);
- RTRACE("fb_div = 0x%x\n", fb_div);
- RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
+ pr_debug("post div = 0x%x\n", post_div->bitvalue);
+ pr_debug("fb_div = 0x%x\n", fb_div);
+ pr_debug("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
}
static int radeonfb_set_par(struct fb_info *info)
@@ -1602,9 +1604,9 @@ static int radeonfb_set_par(struct fb_info *info)
dotClock = 1000000000 / pixClock;
freq = dotClock / 10; /* x100 */
- RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
+ pr_debug("hStart = %d, hEnd = %d, hTotal = %d\n",
hSyncStart, hSyncEnd, hTotal);
- RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
+ pr_debug("vStart = %d, vEnd = %d, vTotal = %d\n",
vSyncStart, vSyncEnd, vTotal);
hsync_wid = (hSyncEnd - hSyncStart) / 8;
@@ -1713,16 +1715,16 @@ static int radeonfb_set_par(struct fb_info *info)
newmode->surf_info[i] = 0;
}
- RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n",
+ pr_debug("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n",
newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid);
- RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n",
+ pr_debug("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n",
newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid);
rinfo->bpp = mode->bits_per_pixel;
rinfo->depth = depth;
- RTRACE("pixclock = %lu\n", (unsigned long)pixClock);
- RTRACE("freq = %lu\n", (unsigned long)freq);
+ pr_debug("pixclock = %lu\n", (unsigned long)pixClock);
+ pr_debug("freq = %lu\n", (unsigned long)freq);
/* We use PPLL_DIV_3 */
newmode->clk_cntl_index = 0x300;
@@ -1986,7 +1988,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo)
if (rinfo->has_CRTC2)
OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl);
- RTRACE("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n",
+ pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n",
aper_base,
((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16),
0xffff0000 | (agp_base >> 16));
@@ -2083,7 +2085,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
* ToDo: identify these cases
*/
- RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n",
+ pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n",
pci_name(rinfo->pdev),
rinfo->video_ram / 1024,
rinfo->vram_ddr ? "DDR" : "SDRAM",
@@ -2158,8 +2160,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
struct fb_info *info;
struct radeonfb_info *rinfo;
int ret;
+ unsigned char c1, c2;
- RTRACE("radeonfb_pci_register BEGIN\n");
+ pr_debug("radeonfb_pci_register BEGIN\n");
/* Enable device in PCI config */
ret = pci_enable_device(pdev);
@@ -2185,9 +2188,15 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
rinfo->lvds_timer.function = radeon_lvds_timer_func;
rinfo->lvds_timer.data = (unsigned long)rinfo;
- strcpy(rinfo->name, "ATI Radeon XX ");
- rinfo->name[11] = ent->device >> 8;
- rinfo->name[12] = ent->device & 0xFF;
+ c1 = ent->device >> 8;
+ c2 = ent->device & 0xff;
+ if (isprint(c1) && isprint(c2))
+ snprintf(rinfo->name, sizeof(rinfo->name),
+ "ATI Radeon %x \"%c%c\"", ent->device & 0xffff, c1, c2);
+ else
+ snprintf(rinfo->name, sizeof(rinfo->name),
+ "ATI Radeon %x", ent->device & 0xffff);
+
rinfo->family = ent->driver_data & CHIP_FAMILY_MASK;
rinfo->chipset = pdev->device;
rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0;
@@ -2278,7 +2287,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
goto err_unmap_rom;
}
- RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev),
+ pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev),
rinfo->mapped_vram/1024);
/*
@@ -2373,7 +2382,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
if (rinfo->bios_seg)
radeon_unmap_ROM(rinfo, pdev);
- RTRACE("radeonfb_pci_register END\n");
+ pr_debug("radeonfb_pci_register END\n");
return 0;
err_unmap_fb:
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 7db9de681716..f9e7c29ad9bf 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -1,3 +1,5 @@
+#include "radeonfb.h"
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -11,7 +13,6 @@
#include <asm/io.h>
#include <video/radeon.h>
-#include "radeonfb.h"
#include "../edid.h"
static void radeon_gpio_setscl(void* data, int state)
@@ -77,7 +78,7 @@ static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name)
chan->algo.setscl = radeon_gpio_setscl;
chan->algo.getsda = radeon_gpio_getsda;
chan->algo.getscl = radeon_gpio_getscl;
- chan->algo.udelay = 40;
+ chan->algo.udelay = 10;
chan->algo.timeout = 20;
chan->algo.data = chan;
@@ -148,21 +149,21 @@ int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
if (out_edid)
*out_edid = edid;
if (!edid) {
- RTRACE("radeonfb: I2C (port %d) ... not found\n", conn);
+ pr_debug("radeonfb: I2C (port %d) ... not found\n", conn);
return MT_NONE;
}
if (edid[0x14] & 0x80) {
/* Fix detection using BIOS tables */
if (rinfo->is_mobility /*&& conn == ddc_dvi*/ &&
(INREG(LVDS_GEN_CNTL) & LVDS_ON)) {
- RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn);
+ pr_debug("radeonfb: I2C (port %d) ... found LVDS panel\n", conn);
return MT_LCD;
} else {
- RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn);
+ pr_debug("radeonfb: I2C (port %d) ... found TMDS panel\n", conn);
return MT_DFP;
}
}
- RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn);
+ pr_debug("radeonfb: I2C (port %d) ... found CRT display\n", conn);
return MT_CRT;
}
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 2030ed813429..b4d4b88afc09 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -69,11 +69,11 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
u8 *tmp;
int i, mt = MT_NONE;
- RTRACE("analyzing OF properties...\n");
+ pr_debug("analyzing OF properties...\n");
pmt = of_get_property(dp, "display-type", NULL);
if (!pmt)
return MT_NONE;
- RTRACE("display-type: %s\n", pmt);
+ pr_debug("display-type: %s\n", pmt);
/* OF says "LCD" for DFP as well, we discriminate from the caller of this
* function
*/
@@ -117,7 +117,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
{
struct device_node *dp;
- RTRACE("radeon_probe_OF_head\n");
+ pr_debug("radeon_probe_OF_head\n");
dp = rinfo->of_node;
while (dp == NULL)
@@ -135,7 +135,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
if (!pname)
return MT_NONE;
len = strlen(pname);
- RTRACE("head: %s (letter: %c, head_no: %d)\n",
+ pr_debug("head: %s (letter: %c, head_no: %d)\n",
pname, pname[len-1], head_no);
if (pname[len-1] == 'A' && head_no == 0) {
int mt = radeon_parse_montype_prop(dp, out_EDID, 0);
@@ -185,7 +185,7 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
rinfo->panel_info.xres, rinfo->panel_info.yres);
rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44);
- RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
+ pr_debug("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay);
if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0)
rinfo->panel_info.pwr_delay = 2000;
@@ -199,16 +199,16 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
rinfo->panel_info.fbk_divider > 3) {
rinfo->panel_info.use_bios_dividers = 1;
printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n");
- RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider);
- RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider);
- RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider);
+ pr_debug("ref_divider = %x\n", rinfo->panel_info.ref_divider);
+ pr_debug("post_divider = %x\n", rinfo->panel_info.post_divider);
+ pr_debug("fbk_divider = %x\n", rinfo->panel_info.fbk_divider);
}
- RTRACE("Scanning BIOS table ...\n");
+ pr_debug("Scanning BIOS table ...\n");
for(i=0; i<32; i++) {
tmp0 = BIOS_IN16(tmp+64+i*2);
if (tmp0 == 0)
break;
- RTRACE(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2));
+ pr_debug(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2));
if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) &&
(BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) {
rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8;
@@ -227,19 +227,19 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
/* Mark panel infos valid */
rinfo->panel_info.valid = 1;
- RTRACE("Found panel in BIOS table:\n");
- RTRACE(" hblank: %d\n", rinfo->panel_info.hblank);
- RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus);
- RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width);
- RTRACE(" vblank: %d\n", rinfo->panel_info.vblank);
- RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus);
- RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width);
- RTRACE(" clock: %d\n", rinfo->panel_info.clock);
+ pr_debug("Found panel in BIOS table:\n");
+ pr_debug(" hblank: %d\n", rinfo->panel_info.hblank);
+ pr_debug(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus);
+ pr_debug(" hSync_width: %d\n", rinfo->panel_info.hSync_width);
+ pr_debug(" vblank: %d\n", rinfo->panel_info.vblank);
+ pr_debug(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus);
+ pr_debug(" vSync_width: %d\n", rinfo->panel_info.vSync_width);
+ pr_debug(" clock: %d\n", rinfo->panel_info.clock);
return 1;
}
}
- RTRACE("Didn't find panel in BIOS table !\n");
+ pr_debug("Didn't find panel in BIOS table !\n");
return 0;
}
@@ -271,18 +271,18 @@ static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo)
* DEBUG is enabled
*/
chips = BIOS_IN8(offset++) >> 4;
- RTRACE("%d chips in connector info\n", chips);
+ pr_debug("%d chips in connector info\n", chips);
for (i = 0; i < chips; i++) {
tmp = BIOS_IN8(offset++);
connectors = tmp & 0x0f;
- RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors);
+ pr_debug(" - chip %d has %d connectors\n", tmp >> 4, connectors);
for (conn = 0; ; conn++) {
tmp = BIOS_IN16(offset);
if (tmp == 0)
break;
offset += 2;
type = (tmp >> 12) & 0x0f;
- RTRACE(" * connector %d of type %d (%s) : %04x\n",
+ pr_debug(" * connector %d of type %d (%s) : %04x\n",
conn, type, __conn_type_table[type], tmp);
}
}
@@ -449,7 +449,7 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
* a layout for each card ?
*/
- RTRACE("Using specified monitor layout: %s", monitor_layout);
+ pr_debug("Using specified monitor layout: %s", monitor_layout);
#ifdef CONFIG_FB_RADEON_I2C
if (!ignore_edid) {
if (rinfo->mon1_type != MT_NONE)
@@ -479,9 +479,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
* Auto-detecting display type (well... trying to ...)
*/
- RTRACE("Starting monitor auto detection...\n");
+ pr_debug("Starting monitor auto detection...\n");
-#if DEBUG && defined(CONFIG_FB_RADEON_I2C)
+#if defined(DEBUG) && defined(CONFIG_FB_RADEON_I2C)
{
u8 *EDIDs[4] = { NULL, NULL, NULL, NULL };
int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE};
@@ -756,7 +756,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT
&& rinfo->mon1_EDID) {
struct fb_var_screeninfo var;
- RTRACE("Parsing EDID data for panel info\n");
+ pr_debug("Parsing EDID data for panel info\n");
if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) {
if (var.xres >= rinfo->panel_info.xres &&
var.yres >= rinfo->panel_info.yres)
@@ -776,7 +776,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) {
struct fb_var_screeninfo *var = &info->var;
- RTRACE("Setting up default mode based on panel info\n");
+ pr_debug("Setting up default mode based on panel info\n");
var->xres = rinfo->panel_info.xres;
var->yres = rinfo->panel_info.yres;
var->xres_virtual = rinfo->panel_info.xres;
@@ -824,7 +824,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
int dbsize;
char modename[32];
- RTRACE("Guessing panel info...\n");
+ pr_debug("Guessing panel info...\n");
if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) {
u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE;
rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8;
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 5eac1ce52e72..c347e38cd0b0 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -1,6 +1,10 @@
#ifndef __RADEONFB_H__
#define __RADEONFB_H__
+#ifdef CONFIG_FB_RADEON_DEBUG
+#define DEBUG 1
+#endif
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -365,22 +369,6 @@ struct radeonfb_info {
/*
- * Debugging stuffs
- */
-#ifdef CONFIG_FB_RADEON_DEBUG
-#define DEBUG 1
-#else
-#define DEBUG 0
-#endif
-
-#if DEBUG
-#define RTRACE printk
-#else
-#define RTRACE if(0) printk
-#endif
-
-
-/*
* IO macros
*/
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index eefba3d0e4b9..49834a67a623 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -336,7 +336,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
{
if (var->bits_per_pixel != LCD_BPP) {
- pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__,
+ pr_debug("%s: depth not supported: %u BPP\n", __func__,
var->bits_per_pixel);
return -EINVAL;
}
@@ -345,7 +345,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
info->var.xres_virtual != var->xres_virtual ||
info->var.yres_virtual != var->yres_virtual) {
pr_debug("%s: Resolution not supported: X%u x Y%u \n",
- __FUNCTION__, var->xres, var->yres);
+ __func__, var->xres, var->yres);
return -EINVAL;
}
@@ -355,7 +355,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
- __FUNCTION__, var->yres_virtual);
+ __func__, var->yres_virtual);
return -ENOMEM;
}
@@ -652,7 +652,7 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
goto out7;
}
- if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED,
+ if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED,
"PPI ERROR", info) < 0) {
printk(KERN_ERR DRIVER_NAME
": unable to request PPI ERROR IRQ\n");
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 833b10c84064..275d9dab0c61 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -339,7 +339,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
dev_set_drvdata(&op->dev, info);
- printk("%s: bwtwo at %lx:%lx\n",
+ printk(KERN_INFO "%s: bwtwo at %lx:%lx\n",
dp->full_name, par->which_io, par->physbase);
return 0;
@@ -399,10 +399,9 @@ static int __init bw2_init(void)
static void __exit bw2_exit(void)
{
- return of_unregister_driver(&bw2_driver);
+ of_unregister_driver(&bw2_driver);
}
-
module_init(bw2_init);
module_exit(bw2_exit);
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index b07e419b12d2..df03f3776dcc 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -44,15 +44,16 @@
*/
static void
-bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
- int src_idx, int bits, unsigned n, u32 bswapmask)
+bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
+ const unsigned long __iomem *src, int src_idx, int bits,
+ unsigned n, u32 bswapmask)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
int left, right;
- first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
- last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
+ first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
if (!shift) {
// Same alignment for source and dest
@@ -202,8 +203,9 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
*/
static void
-bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
- int src_idx, int bits, unsigned n, u32 bswapmask)
+bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
+ const unsigned long __iomem *src, int src_idx, int bits,
+ unsigned n, u32 bswapmask)
{
unsigned long first, last;
int shift;
@@ -221,8 +223,9 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
shift = dst_idx-src_idx;
- first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
- last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
+ first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
+ bswapmask);
if (!shift) {
// Same alignment for source and dest
@@ -404,7 +407,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
- bitcpy_rev(dst, dst_idx, src, src_idx, bits,
+ bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel, bswapmask);
}
} else {
@@ -413,7 +416,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
- bitcpy(dst, dst_idx, src, src_idx, bits,
+ bitcpy(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel, bswapmask);
dst_idx += bits_per_line;
src_idx += bits_per_line;
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 23d70a12e4da..64b35766b2a2 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -36,16 +36,16 @@
*/
static void
-bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
- unsigned n, int bits, u32 bswapmask)
+bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
+ unsigned long pat, unsigned n, int bits, u32 bswapmask)
{
unsigned long first, last;
if (!n)
return;
- first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
- last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
+ first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
if (dst_idx+n <= bits) {
// Single word
@@ -93,16 +93,16 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
*/
static void
-bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
- int left, int right, unsigned n, int bits)
+bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
+ unsigned long pat, int left, int right, unsigned n, int bits)
{
unsigned long first, last;
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) {
// Single word
@@ -147,8 +147,9 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
* Aligned pattern invert using 32/64-bit memory accesses
*/
static void
-bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
- unsigned n, int bits, u32 bswapmask)
+bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
+ int dst_idx, unsigned long pat, unsigned n, int bits,
+ u32 bswapmask)
{
unsigned long val = pat, dat;
unsigned long first, last;
@@ -156,8 +157,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
if (!n)
return;
- first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
- last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
+ first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
if (dst_idx+n <= bits) {
// Single word
@@ -217,16 +218,17 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
*/
static void
-bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
- int left, int right, unsigned n, int bits)
+bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
+ int dst_idx, unsigned long pat, int left, int right,
+ unsigned n, int bits)
{
unsigned long first, last, dat;
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) {
// Single word
@@ -306,7 +308,8 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
p->fbops->fb_sync(p);
if (!left) {
u32 bswapmask = fb_compute_bswapmask(p);
- void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
+ void (*fill_op32)(struct fb_info *p,
+ unsigned long __iomem *dst, int dst_idx,
unsigned long pat, unsigned n, int bits,
u32 bswapmask) = NULL;
@@ -325,16 +328,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bits - 1);
- fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask);
+ fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
+ bswapmask);
dst_idx += p->fix.line_length*8;
}
} else {
int right;
int r;
int rot = (left-dst_idx) % bpp;
- void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
- unsigned long pat, int left, int right,
- unsigned n, int bits) = NULL;
+ void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
+ int dst_idx, unsigned long pat, int left,
+ int right, unsigned n, int bits) = NULL;
/* rotate pattern to correct start position */
pat = pat << rot | pat >> (bpp-rot);
@@ -355,7 +359,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bits - 1);
- fill_op(dst, dst_idx, pat, left, right,
+ fill_op(p, dst, dst_idx, pat, left, right,
width*bpp, bits);
r = (p->fix.line_length*8) % bpp;
pat = pat << (bpp-r) | pat >> r;
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index f598907b42ad..baed57d3cfff 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -38,35 +38,31 @@
#define DEBUG
#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
#else
#define DPRINTK(fmt, args...)
#endif
-static const u32 cfb_tab8[] = {
-#if defined(__BIG_ENDIAN)
+static const u32 cfb_tab8_be[] = {
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
0xffff0000,0xffff00ff,0xffffff00,0xffffffff
-#elif defined(__LITTLE_ENDIAN)
+};
+
+static const u32 cfb_tab8_le[] = {
0x00000000,0xff000000,0x00ff0000,0xffff0000,
0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
-#else
-#error FIXME: No endianness??
-#endif
};
-static const u32 cfb_tab16[] = {
-#if defined(__BIG_ENDIAN)
+static const u32 cfb_tab16_be[] = {
0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
-#elif defined(__LITTLE_ENDIAN)
+};
+
+static const u32 cfb_tab16_le[] = {
0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
-#else
-#error FIXME: No endianness??
-#endif
};
static const u32 cfb_tab32[] = {
@@ -98,7 +94,8 @@ static inline void color_imageblit(const struct fb_image *image,
val = 0;
if (start_index) {
- u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
+ u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
+ start_index, bswapmask);
val = FB_READL(dst) & start_mask;
shift = start_index;
}
@@ -108,20 +105,21 @@ static inline void color_imageblit(const struct fb_image *image,
color = palette[*src];
else
color = *src;
- color <<= FB_LEFT_POS(bpp);
- val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
+ color <<= FB_LEFT_POS(p, bpp);
+ val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
val = (shift == null_bits) ? 0 :
- FB_SHIFT_LOW(color, 32 - shift);
+ FB_SHIFT_LOW(p, color, 32 - shift);
}
shift += bpp;
shift &= (32 - 1);
src++;
}
if (shift) {
- u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
+ u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
+ bswapmask);
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
@@ -152,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
u32 bswapmask = fb_compute_bswapmask(p);
dst2 = (u32 __iomem *) dst1;
- fgcolor <<= FB_LEFT_POS(bpp);
- bgcolor <<= FB_LEFT_POS(bpp);
+ fgcolor <<= FB_LEFT_POS(p, bpp);
+ bgcolor <<= FB_LEFT_POS(p, bpp);
for (i = image->height; i--; ) {
shift = val = 0;
@@ -164,7 +162,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
/* write leading bits */
if (start_index) {
- u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
+ u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
+ start_index, bswapmask);
val = FB_READL(dst) & start_mask;
shift = start_index;
}
@@ -172,13 +171,13 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
while (j--) {
l--;
color = (*s & (1 << l)) ? fgcolor : bgcolor;
- val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
+ val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
/* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
val = (shift == null_bits) ? 0 :
- FB_SHIFT_LOW(color,32 - shift);
+ FB_SHIFT_LOW(p, color, 32 - shift);
}
shift += bpp;
shift &= (32 - 1);
@@ -187,7 +186,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
/* write trailing bits */
if (shift) {
- u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
+ u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
+ bswapmask);
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
@@ -223,13 +223,13 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
u32 __iomem *dst;
const u32 *tab = NULL;
int i, j, k;
-
+
switch (bpp) {
case 8:
- tab = cfb_tab8;
+ tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
break;
case 16:
- tab = cfb_tab16;
+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
break;
case 32:
default:
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index fdc9f43ec30a..0db0fecba93b 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -556,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
dev_set_drvdata(&op->dev, info);
- printk("%s: cgfourteen at %lx:%lx, %dMB\n",
+ printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n",
dp->full_name,
par->iospace, par->physbase,
par->ramsize >> 20);
@@ -605,7 +605,7 @@ static struct of_platform_driver cg14_driver = {
.remove = __devexit_p(cg14_remove),
};
-int __init cg14_init(void)
+static int __init cg14_init(void)
{
if (fb_get_options("cg14fb", NULL))
return -ENODEV;
@@ -613,7 +613,7 @@ int __init cg14_init(void)
return of_register_driver(&cg14_driver, &of_bus_type);
}
-void __exit cg14_exit(void)
+static void __exit cg14_exit(void)
{
of_unregister_driver(&cg14_driver);
}
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index a5c7fb331527..010ea53978f8 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -419,7 +419,7 @@ static int __devinit cg3_probe(struct of_device *op,
dev_set_drvdata(&op->dev, info);
- printk("%s: cg3 at %lx:%lx\n",
+ printk(KERN_INFO "%s: cg3 at %lx:%lx\n",
dp->full_name, par->which_io, par->physbase);
return 0;
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 549891d76ef5..fc90db6da65a 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -781,7 +781,7 @@ static int __devinit cg6_probe(struct of_device *op,
dev_set_drvdata(&op->dev, info);
- printk("%s: CGsix [%s] at %lx:%lx\n",
+ printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n",
dp->full_name, info->fix.id,
par->which_io, par->physbase);
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index f7e2d5add831..35ac9d956b3d 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -81,7 +81,7 @@
/* debug output */
#ifdef CIRRUSFB_DEBUG
#define DPRINTK(fmt, args...) \
- printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+ printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
@@ -91,7 +91,7 @@
#define assert(expr) \
if (!(expr)) { \
printk("Assertion failed! %s,%s,%s,line=%d\n", \
- #expr, __FILE__, __FUNCTION__, __LINE__); \
+ #expr, __FILE__, __func__, __LINE__); \
}
#else
#define assert(expr)
@@ -3117,7 +3117,7 @@ static void bestclock(long freq, long *best, long *nom,
}
}
}
- d = ((143181 * n) + f - 1) / f;
+ d = DIV_ROUND_UP(143181 * n, f);
if ((d >= 7) && (d <= 63)) {
if (d > 31)
d = (d / 2) * 2;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 022282494d3f..8eda7b60df8f 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -92,7 +92,7 @@
#include "fbcon.h"
#ifdef FBCONDEBUG
-# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
@@ -620,8 +620,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
if (fb_get_color_depth(&info->var, &info->fix) == 1)
erase &= ~0x400;
logo_height = fb_prepare_logo(info, ops->rotate);
- logo_lines = (logo_height + vc->vc_font.height - 1) /
- vc->vc_font.height;
+ logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height);
q = (unsigned short *) (vc->vc_origin +
vc->vc_size_row * rows);
step = logo_lines * cols;
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 3706307e70ed..0135e0395456 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -104,10 +104,14 @@ struct fbcon_ops {
#define attr_blink(s) \
((s) & 0x8000)
-#define mono_col(info) \
- (~(0xfff << (max((info)->var.green.length, \
- max((info)->var.red.length, \
- (info)->var.blue.length)))) & 0xff)
+
+static inline int mono_col(const struct fb_info *info)
+{
+ __u32 max_len;
+ max_len = max(info->var.green.length, info->var.red.length);
+ max_len = max(info->var.blue.length, max_len);
+ return ~(0xfff << (max_len & 0xff));
+}
static inline int attr_col_ec(int shift, struct vc_data *vc,
struct fb_info *info, int is_fg)
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index a2a0618d86a5..1db622192bde 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -94,41 +94,44 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
return val;
}
-static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
+static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index,
+ u32 bswapmask)
{
u32 mask;
if (!bswapmask) {
- mask = FB_SHIFT_HIGH(~(u32)0, index);
+ mask = FB_SHIFT_HIGH(p, ~(u32)0, index);
} else {
- mask = 0xff << FB_LEFT_POS(8);
- mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
- mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
+ mask = 0xff << FB_LEFT_POS(p, 8);
+ mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
+ mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
#if defined(__i386__) || defined(__x86_64__)
/* Shift argument is limited to 0 - 31 on x86 based CPU's */
if(index + bswapmask < 32)
#endif
- mask |= FB_SHIFT_HIGH(~(u32)0,
+ mask |= FB_SHIFT_HIGH(p, ~(u32)0,
(index + bswapmask) & ~(bswapmask));
}
return mask;
}
-static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask)
+static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p,
+ u32 index,
+ u32 bswapmask)
{
unsigned long mask;
if (!bswapmask) {
- mask = FB_SHIFT_HIGH(~0UL, index);
+ mask = FB_SHIFT_HIGH(p, ~0UL, index);
} else {
- mask = 0xff << FB_LEFT_POS(8);
- mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
- mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
+ mask = 0xff << FB_LEFT_POS(p, 8);
+ mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask;
+ mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask));
#if defined(__i386__) || defined(__x86_64__)
/* Shift argument is limited to 0 - 31 on x86 based CPU's */
if(index + bswapmask < BITS_PER_LONG)
#endif
- mask |= FB_SHIFT_HIGH(~0UL,
+ mask |= FB_SHIFT_HIGH(p, ~0UL,
(index + bswapmask) & ~(bswapmask));
}
return mask;
@@ -158,8 +161,8 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
return val;
}
-#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i))
-#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i))
+#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i))
+#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i))
#define fb_compute_bswapmask(...) 0
#endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 01072f4b3e8f..776f7fcd2fbf 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/console.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -632,27 +633,51 @@ int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
#endif /* CONFIG_LOGO */
-static int fbmem_read_proc(char *buf, char **start, off_t offset,
- int len, int *eof, void *private)
+static void *fb_seq_start(struct seq_file *m, loff_t *pos)
{
- struct fb_info **fi;
- int clen;
-
- clen = 0;
- for (fi = registered_fb; fi < &registered_fb[FB_MAX] && clen < 4000;
- fi++)
- if (*fi)
- clen += sprintf(buf + clen, "%d %s\n",
- (*fi)->node,
- (*fi)->fix.id);
- *start = buf + offset;
- if (clen > offset)
- clen -= offset;
- else
- clen = 0;
- return clen < len ? clen : len;
+ return (*pos < FB_MAX) ? pos : NULL;
+}
+
+static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return (*pos < FB_MAX) ? pos : NULL;
+}
+
+static void fb_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int fb_seq_show(struct seq_file *m, void *v)
+{
+ int i = *(loff_t *)v;
+ struct fb_info *fi = registered_fb[i];
+
+ if (fi)
+ seq_printf(m, "%d %s\n", fi->node, fi->fix.id);
+ return 0;
+}
+
+static const struct seq_operations proc_fb_seq_ops = {
+ .start = fb_seq_start,
+ .next = fb_seq_next,
+ .stop = fb_seq_stop,
+ .show = fb_seq_show,
+};
+
+static int proc_fb_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &proc_fb_seq_ops);
}
+static const struct file_operations fb_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_fb_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
@@ -1057,7 +1082,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case FBIOPUT_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
return - EFAULT;
- if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
+ if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
return -EINVAL;
@@ -1352,6 +1377,32 @@ static const struct file_operations fb_fops = {
struct class *fb_class;
EXPORT_SYMBOL(fb_class);
+
+static int fb_check_foreignness(struct fb_info *fi)
+{
+ const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
+
+ fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
+
+#ifdef __BIG_ENDIAN
+ fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
+#else
+ fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
+#endif /* __BIG_ENDIAN */
+
+ if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
+ pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
+ "support this framebuffer\n", fi->fix.id);
+ return -ENOSYS;
+ } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
+ pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
+ "support this framebuffer\n", fi->fix.id);
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
@@ -1371,6 +1422,10 @@ register_framebuffer(struct fb_info *fb_info)
if (num_registered_fb == FB_MAX)
return -ENXIO;
+
+ if (fb_check_foreignness(fb_info))
+ return -ENOSYS;
+
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
@@ -1503,7 +1558,7 @@ void fb_set_suspend(struct fb_info *info, int state)
static int __init
fbmem_init(void)
{
- create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
+ proc_create("fb", 0, NULL, &fb_proc_fops);
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index d7e24889650e..93dca3e2aa50 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -32,7 +32,6 @@
static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,
unsigned, struct fb_info *);
static int ffb_blank(int, struct fb_info *);
-static void ffb_init_fix(struct fb_info *);
static void ffb_imageblit(struct fb_info *, const struct fb_image *);
static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
@@ -1001,7 +1000,7 @@ static int __devinit ffb_probe(struct of_device *op,
dev_set_drvdata(&op->dev, info);
- printk("%s: %s at %016lx, type %d, "
+ printk(KERN_INFO "%s: %s at %016lx, type %d, "
"DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
dp->full_name,
((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
@@ -1062,7 +1061,7 @@ static struct of_platform_driver ffb_driver = {
.remove = __devexit_p(ffb_remove),
};
-int __init ffb_init(void)
+static int __init ffb_init(void)
{
if (fb_get_options("ffb", NULL))
return -ENODEV;
@@ -1070,7 +1069,7 @@ int __init ffb_init(void)
return of_register_driver(&ffb_driver, &of_bus_type);
}
-void __exit ffb_exit(void)
+static void __exit ffb_exit(void)
{
of_unregister_driver(&ffb_driver);
}
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
new file mode 100644
index 000000000000..b50bb03cb5ab
--- /dev/null
+++ b/drivers/video/fsl-diu-fb.c
@@ -0,0 +1,1721 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+
+#include <linux/of_platform.h>
+
+#include <sysdev/fsl_soc.h>
+#include "fsl-diu-fb.h"
+
+/*
+ * These parameters give default parameters
+ * for video output 1024x768,
+ * FIXME - change timing to proper amounts
+ * hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __devinitdata fsl_diu_default_mode = {
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15385,
+ .left_margin = 160,
+ .right_margin = 24,
+ .upper_margin = 29,
+ .lower_margin = 3,
+ .hsync_len = 136,
+ .vsync_len = 6,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
+ {
+ .name = "1024x768-60",
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15385,
+ .left_margin = 160,
+ .right_margin = 24,
+ .upper_margin = 29,
+ .lower_margin = 3,
+ .hsync_len = 136,
+ .vsync_len = 6,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1024x768-70",
+ .refresh = 70,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 16886,
+ .left_margin = 3,
+ .right_margin = 3,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 40,
+ .vsync_len = 18,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1024x768-75",
+ .refresh = 75,
+ .xres = 1024,
+ .yres = 768,
+ .pixclock = 15009,
+ .left_margin = 3,
+ .right_margin = 3,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 80,
+ .vsync_len = 32,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9375,
+ .left_margin = 38,
+ .right_margin = 128,
+ .upper_margin = 2,
+ .lower_margin = 7,
+ .hsync_len = 216,
+ .vsync_len = 37,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-70",
+ .refresh = 70,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9380,
+ .left_margin = 6,
+ .right_margin = 6,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 60,
+ .vsync_len = 94,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x1024-75",
+ .refresh = 75,
+ .xres = 1280,
+ .yres = 1024,
+ .pixclock = 9380,
+ .left_margin = 6,
+ .right_margin = 6,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 60,
+ .vsync_len = 15,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "320x240", /* for AOI only */
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = 15385,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .hsync_len = 0,
+ .vsync_len = 0,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "1280x480-60",
+ .refresh = 60,
+ .xres = 1280,
+ .yres = 480,
+ .pixclock = 18939,
+ .left_margin = 353,
+ .right_margin = 47,
+ .upper_margin = 39,
+ .lower_margin = 4,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+};
+
+static char *fb_mode = "1024x768-32@60";
+static unsigned long default_bpp = 32;
+static int monitor_port;
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+static u8 *coherence_data;
+static size_t coherence_data_size;
+static unsigned int d_cache_line_size;
+#endif
+
+static DEFINE_SPINLOCK(diu_lock);
+
+struct fsl_diu_data {
+ struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
+ /*FSL_AOI_NUM has one dummy AOI */
+ struct device_attribute dev_attr;
+ struct diu_ad *dummy_ad;
+ void *dummy_aoi_virt;
+ unsigned int irq;
+ int fb_enabled;
+ int monitor_port;
+};
+
+struct mfb_info {
+ int index;
+ int type;
+ char *id;
+ int registered;
+ int blank;
+ unsigned long pseudo_palette[16];
+ struct diu_ad *ad;
+ int cursor_reset;
+ unsigned char g_alpha;
+ unsigned int count;
+ int x_aoi_d; /* aoi display x offset to physical screen */
+ int y_aoi_d; /* aoi display y offset to physical screen */
+ struct fsl_diu_data *parent;
+};
+
+
+static struct mfb_info mfb_template[] = {
+ { /* AOI 0 for plane 0 */
+ .index = 0,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel0",
+ .registered = 0,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 0 for plane 1 */
+ .index = 1,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 1 for plane 1 */
+ .index = 2,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel1 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 0,
+ .y_aoi_d = 480,
+ },
+ { /* AOI 0 for plane 2 */
+ .index = 3,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI0",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 0,
+ },
+ { /* AOI 1 for plane 2 */
+ .index = 4,
+ .type = MFB_TYPE_OUTPUT,
+ .id = "Panel2 AOI1",
+ .registered = 0,
+ .g_alpha = 0xff,
+ .count = 0,
+ .x_aoi_d = 640,
+ .y_aoi_d = 480,
+ },
+};
+
+static struct diu_hw dr = {
+ .mode = MFB_MODE1,
+ .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
+};
+
+static struct diu_pool pool;
+
+/* To allocate memory for framebuffer. First try __get_free_pages(). If it
+ * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate
+ * very large memory (more than 4MB). We don't want to allocate all memory
+ * in rheap since small memory allocation/deallocation will fragment the
+ * rheap and make the furture large allocation fail.
+ */
+
+void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
+{
+ void *virt;
+
+ pr_debug("size=%lu\n", size);
+
+ virt = (void *)__get_free_pages(GFP_DMA | __GFP_ZERO, get_order(size));
+ if (virt) {
+ *phys = virt_to_phys(virt);
+ pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys);
+ return virt;
+ }
+ if (!diu_ops.diu_mem) {
+ printk(KERN_INFO "%s: no diu_mem."
+ " To reserve more memory, put 'diufb=15M' "
+ "in the command line\n", __func__);
+ return NULL;
+ }
+
+ virt = (void *)rh_alloc(&diu_ops.diu_rh_info, size, "DIU");
+ if (virt) {
+ *phys = virt_to_bus(virt);
+ memset(virt, 0, size);
+ }
+
+ pr_debug("rh virt=%p phys=%lx\n", virt, *phys);
+
+ return virt;
+}
+
+void fsl_diu_free(void *p, unsigned long size)
+{
+ pr_debug("p=%p size=%lu\n", p, size);
+
+ if (!p)
+ return;
+
+ if ((p >= diu_ops.diu_mem) &&
+ (p < (diu_ops.diu_mem + diu_ops.diu_size))) {
+ pr_debug("rh\n");
+ rh_free(&diu_ops.diu_rh_info, (unsigned long) p);
+ } else {
+ pr_debug("dma\n");
+ free_pages((unsigned long)p, get_order(size));
+ }
+}
+
+static int fsl_diu_enable_panel(struct fb_info *info)
+{
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct diu *hw = dr.diu_reg;
+ struct diu_ad *ad = mfbi->ad;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int res = 0;
+
+ pr_debug("enable_panel index %d\n", mfbi->index);
+ if (mfbi->type != MFB_TYPE_OFF) {
+ switch (mfbi->index) {
+ case 0: /* plane 0 */
+ if (hw->desc[0] != ad->paddr)
+ out_be32(&hw->desc[0], ad->paddr);
+ break;
+ case 1: /* plane 1 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ out_be32(&hw->desc[1], ad->paddr);
+ }
+ break;
+ case 3: /* plane 2 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
+ if (cmfbi->count > 0) /* AOI1 open */
+ ad->next_ad =
+ cpu_to_le32(cmfbi->ad->paddr);
+ else
+ ad->next_ad = 0;
+ out_be32(&hw->desc[2], ad->paddr);
+ }
+ break;
+ case 2: /* plane 1 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ ad->next_ad = 0;
+ if (hw->desc[1] == machine_data->dummy_ad->paddr)
+ out_be32(&hw->desc[1], ad->paddr);
+ else /* AOI0 open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ case 4: /* plane 2 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ ad->next_ad = 0;
+ if (hw->desc[2] == machine_data->dummy_ad->paddr)
+ out_be32(&hw->desc[2], ad->paddr);
+ else /* AOI0 was open */
+ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
+ break;
+ default:
+ res = -EINVAL;
+ break;
+ }
+ } else
+ res = -EINVAL;
+ return res;
+}
+
+static int fsl_diu_disable_panel(struct fb_info *info)
+{
+ struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
+ struct diu *hw = dr.diu_reg;
+ struct diu_ad *ad = mfbi->ad;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int res = 0;
+
+ switch (mfbi->index) {
+ case 0: /* plane 0 */
+ if (hw->desc[0] != machine_data->dummy_ad->paddr)
+ out_be32(&hw->desc[0],
+ machine_data->dummy_ad->paddr);
+ break;
+ case 1: /* plane 1 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[2]->par;
+ if (cmfbi->count > 0) /* AOI1 is open */
+ out_be32(&hw->desc[1], cmfbi->ad->paddr);
+ /* move AOI1 to the first */
+ else /* AOI1 was closed */
+ out_be32(&hw->desc[1],
+ machine_data->dummy_ad->paddr);
+ /* close AOI 0 */
+ break;
+ case 3: /* plane 2 AOI 0 */
+ cmfbi = machine_data->fsl_diu_info[4]->par;
+ if (cmfbi->count > 0) /* AOI1 is open */
+ out_be32(&hw->desc[2], cmfbi->ad->paddr);
+ /* move AOI1 to the first */
+ else /* AOI1 was closed */
+ out_be32(&hw->desc[2],
+ machine_data->dummy_ad->paddr);
+ /* close AOI 0 */
+ break;
+ case 2: /* plane 1 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[1]->par;
+ if (hw->desc[1] != ad->paddr) {
+ /* AOI1 is not the first in the chain */
+ if (pmfbi->count > 0)
+ /* AOI0 is open, must be the first */
+ pmfbi->ad->next_ad = 0;
+ } else /* AOI1 is the first in the chain */
+ out_be32(&hw->desc[1], machine_data->dummy_ad->paddr);
+ /* close AOI 1 */
+ break;
+ case 4: /* plane 2 AOI 1 */
+ pmfbi = machine_data->fsl_diu_info[3]->par;
+ if (hw->desc[2] != ad->paddr) {
+ /* AOI1 is not the first in the chain */
+ if (pmfbi->count > 0)
+ /* AOI0 is open, must be the first */
+ pmfbi->ad->next_ad = 0;
+ } else /* AOI1 is the first in the chain */
+ out_be32(&hw->desc[2], machine_data->dummy_ad->paddr);
+ /* close AOI 1 */
+ break;
+ default:
+ res = -EINVAL;
+ break;
+ }
+
+ return res;
+}
+
+static void enable_lcdc(struct fb_info *info)
+{
+ struct diu *hw = dr.diu_reg;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+
+ if (!machine_data->fb_enabled) {
+ out_be32(&hw->diu_mode, dr.mode);
+ machine_data->fb_enabled++;
+ }
+}
+
+static void disable_lcdc(struct fb_info *info)
+{
+ struct diu *hw = dr.diu_reg;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+
+ if (machine_data->fb_enabled) {
+ out_be32(&hw->diu_mode, 0);
+ machine_data->fb_enabled = 0;
+ }
+}
+
+static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ int available_height, upper_aoi_bottom, index = mfbi->index;
+ int lower_aoi_is_open, upper_aoi_is_open;
+ __u32 base_plane_width, base_plane_height, upper_aoi_height;
+
+ base_plane_width = machine_data->fsl_diu_info[0]->var.xres;
+ base_plane_height = machine_data->fsl_diu_info[0]->var.yres;
+
+ switch (index) {
+ case 0:
+ if (mfbi->x_aoi_d != 0)
+ mfbi->x_aoi_d = 0;
+ if (mfbi->y_aoi_d != 0)
+ mfbi->y_aoi_d = 0;
+ break;
+ case 1: /* AOI 0 */
+ case 3:
+ lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
+ lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
+ if (var->xres > base_plane_width)
+ var->xres = base_plane_width;
+ if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
+ mfbi->x_aoi_d = base_plane_width - var->xres;
+
+ if (lower_aoi_is_open)
+ available_height = lower_aoi_mfbi->y_aoi_d;
+ else
+ available_height = base_plane_height;
+ if (var->yres > available_height)
+ var->yres = available_height;
+ if ((mfbi->y_aoi_d + var->yres) > available_height)
+ mfbi->y_aoi_d = available_height - var->yres;
+ break;
+ case 2: /* AOI 1 */
+ case 4:
+ upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
+ upper_aoi_height =
+ machine_data->fsl_diu_info[index-1]->var.yres;
+ upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
+ upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
+ if (var->xres > base_plane_width)
+ var->xres = base_plane_width;
+ if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
+ mfbi->x_aoi_d = base_plane_width - var->xres;
+ if (mfbi->y_aoi_d < 0)
+ mfbi->y_aoi_d = 0;
+ if (upper_aoi_is_open) {
+ if (mfbi->y_aoi_d < upper_aoi_bottom)
+ mfbi->y_aoi_d = upper_aoi_bottom;
+ available_height = base_plane_height
+ - upper_aoi_bottom;
+ } else
+ available_height = base_plane_height;
+ if (var->yres > available_height)
+ var->yres = available_height;
+ if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
+ mfbi->y_aoi_d = base_plane_height - var->yres;
+ break;
+ }
+}
+/*
+ * Checks to see if the hardware supports the state requested by var passed
+ * in. This function does not alter the hardware state! If the var passed in
+ * is slightly off by what the hardware can support then we alter the var
+ * PASSED in to what we can do. If the hardware doesn't support mode change
+ * a -EINVAL will be returned by the upper layers.
+ */
+static int fsl_diu_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ unsigned long htotal, vtotal;
+
+ pr_debug("check_var xres: %d\n", var->xres);
+ pr_debug("check_var yres: %d\n", var->yres);
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->xoffset < 0)
+ var->xoffset = 0;
+
+ if (var->yoffset < 0)
+ var->yoffset = 0;
+
+ if (var->xoffset + info->var.xres > info->var.xres_virtual)
+ var->xoffset = info->var.xres_virtual - info->var.xres;
+
+ if (var->yoffset + info->var.yres > info->var.yres_virtual)
+ var->yoffset = info->var.yres_virtual - info->var.yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16))
+ var->bits_per_pixel = default_bpp;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 16;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+
+ break;
+ }
+ /* If the pixclock is below the minimum spec'd value then set to
+ * refresh rate for 60Hz since this is supported by most monitors.
+ * Refer to Documentation/fb/ for calculations.
+ */
+ if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) {
+ htotal = var->xres + var->right_margin + var->hsync_len +
+ var->left_margin;
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+ pr_debug("pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ /* Copy nonstd field to/from sync for fbset usage */
+ var->sync |= var->nonstd;
+ var->nonstd |= var->sync;
+
+ adjust_aoi_size_position(var, info);
+ return 0;
+}
+
+static void set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+
+ strncpy(fix->id, mfbi->id, strlen(mfbi->id));
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+}
+
+static void update_lcdc(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu *hw;
+ int i, j;
+ char __iomem *cursor_base, *gamma_table_base;
+
+ u32 temp;
+
+ hw = dr.diu_reg;
+
+ if (mfbi->type == MFB_TYPE_OFF) {
+ fsl_diu_disable_panel(info);
+ return;
+ }
+
+ diu_ops.set_monitor_port(machine_data->monitor_port);
+ gamma_table_base = pool.gamma.vaddr;
+ cursor_base = pool.cursor.vaddr;
+ /* Prep for DIU init - gamma table, cursor table */
+
+ for (i = 0; i <= 2; i++)
+ for (j = 0; j <= 255; j++)
+ *gamma_table_base++ = j;
+
+ diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
+
+ pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
+ disable_lcdc(info);
+
+ /* Program DIU registers */
+
+ out_be32(&hw->gamma, pool.gamma.paddr);
+ out_be32(&hw->cursor, pool.cursor.paddr);
+
+ out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */
+ out_be32(&hw->bgnd_wb, 0); /* BGND_WB */
+ out_be32(&hw->disp_size, (var->yres << 16 | var->xres));
+ /* DISP SIZE */
+ pr_debug("DIU xres: %d\n", var->xres);
+ pr_debug("DIU yres: %d\n", var->yres);
+
+ out_be32(&hw->wb_size, 0); /* WB SIZE */
+ out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
+
+ /* Horizontal and vertical configuration register */
+ temp = var->left_margin << 22 | /* BP_H */
+ var->hsync_len << 11 | /* PW_H */
+ var->right_margin; /* FP_H */
+
+ out_be32(&hw->hsyn_para, temp);
+
+ temp = var->upper_margin << 22 | /* BP_V */
+ var->vsync_len << 11 | /* PW_V */
+ var->lower_margin; /* FP_V */
+
+ out_be32(&hw->vsyn_para, temp);
+
+ pr_debug("DIU right_margin - %d\n", var->right_margin);
+ pr_debug("DIU left_margin - %d\n", var->left_margin);
+ pr_debug("DIU hsync_len - %d\n", var->hsync_len);
+ pr_debug("DIU upper_margin - %d\n", var->upper_margin);
+ pr_debug("DIU lower_margin - %d\n", var->lower_margin);
+ pr_debug("DIU vsync_len - %d\n", var->vsync_len);
+ pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
+ pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
+
+ diu_ops.set_pixel_clock(var->pixclock);
+
+ out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */
+ out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */
+ out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */
+ out_be32(&hw->plut, 0x01F5F666);
+
+ /* Enable the DIU */
+ enable_lcdc(info);
+}
+
+static int map_video_memory(struct fb_info *info)
+{
+ phys_addr_t phys;
+
+ pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
+ pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+ pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+
+ info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
+ pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
+ info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+ if (info->screen_base == 0) {
+ printk(KERN_ERR "Unable to allocate fb memory\n");
+ return -ENOMEM;
+ }
+ info->fix.smem_start = (unsigned long) phys;
+ info->screen_size = info->fix.smem_len;
+
+ pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
+ info->fix.smem_start,
+ info->fix.smem_len);
+ pr_debug("screen base %p\n", info->screen_base);
+
+ return 0;
+}
+
+static void unmap_video_memory(struct fb_info *info)
+{
+ fsl_diu_free(info->screen_base, info->fix.smem_len);
+ info->screen_base = 0;
+ info->fix.smem_start = 0;
+ info->fix.smem_len = 0;
+}
+
+/*
+ * Using the fb_var_screeninfo in fb_info we set the resolution of this
+ * particular framebuffer. This function alters the fb_fix_screeninfo stored
+ * in fb_info. It does not alter var in fb_info since we are using that
+ * data. This means we depend on the data in var inside fb_info to be
+ * supported by the hardware. fsl_diu_check_var is always called before
+ * fsl_diu_set_par to ensure this.
+ */
+static int fsl_diu_set_par(struct fb_info *info)
+{
+ unsigned long len;
+ struct fb_var_screeninfo *var = &info->var;
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *machine_data = mfbi->parent;
+ struct diu_ad *ad = mfbi->ad;
+ struct diu *hw;
+
+ hw = dr.diu_reg;
+
+ set_fix(info);
+ mfbi->cursor_reset = 1;
+
+ len = info->var.yres_virtual * info->fix.line_length;
+ /* Alloc & dealloc each time resolution/bpp change */
+ if (len != info->fix.smem_len) {
+ if (info->fix.smem_start)
+ unmap_video_memory(info);
+ pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
+
+ /* Memory allocation for framebuffer */
+ if (map_video_memory(info)) {
+ printk(KERN_ERR "Unable to allocate fb memory 1\n");
+ return -ENOMEM;
+ }
+ }
+
+ ad->pix_fmt =
+ diu_ops.get_pixel_format(var->bits_per_pixel,
+ machine_data->monitor_port);
+ ad->addr = cpu_to_le32(info->fix.smem_start);
+ ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) |
+ var->xres) | mfbi->g_alpha;
+ /* fix me. AOI should not be greater than display size */
+ ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres);
+ ad->offset_xyi = 0;
+ ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
+
+ /* Disable chroma keying function */
+ ad->ckmax_r = 0;
+ ad->ckmax_g = 0;
+ ad->ckmax_b = 0;
+
+ ad->ckmin_r = 255;
+ ad->ckmin_g = 255;
+ ad->ckmin_b = 255;
+
+ if (mfbi->index == 0)
+ update_lcdc(info);
+ return 0;
+}
+
+static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
+{
+ return ((val<<width) + 0x7FFF - val)>>16;
+}
+
+/*
+ * Set a single color register. The values supplied have a 16 bit magnitude
+ * which needs to be scaled in this function for the hardware. Things to take
+ * into consideration are how many color registers, if any, are supported with
+ * the current color visual. With truecolor mode no color palettes are
+ * supported. Here a psuedo palette is created which we store the value in
+ * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
+ * color palette.
+ */
+static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+ u32 v;
+
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ pal[regno] = v;
+ ret = 0;
+ }
+ break;
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
+ * don't fit, return -EINVAL.
+ */
+static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if ((info->var.xoffset == var->xoffset) &&
+ (info->var.yoffset == var->yoffset))
+ return 0; /* No change, do nothing */
+
+ if (var->xoffset < 0 || var->yoffset < 0
+ || var->xoffset + info->var.xres > info->var.xres_virtual
+ || var->yoffset + info->var.yres > info->var.yres_virtual)
+ return -EINVAL;
+
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+ return 0;
+}
+
+/*
+ * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
+ * succeeded, != 0 if un-/blanking failed.
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ */
+static int fsl_diu_blank(int blank_mode, struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ mfbi->blank = blank_mode;
+
+ switch (blank_mode) {
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ /* FIXME: fixes to enable_panel and enable lcdc needed */
+ case FB_BLANK_NORMAL:
+ /* fsl_diu_disable_panel(info);*/
+ break;
+ case FB_BLANK_POWERDOWN:
+ /* disable_lcdc(info); */
+ break;
+ case FB_BLANK_UNBLANK:
+ /* fsl_diu_enable_panel(info);*/
+ break;
+ }
+
+ return 0;
+}
+
+static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mfb_info *mfbi = info->par;
+ struct diu_ad *ad = mfbi->ad;
+ struct mfb_chroma_key ck;
+ unsigned char global_alpha;
+ struct aoi_display_offset aoi_d;
+ __u32 pix_fmt;
+ void __user *buf = (void __user *)arg;
+
+ if (!arg)
+ return -EINVAL;
+ switch (cmd) {
+ case MFB_SET_PIXFMT:
+ if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
+ return -EFAULT;
+ ad->pix_fmt = pix_fmt;
+ pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
+ break;
+ case MFB_GET_PIXFMT:
+ pix_fmt = ad->pix_fmt;
+ if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
+ return -EFAULT;
+ pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
+ break;
+ case MFB_SET_AOID:
+ if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
+ return -EFAULT;
+ mfbi->x_aoi_d = aoi_d.x_aoi_d;
+ mfbi->y_aoi_d = aoi_d.y_aoi_d;
+ pr_debug("set AOI display offset of index %d to (%d,%d)\n",
+ mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+ fsl_diu_check_var(&info->var, info);
+ fsl_diu_set_par(info);
+ break;
+ case MFB_GET_AOID:
+ aoi_d.x_aoi_d = mfbi->x_aoi_d;
+ aoi_d.y_aoi_d = mfbi->y_aoi_d;
+ if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
+ return -EFAULT;
+ pr_debug("get AOI display offset of index %d (%d,%d)\n",
+ mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
+ break;
+ case MFB_GET_ALPHA:
+ global_alpha = mfbi->g_alpha;
+ if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
+ return -EFAULT;
+ pr_debug("get global alpha of index %d\n", mfbi->index);
+ break;
+ case MFB_SET_ALPHA:
+ /* set panel information */
+ if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
+ return -EFAULT;
+ ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
+ (global_alpha & 0xff);
+ mfbi->g_alpha = global_alpha;
+ pr_debug("set global alpha for index %d\n", mfbi->index);
+ break;
+ case MFB_SET_CHROMA_KEY:
+ /* set panel winformation */
+ if (copy_from_user(&ck, buf, sizeof(ck)))
+ return -EFAULT;
+
+ if (ck.enable &&
+ (ck.red_max < ck.red_min ||
+ ck.green_max < ck.green_min ||
+ ck.blue_max < ck.blue_min))
+ return -EINVAL;
+
+ if (!ck.enable) {
+ ad->ckmax_r = 0;
+ ad->ckmax_g = 0;
+ ad->ckmax_b = 0;
+ ad->ckmin_r = 255;
+ ad->ckmin_g = 255;
+ ad->ckmin_b = 255;
+ } else {
+ ad->ckmax_r = ck.red_max;
+ ad->ckmax_g = ck.green_max;
+ ad->ckmax_b = ck.blue_max;
+ ad->ckmin_r = ck.red_min;
+ ad->ckmin_g = ck.green_min;
+ ad->ckmin_b = ck.blue_min;
+ }
+ pr_debug("set chroma key\n");
+ break;
+ case FBIOGET_GWINFO:
+ if (mfbi->type == MFB_TYPE_OFF)
+ return -ENODEV;
+ /* get graphic window information */
+ if (copy_to_user(buf, ad, sizeof(*ad)))
+ return -EFAULT;
+ break;
+ case FBIOGET_HWCINFO:
+ pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
+ break;
+ case FBIOPUT_MODEINFO:
+ pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
+ break;
+ case FBIOGET_DISPINFO:
+ pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+/* turn on fb if count == 1
+ */
+static int fsl_diu_open(struct fb_info *info, int user)
+{
+ struct mfb_info *mfbi = info->par;
+ int res = 0;
+
+ spin_lock(&diu_lock);
+ mfbi->count++;
+ if (mfbi->count == 1) {
+ pr_debug("open plane index %d\n", mfbi->index);
+ fsl_diu_check_var(&info->var, info);
+ res = fsl_diu_set_par(info);
+ if (res < 0)
+ mfbi->count--;
+ else {
+ res = fsl_diu_enable_panel(info);
+ if (res < 0)
+ mfbi->count--;
+ }
+ }
+
+ spin_unlock(&diu_lock);
+ return res;
+}
+
+/* turn off fb if count == 0
+ */
+static int fsl_diu_release(struct fb_info *info, int user)
+{
+ struct mfb_info *mfbi = info->par;
+ int res = 0;
+
+ spin_lock(&diu_lock);
+ mfbi->count--;
+ if (mfbi->count == 0) {
+ pr_debug("release plane index %d\n", mfbi->index);
+ res = fsl_diu_disable_panel(info);
+ if (res < 0)
+ mfbi->count++;
+ }
+ spin_unlock(&diu_lock);
+ return res;
+}
+
+static struct fb_ops fsl_diu_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = fsl_diu_check_var,
+ .fb_set_par = fsl_diu_set_par,
+ .fb_setcolreg = fsl_diu_setcolreg,
+ .fb_blank = fsl_diu_blank,
+ .fb_pan_display = fsl_diu_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_ioctl = fsl_diu_ioctl,
+ .fb_open = fsl_diu_open,
+ .fb_release = fsl_diu_release,
+};
+
+static int init_fbinfo(struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ info->device = NULL;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->fbops = &fsl_diu_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->pseudo_palette = &mfbi->pseudo_palette;
+
+ /* Allocate colormap */
+ fb_alloc_cmap(&info->cmap, 16, 0);
+ return 0;
+}
+
+static int install_fb(struct fb_info *info)
+{
+ int rc;
+ struct mfb_info *mfbi = info->par;
+ const char *aoi_mode, *init_aoi_mode = "320x240";
+
+ if (init_fbinfo(info))
+ return -EINVAL;
+
+ if (mfbi->index == 0) /* plane 0 */
+ aoi_mode = fb_mode;
+ else
+ aoi_mode = init_aoi_mode;
+ pr_debug("mode used = %s\n", aoi_mode);
+ rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
+ ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
+
+ switch (rc) {
+ case 1:
+ pr_debug("using mode specified in @mode\n");
+ break;
+ case 2:
+ pr_debug("using mode specified in @mode "
+ "with ignored refresh rate\n");
+ break;
+ case 3:
+ pr_debug("using mode default mode\n");
+ break;
+ case 4:
+ pr_debug("using mode from list\n");
+ break;
+ default:
+ pr_debug("rc = %d\n", rc);
+ pr_debug("failed to find mode\n");
+ return -EINVAL;
+ break;
+ }
+
+ pr_debug("xres_virtual %d\n", info->var.xres_virtual);
+ pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
+
+ pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
+ pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+
+ if (mfbi->type == MFB_TYPE_OFF)
+ mfbi->blank = FB_BLANK_NORMAL;
+ else
+ mfbi->blank = FB_BLANK_UNBLANK;
+
+ if (fsl_diu_check_var(&info->var, info)) {
+ printk(KERN_ERR "fb_check_var failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (fsl_diu_set_par(info)) {
+ printk(KERN_ERR "fb_set_par failed");
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ if (register_framebuffer(info) < 0) {
+ printk(KERN_ERR "register_framebuffer failed");
+ unmap_video_memory(info);
+ fb_dealloc_cmap(&info->cmap);
+ return -EINVAL;
+ }
+
+ mfbi->registered = 1;
+ printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
+ info->node, info->fix.id);
+
+ return 0;
+}
+
+static void __exit uninstall_fb(struct fb_info *info)
+{
+ struct mfb_info *mfbi = info->par;
+
+ if (!mfbi->registered)
+ return;
+
+ unregister_framebuffer(info);
+ unmap_video_memory(info);
+ if (&info->cmap)
+ fb_dealloc_cmap(&info->cmap);
+
+ mfbi->registered = 0;
+}
+
+static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
+{
+ struct diu *hw = dr.diu_reg;
+ unsigned int status = in_be32(&hw->int_status);
+
+ if (status) {
+ /* This is the workaround for underrun */
+ if (status & INT_UNDRUN) {
+ out_be32(&hw->diu_mode, 0);
+ pr_debug("Err: DIU occurs underrun!\n");
+ udelay(1);
+ out_be32(&hw->diu_mode, 1);
+ }
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ else if (status & INT_VSYNC) {
+ unsigned int i;
+ for (i = 0; i < coherence_data_size;
+ i += d_cache_line_size)
+ __asm__ __volatile__ (
+ "dcbz 0, %[input]"
+ ::[input]"r"(&coherence_data[i]));
+ }
+#endif
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int request_irq_local(int irq)
+{
+ unsigned long status, ints;
+ struct diu *hw;
+ int ret;
+
+ hw = dr.diu_reg;
+
+ /* Read to clear the status */
+ status = in_be32(&hw->int_status);
+
+ ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0);
+ if (ret)
+ pr_info("Request diu IRQ failed.\n");
+ else {
+ ints = INT_PARERR | INT_LS_BF_VS;
+#if !defined(CONFIG_NOT_COHERENT_CACHE)
+ ints |= INT_VSYNC;
+#endif
+ if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
+ ints |= INT_VSYNC_WB;
+
+ /* Read to clear the status */
+ status = in_be32(&hw->int_status);
+ out_be32(&hw->int_mask, ints);
+ }
+ return ret;
+}
+
+static void free_irq_local(int irq)
+{
+ struct diu *hw = dr.diu_reg;
+
+ /* Disable all LCDC interrupt */
+ out_be32(&hw->int_mask, 0x1f);
+
+ free_irq(irq, 0);
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int fsl_diu_suspend(struct of_device *dev, pm_message_t state)
+{
+ struct fsl_diu_data *machine_data;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ disable_lcdc(machine_data->fsl_diu_info[0]);
+
+ return 0;
+}
+
+static int fsl_diu_resume(struct of_device *dev)
+{
+ struct fsl_diu_data *machine_data;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ enable_lcdc(machine_data->fsl_diu_info[0]);
+
+ return 0;
+}
+
+#else
+#define fsl_diu_suspend NULL
+#define fsl_diu_resume NULL
+#endif /* CONFIG_PM */
+
+/* Align to 64-bit(8-byte), 32-byte, etc. */
+static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ u32 offset, ssize;
+ u32 mask;
+ dma_addr_t paddr = 0;
+
+ ssize = size + bytes_align;
+ buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO);
+ if (!buf->vaddr)
+ return -ENOMEM;
+
+ buf->paddr = (__u32) paddr;
+
+ mask = bytes_align - 1;
+ offset = (u32)buf->paddr & mask;
+ if (offset) {
+ buf->offset = bytes_align - offset;
+ buf->paddr = (u32)buf->paddr + offset;
+ } else
+ buf->offset = 0;
+ return 0;
+}
+
+static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ dma_free_coherent(0, size + bytes_align,
+ buf->vaddr, (buf->paddr - buf->offset));
+ return;
+}
+
+static ssize_t store_monitor(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int old_monitor_port;
+ unsigned long val;
+ struct fsl_diu_data *machine_data =
+ container_of(attr, struct fsl_diu_data, dev_attr);
+
+ if (strict_strtoul(buf, 10, &val))
+ return 0;
+
+ old_monitor_port = machine_data->monitor_port;
+ machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
+
+ if (old_monitor_port != machine_data->monitor_port) {
+ /* All AOIs need adjust pixel format
+ * fsl_diu_set_par only change the pixsel format here
+ * unlikely to fail. */
+ fsl_diu_set_par(machine_data->fsl_diu_info[0]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[1]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[2]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[3]);
+ fsl_diu_set_par(machine_data->fsl_diu_info[4]);
+ }
+ return count;
+}
+
+static ssize_t show_monitor(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fsl_diu_data *machine_data =
+ container_of(attr, struct fsl_diu_data, dev_attr);
+ return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
+}
+
+static int fsl_diu_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct mfb_info *mfbi;
+ phys_addr_t dummy_ad_addr;
+ int ret, i, error = 0;
+ struct resource res;
+ struct fsl_diu_data *machine_data;
+
+ machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
+ if (!machine_data)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
+ machine_data->fsl_diu_info[i] =
+ framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
+ if (!machine_data->fsl_diu_info[i]) {
+ dev_err(&ofdev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto error2;
+ }
+ mfbi = machine_data->fsl_diu_info[i]->par;
+ memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
+ mfbi->parent = machine_data;
+ }
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&ofdev->dev, "could not obtain DIU address\n");
+ goto error;
+ }
+ if (!res.start) {
+ dev_err(&ofdev->dev, "invalid DIU address\n");
+ goto error;
+ }
+ dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
+
+ dr.diu_reg = ioremap(res.start, sizeof(struct diu));
+ if (!dr.diu_reg) {
+ dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
+ ret = -EFAULT;
+ goto error2;
+ }
+
+ out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/
+
+ /* Get the IRQ of the DIU */
+ machine_data->irq = irq_of_parse_and_map(np, 0);
+
+ if (!machine_data->irq) {
+ dev_err(&ofdev->dev, "could not get DIU IRQ\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ machine_data->monitor_port = monitor_port;
+
+ /* Area descriptor memory pool aligns to 64-bit boundary */
+ if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
+ return -ENOMEM;
+
+ /* Get memory for Gamma Table - 32-byte aligned memory */
+ if (allocate_buf(&pool.gamma, 768, 32)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
+ if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ i = ARRAY_SIZE(machine_data->fsl_diu_info);
+ machine_data->dummy_ad = (struct diu_ad *)
+ ((u32)pool.ad.vaddr + pool.ad.offset) + i;
+ machine_data->dummy_ad->paddr = pool.ad.paddr +
+ i * sizeof(struct diu_ad);
+ machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
+ if (!machine_data->dummy_aoi_virt) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
+ machine_data->dummy_ad->pix_fmt = 0x88882317;
+ machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
+ machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2);
+ machine_data->dummy_ad->offset_xyi = 0;
+ machine_data->dummy_ad->offset_xyd = 0;
+ machine_data->dummy_ad->next_ad = 0;
+
+ out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+ out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
+ out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
+
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
+ machine_data->fsl_diu_info[i]->fix.smem_start = 0;
+ mfbi = machine_data->fsl_diu_info[i]->par;
+ mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
+ + pool.ad.offset) + i;
+ mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
+ ret = install_fb(machine_data->fsl_diu_info[i]);
+ if (ret) {
+ dev_err(&ofdev->dev,
+ "Failed to register framebuffer %d\n",
+ i);
+ goto error;
+ }
+ }
+
+ if (request_irq_local(machine_data->irq)) {
+ dev_err(machine_data->fsl_diu_info[0]->dev,
+ "could not request irq for diu.");
+ goto error;
+ }
+
+ machine_data->dev_attr.attr.name = "monitor";
+ machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
+ machine_data->dev_attr.show = show_monitor;
+ machine_data->dev_attr.store = store_monitor;
+ error = device_create_file(machine_data->fsl_diu_info[0]->dev,
+ &machine_data->dev_attr);
+ if (error) {
+ dev_err(machine_data->fsl_diu_info[0]->dev,
+ "could not create sysfs %s file\n",
+ machine_data->dev_attr.attr.name);
+ }
+
+ dev_set_drvdata(&ofdev->dev, machine_data);
+ return 0;
+
+error:
+ for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
+ i > 0; i--)
+ uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+ if (pool.ad.vaddr)
+ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+ if (pool.gamma.vaddr)
+ free_buf(&pool.gamma, 768, 32);
+ if (pool.cursor.vaddr)
+ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+ if (machine_data->dummy_aoi_virt)
+ fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+ iounmap(dr.diu_reg);
+
+error2:
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+ if (machine_data->fsl_diu_info[i])
+ framebuffer_release(machine_data->fsl_diu_info[i]);
+ kfree(machine_data);
+
+ return ret;
+}
+
+
+static int fsl_diu_remove(struct of_device *ofdev)
+{
+ struct fsl_diu_data *machine_data;
+ int i;
+
+ machine_data = dev_get_drvdata(&ofdev->dev);
+ disable_lcdc(machine_data->fsl_diu_info[0]);
+ free_irq_local(machine_data->irq);
+ for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
+ uninstall_fb(machine_data->fsl_diu_info[i - 1]);
+ if (pool.ad.vaddr)
+ free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
+ if (pool.gamma.vaddr)
+ free_buf(&pool.gamma, 768, 32);
+ if (pool.cursor.vaddr)
+ free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32);
+ if (machine_data->dummy_aoi_virt)
+ fsl_diu_free(machine_data->dummy_aoi_virt, 64);
+ iounmap(dr.diu_reg);
+ for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
+ if (machine_data->fsl_diu_info[i])
+ framebuffer_release(machine_data->fsl_diu_info[i]);
+ kfree(machine_data);
+
+ return 0;
+}
+
+#ifndef MODULE
+static int __init fsl_diu_setup(char *options)
+{
+ char *opt;
+ unsigned long val;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "monitor=", 8)) {
+ if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
+ monitor_port = val;
+ } else if (!strncmp(opt, "bpp=", 4)) {
+ if (!strict_strtoul(opt + 4, 10, &val))
+ default_bpp = val;
+ } else
+ fb_mode = opt;
+ }
+
+ return 0;
+}
+#endif
+
+static struct of_device_id fsl_diu_match[] = {
+ {
+ .compatible = "fsl,diu",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_diu_match);
+
+static struct of_platform_driver fsl_diu_driver = {
+ .owner = THIS_MODULE,
+ .name = "fsl_diu",
+ .match_table = fsl_diu_match,
+ .probe = fsl_diu_probe,
+ .remove = fsl_diu_remove,
+ .suspend = fsl_diu_suspend,
+ .resume = fsl_diu_resume,
+};
+
+static int __init fsl_diu_init(void)
+{
+#ifdef CONFIG_NOT_COHERENT_CACHE
+ struct device_node *np;
+ const u32 *prop;
+#endif
+ int ret;
+#ifndef MODULE
+ char *option;
+
+ /*
+ * For kernel boot options (in 'video=xxxfb:<options>' format)
+ */
+ if (fb_get_options("fslfb", &option))
+ return -ENODEV;
+ fsl_diu_setup(option);
+#endif
+ printk(KERN_INFO "Freescale DIU driver\n");
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+ np = of_find_node_by_type(NULL, "cpu");
+ if (!np) {
+ printk(KERN_ERR "Err: can't find device node 'cpu'\n");
+ return -ENODEV;
+ }
+
+ prop = of_get_property(np, "d-cache-size", NULL);
+ if (prop == NULL)
+ return -ENODEV;
+
+ /* Freescale PLRU requires 13/8 times the cache size to do a proper
+ displacement flush
+ */
+ coherence_data_size = *prop * 13;
+ coherence_data_size /= 8;
+
+ prop = of_get_property(np, "d-cache-line-size", NULL);
+ if (prop == NULL)
+ return -ENODEV;
+ d_cache_line_size = *prop;
+
+ of_node_put(np);
+ coherence_data = vmalloc(coherence_data_size);
+ if (!coherence_data)
+ return -ENOMEM;
+#endif
+ ret = of_register_platform_driver(&fsl_diu_driver);
+ if (ret) {
+ printk(KERN_ERR
+ "fsl-diu: failed to register platform driver\n");
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ vfree(coherence_data);
+#endif
+ iounmap(dr.diu_reg);
+ }
+ return ret;
+}
+
+static void __exit fsl_diu_exit(void)
+{
+ of_unregister_platform_driver(&fsl_diu_driver);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ vfree(coherence_data);
+#endif
+}
+
+module_init(fsl_diu_init);
+module_exit(fsl_diu_exit);
+
+MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
+MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
+MODULE_LICENSE("GPL");
+
+module_param_named(mode, fb_mode, charp, 0);
+MODULE_PARM_DESC(mode,
+ "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+module_param_named(bpp, default_bpp, ulong, 0);
+MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
+module_param_named(monitor, monitor_port, int, 0);
+MODULE_PARM_DESC(monitor,
+ "Specify the monitor port (0, 1 or 2) if supported by the platform");
+
diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h
new file mode 100644
index 000000000000..fc295d7ea463
--- /dev/null
+++ b/drivers/video/fsl-diu-fb.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale DIU Frame Buffer device driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Paul Widmer <paul.widmer@freescale.com>
+ * Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ * York Sun <yorksun@freescale.com>
+ *
+ * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __FSL_DIU_FB_H__
+#define __FSL_DIU_FB_H__
+
+/* Arbitrary threshold to determine the allocation method
+ * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
+ */
+#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
+/* Minimum value that the pixel clock can be set to in pico seconds
+ * This is determined by platform clock/3 where the minimum platform
+ * clock is 533MHz. This gives 5629 pico seconds.
+ */
+#define MIN_PIX_CLK 5629
+#define MAX_PIX_CLK 96096
+
+#include <linux/types.h>
+
+struct mfb_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mfb_chroma_key {
+ int enable;
+ __u8 red_max;
+ __u8 green_max;
+ __u8 blue_max;
+ __u8 red_min;
+ __u8 green_min;
+ __u8 blue_min;
+};
+
+struct aoi_display_offset {
+ int x_aoi_d;
+ int y_aoi_d;
+};
+
+#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key)
+#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
+#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8)
+
+#define MFB_SET_ALPHA 0x80014d00
+#define MFB_GET_ALPHA 0x40014d00
+#define MFB_SET_AOID 0x80084d04
+#define MFB_GET_AOID 0x40084d04
+#define MFB_SET_PIXFMT 0x80014d08
+#define MFB_GET_PIXFMT 0x40014d08
+
+#define FBIOGET_GWINFO 0x46E0
+#define FBIOPUT_GWINFO 0x46E1
+
+#ifdef __KERNEL__
+#include <linux/spinlock.h>
+
+/*
+ * These are the fields of area descriptor(in DDR memory) for every plane
+ */
+struct diu_ad {
+ /* Word 0(32-bit) in DDR memory */
+/* __u16 comp; */
+/* __u16 pixel_s:2; */
+/* __u16 pallete:1; */
+/* __u16 red_c:2; */
+/* __u16 green_c:2; */
+/* __u16 blue_c:2; */
+/* __u16 alpha_c:3; */
+/* __u16 byte_f:1; */
+/* __u16 res0:3; */
+
+ __be32 pix_fmt; /* hard coding pixel format */
+
+ /* Word 1(32-bit) in DDR memory */
+ __le32 addr;
+
+ /* Word 2(32-bit) in DDR memory */
+/* __u32 delta_xs:11; */
+/* __u32 res1:1; */
+/* __u32 delta_ys:11; */
+/* __u32 res2:1; */
+/* __u32 g_alpha:8; */
+ __le32 src_size_g_alpha;
+
+ /* Word 3(32-bit) in DDR memory */
+/* __u32 delta_xi:11; */
+/* __u32 res3:5; */
+/* __u32 delta_yi:11; */
+/* __u32 res4:3; */
+/* __u32 flip:2; */
+ __le32 aoi_size;
+
+ /* Word 4(32-bit) in DDR memory */
+ /*__u32 offset_xi:11;
+ __u32 res5:5;
+ __u32 offset_yi:11;
+ __u32 res6:5;
+ */
+ __le32 offset_xyi;
+
+ /* Word 5(32-bit) in DDR memory */
+ /*__u32 offset_xd:11;
+ __u32 res7:5;
+ __u32 offset_yd:11;
+ __u32 res8:5; */
+ __le32 offset_xyd;
+
+
+ /* Word 6(32-bit) in DDR memory */
+ __u8 ckmax_r;
+ __u8 ckmax_g;
+ __u8 ckmax_b;
+ __u8 res9;
+
+ /* Word 7(32-bit) in DDR memory */
+ __u8 ckmin_r;
+ __u8 ckmin_g;
+ __u8 ckmin_b;
+ __u8 res10;
+/* __u32 res10:8; */
+
+ /* Word 8(32-bit) in DDR memory */
+ __le32 next_ad;
+
+ /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
+ __u32 paddr;
+} __attribute__ ((packed));
+
+/* DIU register map */
+struct diu {
+ __be32 desc[3];
+ __be32 gamma;
+ __be32 pallete;
+ __be32 cursor;
+ __be32 curs_pos;
+ __be32 diu_mode;
+ __be32 bgnd;
+ __be32 bgnd_wb;
+ __be32 disp_size;
+ __be32 wb_size;
+ __be32 wb_mem_addr;
+ __be32 hsyn_para;
+ __be32 vsyn_para;
+ __be32 syn_pol;
+ __be32 thresholds;
+ __be32 int_status;
+ __be32 int_mask;
+ __be32 colorbar[8];
+ __be32 filling;
+ __be32 plut;
+} __attribute__ ((packed));
+
+struct diu_hw {
+ struct diu *diu_reg;
+ spinlock_t reg_lock;
+
+ __u32 mode; /* DIU operation mode */
+};
+
+struct diu_addr {
+ __u8 __iomem *vaddr; /* Virtual address */
+ dma_addr_t paddr; /* Physical address */
+ __u32 offset;
+};
+
+struct diu_pool {
+ struct diu_addr ad;
+ struct diu_addr gamma;
+ struct diu_addr pallete;
+ struct diu_addr cursor;
+};
+
+#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */
+#define INT_LCDC 64 /* DIU interrupt number */
+
+#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
+ /* 1 for plane 0, 2 for plane 1&2 each */
+
+/* Minimum X and Y resolutions */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
+/* HW cursor parameters */
+#define MAX_CURS 32
+
+/* Modes of operation of DIU */
+#define MFB_MODE0 0 /* DIU off */
+#define MFB_MODE1 1 /* All three planes output to display */
+#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
+#define MFB_MODE3 3 /* All three planes written back to memory */
+#define MFB_MODE4 4 /* Color bar generation */
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC 0x01 /* Vsync interrupt */
+#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
+#define INT_UNDRUN 0x04 /* Under run exception interrupt */
+#define INT_PARERR 0x08 /* Display parameters error interrupt */
+#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
+
+/* Panels'operation modes */
+#define MFB_TYPE_OUTPUT 0 /* Panel output to display */
+#define MFB_TYPE_OFF 1 /* Panel off */
+#define MFB_TYPE_WB 2 /* Panel written back to memory */
+#define MFB_TYPE_TEST 3 /* Panel generate color bar */
+
+#endif /* __KERNEL__ */
+#endif /* __FSL_DIU_FB_H__ */
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index 7608429b3943..c5d8ba4b9fc3 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -38,26 +38,6 @@ config FB_GEODE_GX
If unsure, say N.
-config FB_GEODE_GX_SET_FBSIZE
- bool "Manually specify the Geode GX framebuffer size"
- depends on FB_GEODE_GX
- default n
- ---help---
- If you want to manually specify the size of your GX framebuffer,
- say Y here, otherwise say N to dynamically probe it.
-
- Say N unless you know what you are doing.
-
-config FB_GEODE_GX_FBSIZE
- hex "Size of the GX framebuffer, in bytes"
- depends on FB_GEODE_GX_SET_FBSIZE
- default "0x1600000"
- ---help---
- Specify the size of the GX framebuffer. Normally, you will
- want this to be MB aligned. Common values are 0x80000 (8MB)
- and 0x1600000 (16MB). Don't change this unless you know what
- you are doing
-
config FB_GEODE_GX1
tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
depends on FB && FB_GEODE && EXPERIMENTAL
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
index 957304b45fba..5c98da126883 100644
--- a/drivers/video/geode/Makefile
+++ b/drivers/video/geode/Makefile
@@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o
obj-$(CONFIG_FB_GEODE_LX) += lxfb.o
gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
-gxfb-objs := gxfb_core.o display_gx.o video_gx.o
+gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o
lxfb-objs := lxfb_core.o lxfb_ops.o
diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c
index 0f16e4bffc6c..e759895bf3d3 100644
--- a/drivers/video/geode/display_gx.c
+++ b/drivers/video/geode/display_gx.c
@@ -17,31 +17,40 @@
#include <asm/io.h>
#include <asm/div64.h>
#include <asm/delay.h>
+#include <asm/geode.h>
-#include "geodefb.h"
-#include "display_gx.h"
+#include "gxfb.h"
-#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
-unsigned int gx_frame_buffer_size(void)
-{
- return CONFIG_FB_GEODE_GX_FBSIZE;
-}
-#else
unsigned int gx_frame_buffer_size(void)
{
unsigned int val;
- /* FB size is reported by a virtual register */
+ if (!geode_has_vsa2()) {
+ uint32_t hi, lo;
+
+ /* The number of pages is (PMAX - PMIN)+1 */
+ rdmsr(MSR_GLIU_P2D_RO0, lo, hi);
+
+ /* PMAX */
+ val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
+ /* PMIN */
+ val -= (lo & 0x000fffff);
+ val += 1;
+
+ /* The page size is 4k */
+ return (val << 12);
+ }
+
+ /* FB size can be obtained from the VSA II */
/* Virtual register class = 0x02 */
/* VG_MEM_SIZE(512Kb units) = 0x00 */
- outw(0xFC53, 0xAC1C);
- outw(0x0200, 0xAC1C);
+ outw(VSA_VR_UNLOCK, VSA_VRC_INDEX);
+ outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX);
- val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
+ val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFFl;
return (val << 19);
}
-#endif
int gx_line_delta(int xres, int bpp)
{
@@ -49,75 +58,76 @@ int gx_line_delta(int xres, int bpp)
return (xres * (bpp >> 3) + 7) & ~0x7;
}
-static void gx_set_mode(struct fb_info *info)
+void gx_set_mode(struct fb_info *info)
{
- struct geodefb_par *par = info->par;
+ struct gxfb_par *par = info->par;
u32 gcfg, dcfg;
int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
/* Unlock the display controller registers. */
- readl(par->dc_regs + DC_UNLOCK);
- writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
- gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
- dcfg = readl(par->dc_regs + DC_DISPLAY_CFG);
+ gcfg = read_dc(par, DC_GENERAL_CFG);
+ dcfg = read_dc(par, DC_DISPLAY_CFG);
/* Disable the timing generator. */
- dcfg &= ~(DC_DCFG_TGEN);
- writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
+ dcfg &= ~DC_DISPLAY_CFG_TGEN;
+ write_dc(par, DC_DISPLAY_CFG, dcfg);
/* Wait for pending memory requests before disabling the FIFO load. */
udelay(100);
/* Disable FIFO load and compression. */
- gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
- writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+ gcfg &= ~(DC_GENERAL_CFG_DFLE | DC_GENERAL_CFG_CMPE |
+ DC_GENERAL_CFG_DECE);
+ write_dc(par, DC_GENERAL_CFG, gcfg);
/* Setup DCLK and its divisor. */
- par->vid_ops->set_dclk(info);
+ gx_set_dclk_frequency(info);
/*
* Setup new mode.
*/
/* Clear all unused feature bits. */
- gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE;
+ gcfg &= DC_GENERAL_CFG_YUVM | DC_GENERAL_CFG_VDSE;
dcfg = 0;
/* Set FIFO priority (default 6/5) and enable. */
/* FIXME: increase fifo priority for 1280x1024 and higher modes? */
- gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
+ gcfg |= (6 << DC_GENERAL_CFG_DFHPEL_SHIFT) |
+ (5 << DC_GENERAL_CFG_DFHPSL_SHIFT) | DC_GENERAL_CFG_DFLE;
/* Framebuffer start offset. */
- writel(0, par->dc_regs + DC_FB_ST_OFFSET);
+ write_dc(par, DC_FB_ST_OFFSET, 0);
/* Line delta and line buffer length. */
- writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH);
- writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
- par->dc_regs + DC_LINE_SIZE);
+ write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3);
+ write_dc(par, DC_LINE_SIZE,
+ ((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2);
/* Enable graphics and video data and unmask address lines. */
- dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M;
+ dcfg |= DC_DISPLAY_CFG_GDEN | DC_DISPLAY_CFG_VDEN |
+ DC_DISPLAY_CFG_A20M | DC_DISPLAY_CFG_A18M;
/* Set pixel format. */
switch (info->var.bits_per_pixel) {
case 8:
- dcfg |= DC_DCFG_DISP_MODE_8BPP;
+ dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP;
break;
case 16:
- dcfg |= DC_DCFG_DISP_MODE_16BPP;
- dcfg |= DC_DCFG_16BPP_MODE_565;
+ dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP;
break;
case 32:
- dcfg |= DC_DCFG_DISP_MODE_24BPP;
- dcfg |= DC_DCFG_PALB;
+ dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP;
+ dcfg |= DC_DISPLAY_CFG_PALB;
break;
}
/* Enable timing generator. */
- dcfg |= DC_DCFG_TGEN;
+ dcfg |= DC_DISPLAY_CFG_TGEN;
/* Horizontal and vertical timings. */
hactive = info->var.xres;
@@ -134,28 +144,34 @@ static void gx_set_mode(struct fb_info *info)
vblankend = vsyncend + info->var.upper_margin;
vtotal = vblankend;
- writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING);
- writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING);
- writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING);
+ write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) |
+ ((htotal - 1) << 16));
+ write_dc(par, DC_H_BLANK_TIMING, (hblankstart - 1) |
+ ((hblankend - 1) << 16));
+ write_dc(par, DC_H_SYNC_TIMING, (hsyncstart - 1) |
+ ((hsyncend - 1) << 16));
- writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING);
- writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING);
- writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING);
+ write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) |
+ ((vtotal - 1) << 16));
+ write_dc(par, DC_V_BLANK_TIMING, (vblankstart - 1) |
+ ((vblankend - 1) << 16));
+ write_dc(par, DC_V_SYNC_TIMING, (vsyncstart - 1) |
+ ((vsyncend - 1) << 16));
/* Write final register values. */
- writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
- writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+ write_dc(par, DC_DISPLAY_CFG, dcfg);
+ write_dc(par, DC_GENERAL_CFG, gcfg);
- par->vid_ops->configure_display(info);
+ gx_configure_display(info);
/* Relock display controller registers */
- writel(0, par->dc_regs + DC_UNLOCK);
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
}
-static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
- unsigned red, unsigned green, unsigned blue)
+void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
+ unsigned red, unsigned green, unsigned blue)
{
- struct geodefb_par *par = info->par;
+ struct gxfb_par *par = info->par;
int val;
/* Hardware palette is in RGB 8-8-8 format. */
@@ -163,11 +179,6 @@ static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
val |= (green) & 0x00ff00;
val |= (blue >> 8) & 0x0000ff;
- writel(regno, par->dc_regs + DC_PAL_ADDRESS);
- writel(val, par->dc_regs + DC_PAL_DATA);
+ write_dc(par, DC_PAL_ADDRESS, regno);
+ write_dc(par, DC_PAL_DATA, val);
}
-
-struct geode_dc_ops gx_dc_ops = {
- .set_mode = gx_set_mode,
- .set_palette_reg = gx_set_hw_palette_reg,
-};
diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h
deleted file mode 100644
index 0af33f329e88..000000000000
--- a/drivers/video/geode/display_gx.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Geode GX display controller
- *
- * Copyright (C) 2006 Arcom Control Systems Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-#ifndef __DISPLAY_GX_H__
-#define __DISPLAY_GX_H__
-
-unsigned int gx_frame_buffer_size(void);
-int gx_line_delta(int xres, int bpp);
-
-extern struct geode_dc_ops gx_dc_ops;
-
-/* MSR that tells us if a TFT or CRT is attached */
-#define GLD_MSR_CONFIG 0xC0002001
-#define GLD_MSR_CONFIG_DM_FP 0x40
-
-/* Display controller registers */
-
-#define DC_UNLOCK 0x00
-# define DC_UNLOCK_CODE 0x00004758
-
-#define DC_GENERAL_CFG 0x04
-# define DC_GCFG_DFLE 0x00000001
-# define DC_GCFG_CURE 0x00000002
-# define DC_GCFG_ICNE 0x00000004
-# define DC_GCFG_VIDE 0x00000008
-# define DC_GCFG_CMPE 0x00000020
-# define DC_GCFG_DECE 0x00000040
-# define DC_GCFG_VGAE 0x00000080
-# define DC_GCFG_DFHPSL_MASK 0x00000F00
-# define DC_GCFG_DFHPSL_POS 8
-# define DC_GCFG_DFHPEL_MASK 0x0000F000
-# define DC_GCFG_DFHPEL_POS 12
-# define DC_GCFG_STFM 0x00010000
-# define DC_GCFG_FDTY 0x00020000
-# define DC_GCFG_VGAFT 0x00040000
-# define DC_GCFG_VDSE 0x00080000
-# define DC_GCFG_YUVM 0x00100000
-# define DC_GCFG_VFSL 0x00800000
-# define DC_GCFG_SIGE 0x01000000
-# define DC_GCFG_SGRE 0x02000000
-# define DC_GCFG_SGFR 0x04000000
-# define DC_GCFG_CRC_MODE 0x08000000
-# define DC_GCFG_DIAG 0x10000000
-# define DC_GCFG_CFRW 0x20000000
-
-#define DC_DISPLAY_CFG 0x08
-# define DC_DCFG_TGEN 0x00000001
-# define DC_DCFG_GDEN 0x00000008
-# define DC_DCFG_VDEN 0x00000010
-# define DC_DCFG_TRUP 0x00000040
-# define DC_DCFG_DISP_MODE_MASK 0x00000300
-# define DC_DCFG_DISP_MODE_8BPP 0x00000000
-# define DC_DCFG_DISP_MODE_16BPP 0x00000100
-# define DC_DCFG_DISP_MODE_24BPP 0x00000200
-# define DC_DCFG_16BPP_MODE_MASK 0x00000c00
-# define DC_DCFG_16BPP_MODE_565 0x00000000
-# define DC_DCFG_16BPP_MODE_555 0x00000100
-# define DC_DCFG_16BPP_MODE_444 0x00000200
-# define DC_DCFG_DCEN 0x00080000
-# define DC_DCFG_PALB 0x02000000
-# define DC_DCFG_FRLK 0x04000000
-# define DC_DCFG_VISL 0x08000000
-# define DC_DCFG_FRSL 0x20000000
-# define DC_DCFG_A18M 0x40000000
-# define DC_DCFG_A20M 0x80000000
-
-#define DC_FB_ST_OFFSET 0x10
-
-#define DC_LINE_SIZE 0x30
-# define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff
-# define DC_LINE_SIZE_FB_LINE_SIZE_POS 0
-# define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000
-# define DC_LINE_SIZE_CB_LINE_SIZE_POS 16
-# define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000
-# define DC_LINE_SIZE_VID_LINE_SIZE_POS 24
-
-#define DC_GFX_PITCH 0x34
-# define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff
-# define DC_GFX_PITCH_FB_PITCH_POS 0
-# define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000
-# define DC_GFX_PITCH_CB_PITCH_POS 16
-
-#define DC_H_ACTIVE_TIMING 0x40
-#define DC_H_BLANK_TIMING 0x44
-#define DC_H_SYNC_TIMING 0x48
-#define DC_V_ACTIVE_TIMING 0x50
-#define DC_V_BLANK_TIMING 0x54
-#define DC_V_SYNC_TIMING 0x58
-
-#define DC_PAL_ADDRESS 0x70
-#define DC_PAL_DATA 0x74
-
-#define DC_GLIU0_MEM_OFFSET 0x84
-#endif /* !__DISPLAY_GX1_H__ */
diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h
new file mode 100644
index 000000000000..16a96f8fd8c5
--- /dev/null
+++ b/drivers/video/geode/gxfb.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 Andres Salomon <dilinger@debian.org>
+ *
+ * Geode GX2 header information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _GXFB_H_
+#define _GXFB_H_
+
+#include <linux/io.h>
+
+#define GP_REG_COUNT (0x50 / 4)
+#define DC_REG_COUNT (0x90 / 4)
+#define VP_REG_COUNT (0x138 / 8)
+#define FP_REG_COUNT (0x68 / 8)
+
+#define DC_PAL_COUNT 0x104
+
+struct gxfb_par {
+ int enable_crt;
+ void __iomem *dc_regs;
+ void __iomem *vid_regs;
+ void __iomem *gp_regs;
+#ifdef CONFIG_PM
+ int powered_down;
+
+ /* register state, for power management functionality */
+ struct {
+ uint64_t padsel;
+ uint64_t dotpll;
+ } msr;
+
+ uint32_t gp[GP_REG_COUNT];
+ uint32_t dc[DC_REG_COUNT];
+ uint64_t vp[VP_REG_COUNT];
+ uint64_t fp[FP_REG_COUNT];
+
+ uint32_t pal[DC_PAL_COUNT];
+#endif
+};
+
+unsigned int gx_frame_buffer_size(void);
+int gx_line_delta(int xres, int bpp);
+void gx_set_mode(struct fb_info *info);
+void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno,
+ unsigned red, unsigned green, unsigned blue);
+
+void gx_set_dclk_frequency(struct fb_info *info);
+void gx_configure_display(struct fb_info *info);
+int gx_blank_display(struct fb_info *info, int blank_mode);
+
+#ifdef CONFIG_PM
+int gx_powerdown(struct fb_info *info);
+int gx_powerup(struct fb_info *info);
+#endif
+
+
+/* Graphics Processor registers (table 6-23 from the data book) */
+enum gp_registers {
+ GP_DST_OFFSET = 0,
+ GP_SRC_OFFSET,
+ GP_STRIDE,
+ GP_WID_HEIGHT,
+
+ GP_SRC_COLOR_FG,
+ GP_SRC_COLOR_BG,
+ GP_PAT_COLOR_0,
+ GP_PAT_COLOR_1,
+
+ GP_PAT_COLOR_2,
+ GP_PAT_COLOR_3,
+ GP_PAT_COLOR_4,
+ GP_PAT_COLOR_5,
+
+ GP_PAT_DATA_0,
+ GP_PAT_DATA_1,
+ GP_RASTER_MODE,
+ GP_VECTOR_MODE,
+
+ GP_BLT_MODE,
+ GP_BLT_STATUS,
+ GP_HST_SRC,
+ GP_BASE_OFFSET, /* 0x4c */
+};
+
+#define GP_BLT_STATUS_BLT_PENDING (1 << 2)
+#define GP_BLT_STATUS_BLT_BUSY (1 << 0)
+
+
+/* Display Controller registers (table 6-38 from the data book) */
+enum dc_registers {
+ DC_UNLOCK = 0,
+ DC_GENERAL_CFG,
+ DC_DISPLAY_CFG,
+ DC_RSVD_0,
+
+ DC_FB_ST_OFFSET,
+ DC_CB_ST_OFFSET,
+ DC_CURS_ST_OFFSET,
+ DC_ICON_ST_OFFSET,
+
+ DC_VID_Y_ST_OFFSET,
+ DC_VID_U_ST_OFFSET,
+ DC_VID_V_ST_OFFSET,
+ DC_RSVD_1,
+
+ DC_LINE_SIZE,
+ DC_GFX_PITCH,
+ DC_VID_YUV_PITCH,
+ DC_RSVD_2,
+
+ DC_H_ACTIVE_TIMING,
+ DC_H_BLANK_TIMING,
+ DC_H_SYNC_TIMING,
+ DC_RSVD_3,
+
+ DC_V_ACTIVE_TIMING,
+ DC_V_BLANK_TIMING,
+ DC_V_SYNC_TIMING,
+ DC_RSVD_4,
+
+ DC_CURSOR_X,
+ DC_CURSOR_Y,
+ DC_ICON_X,
+ DC_LINE_CNT,
+
+ DC_PAL_ADDRESS,
+ DC_PAL_DATA,
+ DC_DFIFO_DIAG,
+ DC_CFIFO_DIAG,
+
+ DC_VID_DS_DELTA,
+ DC_GLIU0_MEM_OFFSET,
+ DC_RSVD_5,
+ DC_DV_ACC, /* 0x8c */
+};
+
+#define DC_UNLOCK_LOCK 0x00000000
+#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */
+
+#define DC_GENERAL_CFG_YUVM (1 << 20)
+#define DC_GENERAL_CFG_VDSE (1 << 19)
+#define DC_GENERAL_CFG_DFHPEL_SHIFT 12
+#define DC_GENERAL_CFG_DFHPSL_SHIFT 8
+#define DC_GENERAL_CFG_DECE (1 << 6)
+#define DC_GENERAL_CFG_CMPE (1 << 5)
+#define DC_GENERAL_CFG_VIDE (1 << 3)
+#define DC_GENERAL_CFG_ICNE (1 << 2)
+#define DC_GENERAL_CFG_CURE (1 << 1)
+#define DC_GENERAL_CFG_DFLE (1 << 0)
+
+#define DC_DISPLAY_CFG_A20M (1 << 31)
+#define DC_DISPLAY_CFG_A18M (1 << 30)
+#define DC_DISPLAY_CFG_PALB (1 << 25)
+#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9)
+#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8)
+#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0)
+#define DC_DISPLAY_CFG_VDEN (1 << 4)
+#define DC_DISPLAY_CFG_GDEN (1 << 3)
+#define DC_DISPLAY_CFG_TGEN (1 << 0)
+
+
+/*
+ * Video Processor registers (table 6-54).
+ * There is space for 64 bit values, but we never use more than the
+ * lower 32 bits. The actual register save/restore code only bothers
+ * to restore those 32 bits.
+ */
+enum vp_registers {
+ VP_VCFG = 0,
+ VP_DCFG,
+
+ VP_VX,
+ VP_VY,
+
+ VP_VS,
+ VP_VCK,
+
+ VP_VCM,
+ VP_GAR,
+
+ VP_GDR,
+ VP_RSVD_0,
+
+ VP_MISC,
+ VP_CCS,
+
+ VP_RSVD_1,
+ VP_RSVD_2,
+
+ VP_RSVD_3,
+ VP_VDC,
+
+ VP_VCO,
+ VP_CRC,
+
+ VP_CRC32,
+ VP_VDE,
+
+ VP_CCK,
+ VP_CCM,
+
+ VP_CC1,
+ VP_CC2,
+
+ VP_A1X,
+ VP_A1Y,
+
+ VP_A1C,
+ VP_A1T,
+
+ VP_A2X,
+ VP_A2Y,
+
+ VP_A2C,
+ VP_A2T,
+
+ VP_A3X,
+ VP_A3Y,
+
+ VP_A3C,
+ VP_A3T,
+
+ VP_VRR,
+ VP_AWT,
+
+ VP_VTM, /* 0x130 */
+};
+
+#define VP_VCFG_VID_EN (1 << 0)
+
+#define VP_DCFG_DAC_VREF (1 << 26)
+#define VP_DCFG_GV_GAM (1 << 21)
+#define VP_DCFG_VG_CK (1 << 20)
+#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16)
+#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16))
+#define VP_DCFG_CRT_VSYNC_POL (1 << 9)
+#define VP_DCFG_CRT_HSYNC_POL (1 << 8)
+#define VP_DCFG_FP_DATA_EN (1 << 7) /* undocumented */
+#define VP_DCFG_FP_PWR_EN (1 << 6) /* undocumented */
+#define VP_DCFG_DAC_BL_EN (1 << 3)
+#define VP_DCFG_VSYNC_EN (1 << 2)
+#define VP_DCFG_HSYNC_EN (1 << 1)
+#define VP_DCFG_CRT_EN (1 << 0)
+
+#define VP_MISC_GAM_EN (1 << 0)
+#define VP_MISC_DACPWRDN (1 << 10)
+#define VP_MISC_APWRDN (1 << 11)
+
+
+/*
+ * Flat Panel registers (table 6-55).
+ * Also 64 bit registers; see above note about 32-bit handling.
+ */
+
+/* we're actually in the VP register space, starting at address 0x400 */
+#define VP_FP_START 0x400
+
+enum fp_registers {
+ FP_PT1 = 0,
+ FP_PT2,
+
+ FP_PM,
+ FP_DFC,
+
+ FP_BLFSR,
+ FP_RLFSR,
+
+ FP_FMI,
+ FP_FMD,
+
+ FP_RSVD_0,
+ FP_DCA,
+
+ FP_DMD,
+ FP_CRC,
+
+ FP_FBB, /* 0x460 */
+};
+
+#define FP_PT1_VSIZE_SHIFT 16 /* undocumented? */
+#define FP_PT1_VSIZE_MASK 0x7FF0000 /* undocumented? */
+
+#define FP_PT2_HSP (1 << 22)
+#define FP_PT2_VSP (1 << 23)
+
+#define FP_PM_P (1 << 24) /* panel power on */
+#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */
+#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */
+#define FP_PM_PANEL_OFF (1 << 1) /* r/o */
+#define FP_PM_PANEL_ON (1 << 0) /* r/o */
+
+#define FP_DFC_NFI ((1 << 4) | (1 << 5) | (1 << 6))
+
+
+/* register access functions */
+
+static inline uint32_t read_gp(struct gxfb_par *par, int reg)
+{
+ return readl(par->gp_regs + 4*reg);
+}
+
+static inline void write_gp(struct gxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->gp_regs + 4*reg);
+}
+
+static inline uint32_t read_dc(struct gxfb_par *par, int reg)
+{
+ return readl(par->dc_regs + 4*reg);
+}
+
+static inline void write_dc(struct gxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->dc_regs + 4*reg);
+}
+
+static inline uint32_t read_vp(struct gxfb_par *par, int reg)
+{
+ return readl(par->vid_regs + 8*reg);
+}
+
+static inline void write_vp(struct gxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->vid_regs + 8*reg);
+}
+
+static inline uint32_t read_fp(struct gxfb_par *par, int reg)
+{
+ return readl(par->vid_regs + 8*reg + VP_FP_START);
+}
+
+static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->vid_regs + 8*reg + VP_FP_START);
+}
+
+
+/* MSRs are defined in asm/geode.h; their bitfields are here */
+
+#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3)
+#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2)
+#define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (1 << 1)
+
+#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */
+#define MSR_GLCP_DOTPLL_BYPASS (1 << 15)
+#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0)
+
+#define MSR_GX_MSR_PADSEL_MASK 0x3FFFFFFF /* undocumented? */
+#define MSR_GX_MSR_PADSEL_TFT 0x1FFFFFFF /* undocumented? */
+
+#define MSR_GX_GLD_MSR_CONFIG_FP (1 << 3)
+
+#endif
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index cf841efa229a..de2b8f9876a5 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -28,17 +28,20 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/suspend.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <asm/geode.h>
-#include "geodefb.h"
-#include "display_gx.h"
-#include "video_gx.h"
+#include "gxfb.h"
static char *mode_option;
+static int vram;
+static int vt_switch;
/* Modes relevant to the GX (taken from modedb.c) */
-static const struct fb_videomode gx_modedb[] __initdata = {
+static struct fb_videomode gx_modedb[] __initdata = {
/* 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -105,6 +108,35 @@ static const struct fb_videomode gx_modedb[] __initdata = {
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+
+static struct fb_videomode gx_dcon_modedb[] __initdata = {
+ /* The only mode the DCON has is 1200x900 */
+ { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 }
+};
+
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+ if (olpc_has_dcon()) {
+ *modedb = (struct fb_videomode *) gx_dcon_modedb;
+ *size = ARRAY_SIZE(gx_dcon_modedb);
+ } else {
+ *modedb = (struct fb_videomode *) gx_modedb;
+ *size = ARRAY_SIZE(gx_modedb);
+ }
+}
+
+#else
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+ *modedb = (struct fb_videomode *) gx_modedb;
+ *size = ARRAY_SIZE(gx_modedb);
+}
+#endif
+
static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
if (var->xres > 1600 || var->yres > 1200)
@@ -139,8 +171,6 @@ static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int gxfb_set_par(struct fb_info *info)
{
- struct geodefb_par *par = info->par;
-
if (info->var.bits_per_pixel > 8) {
info->fix.visual = FB_VISUAL_TRUECOLOR;
fb_dealloc_cmap(&info->cmap);
@@ -151,7 +181,7 @@ static int gxfb_set_par(struct fb_info *info)
info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel);
- par->dc_ops->set_mode(info);
+ gx_set_mode(info);
return 0;
}
@@ -167,8 +197,6 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
- struct geodefb_par *par = info->par;
-
if (info->var.grayscale) {
/* grayscale = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
@@ -191,7 +219,7 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (regno >= 256)
return -EINVAL;
- par->dc_ops->set_palette_reg(info, regno, red, green, blue);
+ gx_set_hw_palette_reg(info, regno, red, green, blue);
}
return 0;
@@ -199,15 +227,12 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
static int gxfb_blank(int blank_mode, struct fb_info *info)
{
- struct geodefb_par *par = info->par;
-
- return par->vid_ops->blank_display(info, blank_mode);
+ return gx_blank_display(info, blank_mode);
}
static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
{
- struct geodefb_par *par = info->par;
- int fb_len;
+ struct gxfb_par *par = info->par;
int ret;
ret = pci_enable_device(dev);
@@ -229,24 +254,31 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de
if (!par->dc_regs)
return -ENOMEM;
- ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
+ ret = pci_request_region(dev, 1, "gxfb (graphics processor)");
if (ret < 0)
return ret;
- if ((fb_len = gx_frame_buffer_size()) < 0)
+ par->gp_regs = ioremap(pci_resource_start(dev, 1),
+ pci_resource_len(dev, 1));
+
+ if (!par->gp_regs)
return -ENOMEM;
+
+ ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
+ if (ret < 0)
+ return ret;
+
info->fix.smem_start = pci_resource_start(dev, 0);
- info->fix.smem_len = fb_len;
+ info->fix.smem_len = vram ? vram : gx_frame_buffer_size();
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
if (!info->screen_base)
return -ENOMEM;
- /* Set the 16MB aligned base address of the graphics memory region
+ /* Set the 16MiB aligned base address of the graphics memory region
* in the display controller */
- writel(info->fix.smem_start & 0xFF000000,
- par->dc_regs + DC_GLIU0_MEM_OFFSET);
+ write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000);
- dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
+ dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n",
info->fix.smem_len / 1024, info->fix.smem_start);
return 0;
@@ -266,11 +298,12 @@ static struct fb_ops gxfb_ops = {
static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
{
- struct geodefb_par *par;
+ struct gxfb_par *par;
struct fb_info *info;
/* Alloc enough space for the pseudo palette. */
- info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev);
+ info = framebuffer_alloc(sizeof(struct gxfb_par) + sizeof(u32) * 16,
+ dev);
if (!info)
return NULL;
@@ -296,29 +329,64 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
info->flags = FBINFO_DEFAULT;
info->node = -1;
- info->pseudo_palette = (void *)par + sizeof(struct geodefb_par);
+ info->pseudo_palette = (void *)par + sizeof(struct gxfb_par);
info->var.grayscale = 0;
return info;
}
+#ifdef CONFIG_PM
+static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+
+ if (state.event == PM_EVENT_SUSPEND) {
+ acquire_console_sem();
+ gx_powerdown(info);
+ fb_set_suspend(info, 1);
+ release_console_sem();
+ }
+
+ /* there's no point in setting PCI states; we emulate PCI, so
+ * we don't end up getting power savings anyways */
+
+ return 0;
+}
+
+static int gxfb_resume(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ int ret;
+
+ acquire_console_sem();
+ ret = gx_powerup(info);
+ if (ret) {
+ printk(KERN_ERR "gxfb: power up failed!\n");
+ return ret;
+ }
+
+ fb_set_suspend(info, 0);
+ release_console_sem();
+ return 0;
+}
+#endif
+
static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct geodefb_par *par;
+ struct gxfb_par *par;
struct fb_info *info;
int ret;
unsigned long val;
+ struct fb_videomode *modedb_ptr;
+ unsigned int modedb_size;
+
info = gxfb_init_fbinfo(&pdev->dev);
if (!info)
return -ENOMEM;
par = info->par;
- /* GX display controller and GX video device. */
- par->dc_ops = &gx_dc_ops;
- par->vid_ops = &gx_vid_ops;
-
if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
goto err;
@@ -326,15 +394,16 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
/* Figure out if this is a TFT or CRT part */
- rdmsrl(GLD_MSR_CONFIG, val);
+ rdmsrl(MSR_GX_GLD_MSR_CONFIG, val);
- if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP)
+ if ((val & MSR_GX_GLD_MSR_CONFIG_FP) == MSR_GX_GLD_MSR_CONFIG_FP)
par->enable_crt = 0;
else
par->enable_crt = 1;
+ get_modedb(&modedb_ptr, &modedb_size);
ret = fb_find_mode(&info->var, info, mode_option,
- gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
+ modedb_ptr, modedb_size, NULL, 16);
if (ret == 0 || ret == 4) {
dev_err(&pdev->dev, "could not find valid video mode\n");
ret = -EINVAL;
@@ -348,6 +417,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
gxfb_check_var(&info->var, info);
gxfb_set_par(info);
+ pm_set_vt_switch(vt_switch);
+
if (register_framebuffer(info) < 0) {
ret = -EINVAL;
goto err;
@@ -369,6 +440,10 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
iounmap(par->dc_regs);
pci_release_region(pdev, 2);
}
+ if (par->gp_regs) {
+ iounmap(par->gp_regs);
+ pci_release_region(pdev, 1);
+ }
if (info)
framebuffer_release(info);
@@ -378,7 +453,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
static void gxfb_remove(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
- struct geodefb_par *par = info->par;
+ struct gxfb_par *par = info->par;
unregister_framebuffer(info);
@@ -391,15 +466,16 @@ static void gxfb_remove(struct pci_dev *pdev)
iounmap(par->dc_regs);
pci_release_region(pdev, 2);
+ iounmap(par->gp_regs);
+ pci_release_region(pdev, 1);
+
pci_set_drvdata(pdev, NULL);
framebuffer_release(info);
}
static struct pci_device_id gxfb_id_table[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO,
- PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
- 0xff0000, 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) },
{ 0, }
};
@@ -410,6 +486,10 @@ static struct pci_driver gxfb_driver = {
.id_table = gxfb_id_table,
.probe = gxfb_probe,
.remove = gxfb_remove,
+#ifdef CONFIG_PM
+ .suspend = gxfb_suspend,
+ .resume = gxfb_resume,
+#endif
};
#ifndef MODULE
@@ -456,5 +536,11 @@ module_exit(gxfb_cleanup);
module_param(mode_option, charp, 0);
MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram, "video memory size");
+
+module_param(vt_switch, int, 0);
+MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
+
MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
index ca13c48d19b0..3b9416f4ee20 100644
--- a/drivers/video/geode/lxfb.h
+++ b/drivers/video/geode/lxfb.h
@@ -3,17 +3,46 @@
#include <linux/fb.h>
+#define GP_REG_COUNT (0x7c / 4)
+#define DC_REG_COUNT (0xf0 / 4)
+#define VP_REG_COUNT (0x158 / 8)
+#define FP_REG_COUNT (0x60 / 8)
+
+#define DC_PAL_COUNT 0x104
+#define DC_HFILT_COUNT 0x100
+#define DC_VFILT_COUNT 0x100
+#define VP_COEFF_SIZE 0x1000
+
#define OUTPUT_CRT 0x01
#define OUTPUT_PANEL 0x02
struct lxfb_par {
int output;
- int panel_width;
- int panel_height;
void __iomem *gp_regs;
void __iomem *dc_regs;
- void __iomem *df_regs;
+ void __iomem *vp_regs;
+#ifdef CONFIG_PM
+ int powered_down;
+
+ /* register state, for power mgmt functionality */
+ struct {
+ uint64_t padsel;
+ uint64_t dotpll;
+ uint64_t dfglcfg;
+ uint64_t dcspare;
+ } msr;
+
+ uint32_t gp[GP_REG_COUNT];
+ uint32_t dc[DC_REG_COUNT];
+ uint64_t vp[VP_REG_COUNT];
+ uint64_t fp[FP_REG_COUNT];
+
+ uint32_t pal[DC_PAL_COUNT];
+ uint32_t hcoeff[DC_HFILT_COUNT * 2];
+ uint32_t vcoeff[DC_VFILT_COUNT];
+ uint32_t vp_coeff[VP_COEFF_SIZE / 4];
+#endif
};
static inline unsigned int lx_get_pitch(unsigned int xres, int bpp)
@@ -29,171 +58,383 @@ int lx_blank_display(struct fb_info *, int);
void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
unsigned int, unsigned int);
-/* MSRS */
+#ifdef CONFIG_PM
+int lx_powerdown(struct fb_info *info);
+int lx_powerup(struct fb_info *info);
+#endif
+
+
+/* Graphics Processor registers (table 6-29 from the data book) */
+enum gp_registers {
+ GP_DST_OFFSET = 0,
+ GP_SRC_OFFSET,
+ GP_STRIDE,
+ GP_WID_HEIGHT,
+
+ GP_SRC_COLOR_FG,
+ GP_SRC_COLOR_BG,
+ GP_PAT_COLOR_0,
+ GP_PAT_COLOR_1,
+
+ GP_PAT_COLOR_2,
+ GP_PAT_COLOR_3,
+ GP_PAT_COLOR_4,
+ GP_PAT_COLOR_5,
+
+ GP_PAT_DATA_0,
+ GP_PAT_DATA_1,
+ GP_RASTER_MODE,
+ GP_VECTOR_MODE,
+
+ GP_BLT_MODE,
+ GP_BLT_STATUS,
+ GP_HST_SRC,
+ GP_BASE_OFFSET,
+
+ GP_CMD_TOP,
+ GP_CMD_BOT,
+ GP_CMD_READ,
+ GP_CMD_WRITE,
+
+ GP_CH3_OFFSET,
+ GP_CH3_MODE_STR,
+ GP_CH3_WIDHI,
+ GP_CH3_HSRC,
+
+ GP_LUT_INDEX,
+ GP_LUT_DATA,
+ GP_INT_CNTRL, /* 0x78 */
+};
+
+#define GP_BLT_STATUS_CE (1 << 4) /* cmd buf empty */
+#define GP_BLT_STATUS_PB (1 << 0) /* primative busy */
+
+
+/* Display Controller registers (table 6-47 from the data book) */
+enum dc_registers {
+ DC_UNLOCK = 0,
+ DC_GENERAL_CFG,
+ DC_DISPLAY_CFG,
+ DC_ARB_CFG,
+
+ DC_FB_ST_OFFSET,
+ DC_CB_ST_OFFSET,
+ DC_CURS_ST_OFFSET,
+ DC_RSVD_0,
+
+ DC_VID_Y_ST_OFFSET,
+ DC_VID_U_ST_OFFSET,
+ DC_VID_V_ST_OFFSET,
+ DC_DV_TOP,
+
+ DC_LINE_SIZE,
+ DC_GFX_PITCH,
+ DC_VID_YUV_PITCH,
+ DC_RSVD_1,
+
+ DC_H_ACTIVE_TIMING,
+ DC_H_BLANK_TIMING,
+ DC_H_SYNC_TIMING,
+ DC_RSVD_2,
+
+ DC_V_ACTIVE_TIMING,
+ DC_V_BLANK_TIMING,
+ DC_V_SYNC_TIMING,
+ DC_FB_ACTIVE,
+
+ DC_CURSOR_X,
+ DC_CURSOR_Y,
+ DC_RSVD_3,
+ DC_LINE_CNT,
+
+ DC_PAL_ADDRESS,
+ DC_PAL_DATA,
+ DC_DFIFO_DIAG,
+ DC_CFIFO_DIAG,
+
+ DC_VID_DS_DELTA,
+ DC_GLIU0_MEM_OFFSET,
+ DC_DV_CTL,
+ DC_DV_ACCESS,
+
+ DC_GFX_SCALE,
+ DC_IRQ_FILT_CTL,
+ DC_FILT_COEFF1,
+ DC_FILT_COEFF2,
+
+ DC_VBI_EVEN_CTL,
+ DC_VBI_ODD_CTL,
+ DC_VBI_HOR,
+ DC_VBI_LN_ODD,
+
+ DC_VBI_LN_EVEN,
+ DC_VBI_PITCH,
+ DC_CLR_KEY,
+ DC_CLR_KEY_MASK,
+
+ DC_CLR_KEY_X,
+ DC_CLR_KEY_Y,
+ DC_IRQ,
+ DC_RSVD_4,
+
+ DC_RSVD_5,
+ DC_GENLK_CTL,
+ DC_VID_EVEN_Y_ST_OFFSET,
+ DC_VID_EVEN_U_ST_OFFSET,
+
+ DC_VID_EVEN_V_ST_OFFSET,
+ DC_V_ACTIVE_EVEN_TIMING,
+ DC_V_BLANK_EVEN_TIMING,
+ DC_V_SYNC_EVEN_TIMING, /* 0xec */
+};
+
+#define DC_UNLOCK_LOCK 0x00000000
+#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */
+
+#define DC_GENERAL_CFG_FDTY (1 << 17)
+#define DC_GENERAL_CFG_DFHPEL_SHIFT (12)
+#define DC_GENERAL_CFG_DFHPSL_SHIFT (8)
+#define DC_GENERAL_CFG_VGAE (1 << 7)
+#define DC_GENERAL_CFG_DECE (1 << 6)
+#define DC_GENERAL_CFG_CMPE (1 << 5)
+#define DC_GENERAL_CFG_VIDE (1 << 3)
+#define DC_GENERAL_CFG_DFLE (1 << 0)
+
+#define DC_DISPLAY_CFG_VISL (1 << 27)
+#define DC_DISPLAY_CFG_PALB (1 << 25)
+#define DC_DISPLAY_CFG_DCEN (1 << 24)
+#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9)
+#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8)
+#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0)
+#define DC_DISPLAY_CFG_TRUP (1 << 6)
+#define DC_DISPLAY_CFG_VDEN (1 << 4)
+#define DC_DISPLAY_CFG_GDEN (1 << 3)
+#define DC_DISPLAY_CFG_TGEN (1 << 0)
+
+#define DC_DV_TOP_DV_TOP_EN (1 << 0)
+
+#define DC_DV_CTL_DV_LINE_SIZE ((1 << 10) | (1 << 11))
+#define DC_DV_CTL_DV_LINE_SIZE_1K (0)
+#define DC_DV_CTL_DV_LINE_SIZE_2K (1 << 10)
+#define DC_DV_CTL_DV_LINE_SIZE_4K (1 << 11)
+#define DC_DV_CTL_DV_LINE_SIZE_8K ((1 << 10) | (1 << 11))
+#define DC_DV_CTL_CLEAR_DV_RAM (1 << 0)
+
+#define DC_IRQ_FILT_CTL_H_FILT_SEL (1 << 10)
+
+#define DC_CLR_KEY_CLR_KEY_EN (1 << 24)
+
+#define DC_IRQ_VIP_VSYNC_IRQ_STATUS (1 << 21) /* undocumented? */
+#define DC_IRQ_STATUS (1 << 20) /* undocumented? */
+#define DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK (1 << 1)
+#define DC_IRQ_MASK (1 << 0)
-#define MSR_LX_GLD_CONFIG 0x48002001
-#define MSR_LX_GLCP_DOTPLL 0x4c000015
-#define MSR_LX_DF_PADSEL 0x48002011
-#define MSR_LX_DC_SPARE 0x80000011
-#define MSR_LX_DF_GLCONFIG 0x48002001
-
-#define MSR_LX_GLIU0_P2D_RO0 0x10000029
-
-#define GLCP_DOTPLL_RESET (1 << 0)
-#define GLCP_DOTPLL_BYPASS (1 << 15)
-#define GLCP_DOTPLL_HALFPIX (1 << 24)
-#define GLCP_DOTPLL_LOCK (1 << 25)
-
-#define DF_CONFIG_OUTPUT_MASK 0x38
-#define DF_OUTPUT_PANEL 0x08
-#define DF_OUTPUT_CRT 0x00
-#define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15)
-
-#define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF
-#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F
-
-#define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800
-#define DC_SPARE_VFIFO_ARB_SELECT 0x00000400
-#define DC_SPARE_WM_LPEN_OVRD 0x00000200
-#define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100
-#define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080
-#define DC_SPARE_DISABLE_VFIFO_WM 0x00000040
-#define DC_SPARE_DISABLE_CWD_CHECK 0x00000020
-#define DC_SPARE_PIX8_PAN_FIX 0x00000010
-#define DC_SPARE_FIRST_REQ_MASK 0x00000002
-
-/* Registers */
-
-#define DC_UNLOCK 0x00
-#define DC_UNLOCK_CODE 0x4758
+#define DC_GENLK_CTL_FLICK_SEL_MASK (0x0F << 28)
+#define DC_GENLK_CTL_ALPHA_FLICK_EN (1 << 25)
+#define DC_GENLK_CTL_FLICK_EN (1 << 24)
+#define DC_GENLK_CTL_GENLK_EN (1 << 18)
-#define DC_GENERAL_CFG 0x04
-#define DC_GCFG_DFLE (1 << 0)
-#define DC_GCFG_VIDE (1 << 3)
-#define DC_GCFG_VGAE (1 << 7)
-#define DC_GCFG_CMPE (1 << 5)
-#define DC_GCFG_DECE (1 << 6)
-#define DC_GCFG_FDTY (1 << 17)
-#define DC_DISPLAY_CFG 0x08
-#define DC_DCFG_TGEN (1 << 0)
-#define DC_DCFG_GDEN (1 << 3)
-#define DC_DCFG_VDEN (1 << 4)
-#define DC_DCFG_TRUP (1 << 6)
-#define DC_DCFG_DCEN (1 << 24)
-#define DC_DCFG_PALB (1 << 25)
-#define DC_DCFG_VISL (1 << 27)
+/*
+ * Video Processor registers (table 6-71).
+ * There is space for 64 bit values, but we never use more than the
+ * lower 32 bits. The actual register save/restore code only bothers
+ * to restore those 32 bits.
+ */
+enum vp_registers {
+ VP_VCFG = 0,
+ VP_DCFG,
-#define DC_DCFG_16BPP 0x0
+ VP_VX,
+ VP_VY,
-#define DC_DCFG_DISP_MODE_MASK 0x00000300
-#define DC_DCFG_DISP_MODE_8BPP 0x00000000
-#define DC_DCFG_DISP_MODE_16BPP 0x00000100
-#define DC_DCFG_DISP_MODE_24BPP 0x00000200
-#define DC_DCFG_DISP_MODE_32BPP 0x00000300
+ VP_SCL,
+ VP_VCK,
+ VP_VCM,
+ VP_PAR,
-#define DC_ARB_CFG 0x0C
+ VP_PDR,
+ VP_SLR,
-#define DC_FB_START 0x10
-#define DC_CB_START 0x14
-#define DC_CURSOR_START 0x18
+ VP_MISC,
+ VP_CCS,
-#define DC_DV_TOP 0x2C
-#define DC_DV_TOP_ENABLE (1 << 0)
+ VP_VYS,
+ VP_VXS,
-#define DC_LINE_SIZE 0x30
-#define DC_GRAPHICS_PITCH 0x34
-#define DC_H_ACTIVE_TIMING 0x40
-#define DC_H_BLANK_TIMING 0x44
-#define DC_H_SYNC_TIMING 0x48
-#define DC_V_ACTIVE_TIMING 0x50
-#define DC_V_BLANK_TIMING 0x54
-#define DC_V_SYNC_TIMING 0x58
-#define DC_FB_ACTIVE 0x5C
+ VP_RSVD_0,
+ VP_VDC,
+
+ VP_RSVD_1,
+ VP_CRC,
+
+ VP_CRC32,
+ VP_VDE,
+
+ VP_CCK,
+ VP_CCM,
+
+ VP_CC1,
+ VP_CC2,
+
+ VP_A1X,
+ VP_A1Y,
+
+ VP_A1C,
+ VP_A1T,
+
+ VP_A2X,
+ VP_A2Y,
+
+ VP_A2C,
+ VP_A2T,
+
+ VP_A3X,
+ VP_A3Y,
+
+ VP_A3C,
+ VP_A3T,
+
+ VP_VRR,
+ VP_AWT,
+
+ VP_VTM,
+ VP_VYE,
+
+ VP_A1YE,
+ VP_A2YE,
+
+ VP_A3YE, /* 0x150 */
+
+ VP_VCR = 0x1000, /* 0x1000 - 0x1fff */
+};
-#define DC_PAL_ADDRESS 0x70
-#define DC_PAL_DATA 0x74
+#define VP_VCFG_VID_EN (1 << 0)
-#define DC_PHY_MEM_OFFSET 0x84
+#define VP_DCFG_GV_GAM (1 << 21)
+#define VP_DCFG_PWR_SEQ_DELAY ((1 << 17) | (1 << 18) | (1 << 19))
+#define VP_DCFG_PWR_SEQ_DELAY_DEFAULT (1 << 19) /* undocumented */
+#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16))
+#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16)
+#define VP_DCFG_CRT_VSYNC_POL (1 << 9)
+#define VP_DCFG_CRT_HSYNC_POL (1 << 8)
+#define VP_DCFG_DAC_BL_EN (1 << 3)
+#define VP_DCFG_VSYNC_EN (1 << 2)
+#define VP_DCFG_HSYNC_EN (1 << 1)
+#define VP_DCFG_CRT_EN (1 << 0)
-#define DC_DV_CTL 0x88
-#define DC_DV_LINE_SIZE_MASK 0x00000C00
-#define DC_DV_LINE_SIZE_1024 0x00000000
-#define DC_DV_LINE_SIZE_2048 0x00000400
-#define DC_DV_LINE_SIZE_4096 0x00000800
-#define DC_DV_LINE_SIZE_8192 0x00000C00
+#define VP_MISC_APWRDN (1 << 11)
+#define VP_MISC_DACPWRDN (1 << 10)
+#define VP_MISC_BYP_BOTH (1 << 0)
-#define DC_GFX_SCALE 0x90
-#define DC_IRQ_FILT_CTL 0x94
+/*
+ * Flat Panel registers (table 6-71).
+ * Also 64 bit registers; see above note about 32-bit handling.
+ */
+/* we're actually in the VP register space, starting at address 0x400 */
+#define VP_FP_START 0x400
-#define DC_IRQ 0xC8
-#define DC_IRQ_MASK (1 << 0)
-#define DC_VSYNC_IRQ_MASK (1 << 1)
-#define DC_IRQ_STATUS (1 << 20)
-#define DC_VSYNC_IRQ_STATUS (1 << 21)
-
-#define DC_GENLCK_CTRL 0xD4
-#define DC_GENLCK_ENABLE (1 << 18)
-#define DC_GC_ALPHA_FLICK_ENABLE (1 << 25)
-#define DC_GC_FLICKER_FILTER_ENABLE (1 << 24)
-#define DC_GC_FLICKER_FILTER_MASK (0x0F << 28)
-
-#define DC_COLOR_KEY 0xB8
-#define DC_CLR_KEY_ENABLE (1 << 24)
-
-
-#define DC3_DV_LINE_SIZE_MASK 0x00000C00
-#define DC3_DV_LINE_SIZE_1024 0x00000000
-#define DC3_DV_LINE_SIZE_2048 0x00000400
-#define DC3_DV_LINE_SIZE_4096 0x00000800
-#define DC3_DV_LINE_SIZE_8192 0x00000C00
-
-#define DF_VIDEO_CFG 0x0
-#define DF_VCFG_VID_EN (1 << 0)
-
-#define DF_DISPLAY_CFG 0x08
-
-#define DF_DCFG_CRT_EN (1 << 0)
-#define DF_DCFG_HSYNC_EN (1 << 1)
-#define DF_DCFG_VSYNC_EN (1 << 2)
-#define DF_DCFG_DAC_BL_EN (1 << 3)
-#define DF_DCFG_CRT_HSYNC_POL (1 << 8)
-#define DF_DCFG_CRT_VSYNC_POL (1 << 9)
-#define DF_DCFG_GV_PAL_BYP (1 << 21)
+enum fp_registers {
+ FP_PT1 = 0,
+ FP_PT2,
-#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000
-#define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000
+ FP_PM,
+ FP_DFC,
-#define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000
-#define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000
+ FP_RSVD_0,
+ FP_RSVD_1,
-#define DF_MISC 0x50
+ FP_RSVD_2,
+ FP_RSVD_3,
+
+ FP_RSVD_4,
+ FP_DCA,
+
+ FP_DMD,
+ FP_CRC, /* 0x458 */
+};
+
+#define FP_PT2_SCRC (1 << 27) /* shfclk free */
+
+#define FP_PM_P (1 << 24) /* panel power ctl */
+#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */
+#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */
+#define FP_PM_PANEL_OFF (1 << 1) /* r/o */
+#define FP_PM_PANEL_ON (1 << 0) /* r/o */
+
+#define FP_DFC_BC ((1 << 4) | (1 << 5) | (1 << 6))
+
+
+/* register access functions */
+
+static inline uint32_t read_gp(struct lxfb_par *par, int reg)
+{
+ return readl(par->gp_regs + 4*reg);
+}
+
+static inline void write_gp(struct lxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->gp_regs + 4*reg);
+}
+
+static inline uint32_t read_dc(struct lxfb_par *par, int reg)
+{
+ return readl(par->dc_regs + 4*reg);
+}
+
+static inline void write_dc(struct lxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->dc_regs + 4*reg);
+}
+
+static inline uint32_t read_vp(struct lxfb_par *par, int reg)
+{
+ return readl(par->vp_regs + 8*reg);
+}
+
+static inline void write_vp(struct lxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->vp_regs + 8*reg);
+}
+
+static inline uint32_t read_fp(struct lxfb_par *par, int reg)
+{
+ return readl(par->vp_regs + 8*reg + VP_FP_START);
+}
+
+static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val)
+{
+ writel(val, par->vp_regs + 8*reg + VP_FP_START);
+}
-#define DF_MISC_GAM_BYPASS (1 << 0)
-#define DF_MISC_DAC_PWRDN (1 << 10)
-#define DF_MISC_A_PWRDN (1 << 11)
-#define DF_PAR 0x38
-#define DF_PDR 0x40
-#define DF_ALPHA_CONTROL_1 0xD8
-#define DF_VIDEO_REQUEST 0x120
+/* MSRs are defined in asm/geode.h; their bitfields are here */
-#define DF_PANEL_TIM1 0x400
-#define DF_DEFAULT_TFT_PMTIM1 0x0
+#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */
+#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24)
+#define MSR_GLCP_DOTPLL_BYPASS (1 << 15)
+#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0)
-#define DF_PANEL_TIM2 0x408
-#define DF_DEFAULT_TFT_PMTIM2 0x08000000
+/* note: this is actually the VP's GLD_MSR_CONFIG */
+#define MSR_LX_GLD_MSR_CONFIG_FMT ((1 << 3) | (1 << 4) | (1 << 5))
+#define MSR_LX_GLD_MSR_CONFIG_FMT_FP (1 << 3)
+#define MSR_LX_GLD_MSR_CONFIG_FMT_CRT (0)
+#define MSR_LX_GLD_MSR_CONFIG_FPC (1 << 15) /* FP *and* CRT */
-#define DF_FP_PM 0x410
-#define DF_FP_PM_P (1 << 24)
+#define MSR_LX_MSR_PADSEL_TFT_SEL_LOW 0xDFFFFFFF /* ??? */
+#define MSR_LX_MSR_PADSEL_TFT_SEL_HIGH 0x0000003F /* ??? */
-#define DF_DITHER_CONTROL 0x418
-#define DF_DEFAULT_TFT_DITHCTL 0x00000070
-#define GP_BLT_STATUS 0x44
-#define GP_BS_BLT_BUSY (1 << 0)
-#define GP_BS_CB_EMPTY (1 << 4)
+#define MSR_LX_SPARE_MSR_DIS_CFIFO_HGO (1 << 11) /* undocumented */
+#define MSR_LX_SPARE_MSR_VFIFO_ARB_SEL (1 << 10) /* undocumented */
+#define MSR_LX_SPARE_MSR_WM_LPEN_OVRD (1 << 9) /* undocumented */
+#define MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M (1 << 8) /* undocumented */
+#define MSR_LX_SPARE_MSR_DIS_INIT_V_PRI (1 << 7) /* undocumented */
+#define MSR_LX_SPARE_MSR_DIS_VIFO_WM (1 << 6)
+#define MSR_LX_SPARE_MSR_DIS_CWD_CHECK (1 << 5) /* undocumented */
+#define MSR_LX_SPARE_MSR_PIX8_PAN_FIX (1 << 4) /* undocumented */
+#define MSR_LX_SPARE_MSR_FIRST_REQ_MASK (1 << 1) /* undocumented */
#endif
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
index eb6b88171538..2cd9b74d2225 100644
--- a/drivers/video/geode/lxfb_core.c
+++ b/drivers/video/geode/lxfb_core.c
@@ -17,6 +17,7 @@
#include <linux/console.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
@@ -27,14 +28,15 @@
static char *mode_option;
static int noclear, nopanel, nocrt;
-static int fbsize;
+static int vram;
+static int vt_switch;
/* Most of these modes are sorted in ascending order, but
* since the first entry in this table is the "default" mode,
* we try to make it something sane - 640x480-60 is sane
*/
-static const struct fb_videomode geode_modedb[] __initdata = {
+static struct fb_videomode geode_modedb[] __initdata = {
/* 640x480-60 */
{ NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
@@ -215,6 +217,35 @@ static const struct fb_videomode geode_modedb[] __initdata = {
0, FB_VMODE_NONINTERLACED, 0 },
};
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+
+static struct fb_videomode olpc_dcon_modedb[] __initdata = {
+ /* The only mode the DCON has is 1200x900 */
+ { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 }
+};
+
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+ if (olpc_has_dcon()) {
+ *modedb = (struct fb_videomode *) olpc_dcon_modedb;
+ *size = ARRAY_SIZE(olpc_dcon_modedb);
+ } else {
+ *modedb = (struct fb_videomode *) geode_modedb;
+ *size = ARRAY_SIZE(geode_modedb);
+ }
+}
+
+#else
+static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+{
+ *modedb = (struct fb_videomode *) geode_modedb;
+ *size = ARRAY_SIZE(geode_modedb);
+}
+#endif
+
static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
if (var->xres > 1920 || var->yres > 1440)
@@ -333,13 +364,13 @@ static int __init lxfb_map_video_memory(struct fb_info *info,
if (ret)
return ret;
- ret = pci_request_region(dev, 3, "lxfb-vip");
+ ret = pci_request_region(dev, 3, "lxfb-vp");
if (ret)
return ret;
info->fix.smem_start = pci_resource_start(dev, 0);
- info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size();
+ info->fix.smem_len = vram ? vram : lx_framebuffer_size();
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
@@ -360,18 +391,15 @@ static int __init lxfb_map_video_memory(struct fb_info *info,
if (par->dc_regs == NULL)
return ret;
- par->df_regs = ioremap(pci_resource_start(dev, 3),
+ par->vp_regs = ioremap(pci_resource_start(dev, 3),
pci_resource_len(dev, 3));
- if (par->df_regs == NULL)
+ if (par->vp_regs == NULL)
return ret;
- writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
-
- writel(info->fix.smem_start & 0xFF000000,
- par->dc_regs + DC_PHY_MEM_OFFSET);
-
- writel(0, par->dc_regs + DC_UNLOCK);
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
+ write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000);
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
info->fix.smem_len / 1024, info->fix.smem_start);
@@ -431,6 +459,45 @@ static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
return info;
}
+#ifdef CONFIG_PM
+static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+
+ if (state.event == PM_EVENT_SUSPEND) {
+ acquire_console_sem();
+ lx_powerdown(info);
+ fb_set_suspend(info, 1);
+ release_console_sem();
+ }
+
+ /* there's no point in setting PCI states; we emulate PCI, so
+ * we don't end up getting power savings anyways */
+
+ return 0;
+}
+
+static int lxfb_resume(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ int ret;
+
+ acquire_console_sem();
+ ret = lx_powerup(info);
+ if (ret) {
+ printk(KERN_ERR "lxfb: power up failed!\n");
+ return ret;
+ }
+
+ fb_set_suspend(info, 0);
+ release_console_sem();
+ return 0;
+}
+#else
+#define lxfb_suspend NULL
+#define lxfb_resume NULL
+#endif
+
static int __init lxfb_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -439,7 +506,7 @@ static int __init lxfb_probe(struct pci_dev *pdev,
int ret;
struct fb_videomode *modedb_ptr;
- int modedb_size;
+ unsigned int modedb_size;
info = lxfb_init_fbinfo(&pdev->dev);
@@ -464,9 +531,7 @@ static int __init lxfb_probe(struct pci_dev *pdev,
/* Set up the mode database */
- modedb_ptr = (struct fb_videomode *) geode_modedb;
- modedb_size = ARRAY_SIZE(geode_modedb);
-
+ get_modedb(&modedb_ptr, &modedb_size);
ret = fb_find_mode(&info->var, info, mode_option,
modedb_ptr, modedb_size, NULL, 16);
@@ -487,6 +552,8 @@ static int __init lxfb_probe(struct pci_dev *pdev,
lxfb_check_var(&info->var, info);
lxfb_set_par(info);
+ pm_set_vt_switch(vt_switch);
+
if (register_framebuffer(info) < 0) {
ret = -EINVAL;
goto err;
@@ -510,8 +577,8 @@ err:
iounmap(par->dc_regs);
pci_release_region(pdev, 2);
}
- if (par->df_regs) {
- iounmap(par->df_regs);
+ if (par->vp_regs) {
+ iounmap(par->vp_regs);
pci_release_region(pdev, 3);
}
@@ -537,7 +604,7 @@ static void lxfb_remove(struct pci_dev *pdev)
iounmap(par->dc_regs);
pci_release_region(pdev, 2);
- iounmap(par->df_regs);
+ iounmap(par->vp_regs);
pci_release_region(pdev, 3);
pci_set_drvdata(pdev, NULL);
@@ -556,6 +623,8 @@ static struct pci_driver lxfb_driver = {
.id_table = lxfb_id_table,
.probe = lxfb_probe,
.remove = lxfb_remove,
+ .suspend = lxfb_suspend,
+ .resume = lxfb_resume,
};
#ifndef MODULE
@@ -570,9 +639,7 @@ static int __init lxfb_setup(char *options)
if (!*opt)
continue;
- if (!strncmp(opt, "fbsize:", 7))
- fbsize = simple_strtoul(opt+7, NULL, 0);
- else if (!strcmp(opt, "noclear"))
+ if (!strcmp(opt, "noclear"))
noclear = 1;
else if (!strcmp(opt, "nopanel"))
nopanel = 1;
@@ -609,8 +676,11 @@ module_exit(lxfb_cleanup);
module_param(mode_option, charp, 0);
MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
-module_param(fbsize, int, 0);
-MODULE_PARM_DESC(fbsize, "video memory size");
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram, "video memory size");
+
+module_param(vt_switch, int, 0);
+MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
index 4fbc99be96ef..cd9d4cc26954 100644
--- a/drivers/video/geode/lxfb_ops.c
+++ b/drivers/video/geode/lxfb_ops.c
@@ -13,6 +13,7 @@
#include <linux/fb.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
+#include <asm/geode.h>
#include "lxfb.h"
@@ -34,35 +35,85 @@ static const struct {
unsigned int pllval;
unsigned int freq;
} pll_table[] = {
- { 0x000031AC, 24923 },
- { 0x0000215D, 25175 },
- { 0x00001087, 27000 },
- { 0x0000216C, 28322 },
- { 0x0000218D, 28560 },
- { 0x000010C9, 31200 },
- { 0x00003147, 31500 },
- { 0x000010A7, 33032 },
- { 0x00002159, 35112 },
- { 0x00004249, 35500 },
- { 0x00000057, 36000 },
- { 0x0000219A, 37889 },
- { 0x00002158, 39168 },
- { 0x00000045, 40000 },
- { 0x00000089, 43163 },
- { 0x000010E7, 44900 },
- { 0x00002136, 45720 },
- { 0x00003207, 49500 },
- { 0x00002187, 50000 },
- { 0x00004286, 56250 },
- { 0x000010E5, 60065 },
- { 0x00004214, 65000 },
- { 0x00001105, 68179 },
- { 0x000031E4, 74250 },
- { 0x00003183, 75000 },
- { 0x00004284, 78750 },
- { 0x00001104, 81600 },
- { 0x00006363, 94500 },
- { 0x00005303, 97520 },
+ { 0x000131AC, 6231 },
+ { 0x0001215D, 6294 },
+ { 0x00011087, 6750 },
+ { 0x0001216C, 7081 },
+ { 0x0001218D, 7140 },
+ { 0x000110C9, 7800 },
+ { 0x00013147, 7875 },
+ { 0x000110A7, 8258 },
+ { 0x00012159, 8778 },
+ { 0x00014249, 8875 },
+ { 0x00010057, 9000 },
+ { 0x0001219A, 9472 },
+ { 0x00012158, 9792 },
+ { 0x00010045, 10000 },
+ { 0x00010089, 10791 },
+ { 0x000110E7, 11225 },
+ { 0x00012136, 11430 },
+ { 0x00013207, 12375 },
+ { 0x00012187, 12500 },
+ { 0x00014286, 14063 },
+ { 0x000110E5, 15016 },
+ { 0x00014214, 16250 },
+ { 0x00011105, 17045 },
+ { 0x000131E4, 18563 },
+ { 0x00013183, 18750 },
+ { 0x00014284, 19688 },
+ { 0x00011104, 20400 },
+ { 0x00016363, 23625 },
+ { 0x00015303, 24380 },
+ { 0x000031AC, 24923 },
+ { 0x0000215D, 25175 },
+ { 0x00001087, 27000 },
+ { 0x0000216C, 28322 },
+ { 0x0000218D, 28560 },
+ { 0x00010041, 29913 },
+ { 0x000010C9, 31200 },
+ { 0x00003147, 31500 },
+ { 0x000141A1, 32400 },
+ { 0x000010A7, 33032 },
+ { 0x00012182, 33375 },
+ { 0x000141B1, 33750 },
+ { 0x00002159, 35112 },
+ { 0x00004249, 35500 },
+ { 0x00000057, 36000 },
+ { 0x000141E1, 37125 },
+ { 0x0000219A, 37889 },
+ { 0x00002158, 39168 },
+ { 0x00000045, 40000 },
+ { 0x000131A1, 40500 },
+ { 0x00010061, 42301 },
+ { 0x00000089, 43163 },
+ { 0x00012151, 43875 },
+ { 0x000010E7, 44900 },
+ { 0x00002136, 45720 },
+ { 0x000152E1, 47250 },
+ { 0x00010071, 48000 },
+ { 0x00003207, 49500 },
+ { 0x00002187, 50000 },
+ { 0x00014291, 50625 },
+ { 0x00011101, 51188 },
+ { 0x00017481, 54563 },
+ { 0x00004286, 56250 },
+ { 0x00014170, 57375 },
+ { 0x00016210, 58500 },
+ { 0x000010E5, 60065 },
+ { 0x00013140, 62796 },
+ { 0x00004214, 65000 },
+ { 0x00016250, 65250 },
+ { 0x00001105, 68179 },
+ { 0x000141C0, 69600 },
+ { 0x00015220, 70160 },
+ { 0x00010050, 72000 },
+ { 0x000031E4, 74250 },
+ { 0x00003183, 75000 },
+ { 0x00004284, 78750 },
+ { 0x00012130, 80052 },
+ { 0x00001104, 81600 },
+ { 0x00006363, 94500 },
+ { 0x00005303, 97520 },
{ 0x00002183, 100187 },
{ 0x00002122, 101420 },
{ 0x00001081, 108000 },
@@ -101,16 +152,16 @@ static void lx_set_dotpll(u32 pllval)
u32 dotpll_lo, dotpll_hi;
int i;
- rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+ rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
- if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval))
+ if ((dotpll_lo & MSR_GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval))
return;
dotpll_hi = pllval;
- dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX);
- dotpll_lo |= GLCP_DOTPLL_RESET;
+ dotpll_lo &= ~(MSR_GLCP_DOTPLL_BYPASS | MSR_GLCP_DOTPLL_HALFPIX);
+ dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET;
- wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+ wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
/* Wait 100us for the PLL to lock */
@@ -119,15 +170,15 @@ static void lx_set_dotpll(u32 pllval)
/* Now, loop for the lock bit */
for (i = 0; i < 1000; i++) {
- rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
- if (dotpll_lo & GLCP_DOTPLL_LOCK)
+ rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+ if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK)
break;
}
/* Clear the reset bit */
- dotpll_lo &= ~GLCP_DOTPLL_RESET;
- wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+ dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET;
+ wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
}
/* Set the clock based on the frequency specified by the current mode */
@@ -137,7 +188,7 @@ static void lx_set_clock(struct fb_info *info)
unsigned int diff, min, best = 0;
unsigned int freq, i;
- freq = (unsigned int) (0x3b9aca00 / info->var.pixclock);
+ freq = (unsigned int) (1000000000 / info->var.pixclock);
min = abs(pll_table[0].freq - freq);
@@ -149,7 +200,7 @@ static void lx_set_clock(struct fb_info *info)
}
}
- lx_set_dotpll(pll_table[best].pllval & 0x7FFF);
+ lx_set_dotpll(pll_table[best].pllval & 0x00017FFF);
}
static void lx_graphics_disable(struct fb_info *info)
@@ -159,63 +210,62 @@ static void lx_graphics_disable(struct fb_info *info)
/* Note: This assumes that the video is in a quitet state */
- writel(0, par->df_regs + DF_ALPHA_CONTROL_1);
- writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32);
- writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64);
+ write_vp(par, VP_A1T, 0);
+ write_vp(par, VP_A2T, 0);
+ write_vp(par, VP_A3T, 0);
/* Turn off the VGA and video enable */
- val = readl (par->dc_regs + DC_GENERAL_CFG) &
- ~(DC_GCFG_VGAE | DC_GCFG_VIDE);
+ val = read_dc(par, DC_GENERAL_CFG) & ~(DC_GENERAL_CFG_VGAE |
+ DC_GENERAL_CFG_VIDE);
- writel(val, par->dc_regs + DC_GENERAL_CFG);
+ write_dc(par, DC_GENERAL_CFG, val);
- val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN;
- writel(val, par->df_regs + DF_VIDEO_CFG);
+ val = read_vp(par, VP_VCFG) & ~VP_VCFG_VID_EN;
+ write_vp(par, VP_VCFG, val);
- writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK |
- DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS,
- par->dc_regs + DC_IRQ);
+ write_dc(par, DC_IRQ, DC_IRQ_MASK | DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK |
+ DC_IRQ_STATUS | DC_IRQ_VIP_VSYNC_IRQ_STATUS);
- val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE;
- writel(val, par->dc_regs + DC_GENLCK_CTRL);
+ val = read_dc(par, DC_GENLK_CTL) & ~DC_GENLK_CTL_GENLK_EN;
+ write_dc(par, DC_GENLK_CTL, val);
- val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE;
- writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY);
+ val = read_dc(par, DC_CLR_KEY);
+ write_dc(par, DC_CLR_KEY, val & ~DC_CLR_KEY_CLR_KEY_EN);
- /* We don't actually blank the panel, due to the long latency
- involved with bringing it back */
+ /* turn off the panel */
+ write_fp(par, FP_PM, read_fp(par, FP_PM) & ~FP_PM_P);
- val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN;
- writel(val, par->df_regs + DF_MISC);
+ val = read_vp(par, VP_MISC) | VP_MISC_DACPWRDN;
+ write_vp(par, VP_MISC, val);
/* Turn off the display */
- val = readl(par->df_regs + DF_DISPLAY_CFG);
- writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN |
- DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG);
+ val = read_vp(par, VP_DCFG);
+ write_vp(par, VP_DCFG, val & ~(VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN |
+ VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN));
- gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
- gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE);
- writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+ gcfg = read_dc(par, DC_GENERAL_CFG);
+ gcfg &= ~(DC_GENERAL_CFG_CMPE | DC_GENERAL_CFG_DECE);
+ write_dc(par, DC_GENERAL_CFG, gcfg);
/* Turn off the TGEN */
- val = readl(par->dc_regs + DC_DISPLAY_CFG);
- val &= ~DC_DCFG_TGEN;
- writel(val, par->dc_regs + DC_DISPLAY_CFG);
+ val = read_dc(par, DC_DISPLAY_CFG);
+ val &= ~DC_DISPLAY_CFG_TGEN;
+ write_dc(par, DC_DISPLAY_CFG, val);
/* Wait 1000 usecs to ensure that the TGEN is clear */
udelay(1000);
/* Turn off the FIFO loader */
- gcfg &= ~DC_GCFG_DFLE;
- writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+ gcfg &= ~DC_GENERAL_CFG_DFLE;
+ write_dc(par, DC_GENERAL_CFG, gcfg);
/* Lastly, wait for the GP to go idle */
do {
- val = readl(par->gp_regs + GP_BLT_STATUS);
- } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY));
+ val = read_gp(par, GP_BLT_STATUS);
+ } while ((val & GP_BLT_STATUS_PB) || !(val & GP_BLT_STATUS_CE));
}
static void lx_graphics_enable(struct fb_info *info)
@@ -224,80 +274,85 @@ static void lx_graphics_enable(struct fb_info *info)
u32 temp, config;
/* Set the video request register */
- writel(0, par->df_regs + DF_VIDEO_REQUEST);
+ write_vp(par, VP_VRR, 0);
/* Set up the polarities */
- config = readl(par->df_regs + DF_DISPLAY_CFG);
+ config = read_vp(par, VP_DCFG);
- config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK |
- DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL);
+ config &= ~(VP_DCFG_CRT_SYNC_SKW | VP_DCFG_PWR_SEQ_DELAY |
+ VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL);
- config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT |
- DF_DCFG_GV_PAL_BYP);
+ config |= (VP_DCFG_CRT_SYNC_SKW_DEFAULT | VP_DCFG_PWR_SEQ_DELAY_DEFAULT
+ | VP_DCFG_GV_GAM);
if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
- config |= DF_DCFG_CRT_HSYNC_POL;
+ config |= VP_DCFG_CRT_HSYNC_POL;
if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
- config |= DF_DCFG_CRT_VSYNC_POL;
+ config |= VP_DCFG_CRT_VSYNC_POL;
if (par->output & OUTPUT_PANEL) {
u32 msrlo, msrhi;
- writel(DF_DEFAULT_TFT_PMTIM1,
- par->df_regs + DF_PANEL_TIM1);
- writel(DF_DEFAULT_TFT_PMTIM2,
- par->df_regs + DF_PANEL_TIM2);
- writel(DF_DEFAULT_TFT_DITHCTL,
- par->df_regs + DF_DITHER_CONTROL);
+ write_fp(par, FP_PT1, 0);
+ write_fp(par, FP_PT2, FP_PT2_SCRC);
+ write_fp(par, FP_DFC, FP_DFC_BC);
- msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW;
- msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH;
+ msrlo = MSR_LX_MSR_PADSEL_TFT_SEL_LOW;
+ msrhi = MSR_LX_MSR_PADSEL_TFT_SEL_HIGH;
- wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi);
+ wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi);
}
if (par->output & OUTPUT_CRT) {
- config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN |
- DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN;
+ config |= VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN |
+ VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN;
}
- writel(config, par->df_regs + DF_DISPLAY_CFG);
+ write_vp(par, VP_DCFG, config);
/* Turn the CRT dacs back on */
if (par->output & OUTPUT_CRT) {
- temp = readl(par->df_regs + DF_MISC);
- temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN);
- writel(temp, par->df_regs + DF_MISC);
+ temp = read_vp(par, VP_MISC);
+ temp &= ~(VP_MISC_DACPWRDN | VP_MISC_APWRDN);
+ write_vp(par, VP_MISC, temp);
}
/* Turn the panel on (if it isn't already) */
-
- if (par->output & OUTPUT_PANEL) {
- temp = readl(par->df_regs + DF_FP_PM);
-
- if (!(temp & 0x09))
- writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM);
- }
-
- temp = readl(par->df_regs + DF_MISC);
- temp = readl(par->df_regs + DF_DISPLAY_CFG);
+ if (par->output & OUTPUT_PANEL)
+ write_fp(par, FP_PM, read_fp(par, FP_PM) | FP_PM_P);
}
unsigned int lx_framebuffer_size(void)
{
unsigned int val;
+ if (!geode_has_vsa2()) {
+ uint32_t hi, lo;
+
+ /* The number of pages is (PMAX - PMIN)+1 */
+ rdmsr(MSR_GLIU_P2D_RO0, lo, hi);
+
+ /* PMAX */
+ val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20);
+ /* PMIN */
+ val -= (lo & 0x000fffff);
+ val += 1;
+
+ /* The page size is 4k */
+ return (val << 12);
+ }
+
/* The frame buffer size is reported by a VSM in VSA II */
/* Virtual Register Class = 0x02 */
/* VG_MEM_SIZE (1MB units) = 0x00 */
- outw(0xFC53, 0xAC1C);
- outw(0x0200, 0xAC1C);
+ outw(VSA_VR_UNLOCK, VSA_VRC_INDEX);
+ outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX);
- val = (unsigned int)(inw(0xAC1E)) & 0xFE;
+ val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFE;
return (val << 20);
}
@@ -313,7 +368,7 @@ void lx_set_mode(struct fb_info *info)
int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
/* Unlock the DC registers */
- writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
lx_graphics_disable(info);
@@ -321,102 +376,104 @@ void lx_set_mode(struct fb_info *info)
/* Set output mode */
- rdmsrl(MSR_LX_DF_GLCONFIG, msrval);
- msrval &= ~DF_CONFIG_OUTPUT_MASK;
+ rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval);
+ msrval &= ~MSR_LX_GLD_MSR_CONFIG_FMT;
if (par->output & OUTPUT_PANEL) {
- msrval |= DF_OUTPUT_PANEL;
+ msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_FP;
if (par->output & OUTPUT_CRT)
- msrval |= DF_SIMULTANEOUS_CRT_AND_FP;
+ msrval |= MSR_LX_GLD_MSR_CONFIG_FPC;
else
- msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP;
- } else {
- msrval |= DF_OUTPUT_CRT;
- }
+ msrval &= ~MSR_LX_GLD_MSR_CONFIG_FPC;
+ } else
+ msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_CRT;
- wrmsrl(MSR_LX_DF_GLCONFIG, msrval);
+ wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval);
/* Clear the various buffers */
/* FIXME: Adjust for panning here */
- writel(0, par->dc_regs + DC_FB_START);
- writel(0, par->dc_regs + DC_CB_START);
- writel(0, par->dc_regs + DC_CURSOR_START);
+ write_dc(par, DC_FB_ST_OFFSET, 0);
+ write_dc(par, DC_CB_ST_OFFSET, 0);
+ write_dc(par, DC_CURS_ST_OFFSET, 0);
/* FIXME: Add support for interlacing */
/* FIXME: Add support for scaling */
- val = readl(par->dc_regs + DC_GENLCK_CTRL);
- val &= ~(DC_GC_ALPHA_FLICK_ENABLE |
- DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK);
+ val = read_dc(par, DC_GENLK_CTL);
+ val &= ~(DC_GENLK_CTL_ALPHA_FLICK_EN | DC_GENLK_CTL_FLICK_EN |
+ DC_GENLK_CTL_FLICK_SEL_MASK);
/* Default scaling params */
- writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE);
- writel(0, par->dc_regs + DC_IRQ_FILT_CTL);
- writel(val, par->dc_regs + DC_GENLCK_CTRL);
+ write_dc(par, DC_GFX_SCALE, (0x4000 << 16) | 0x4000);
+ write_dc(par, DC_IRQ_FILT_CTL, 0);
+ write_dc(par, DC_GENLK_CTL, val);
/* FIXME: Support compression */
if (info->fix.line_length > 4096)
- dv = DC_DV_LINE_SIZE_8192;
+ dv = DC_DV_CTL_DV_LINE_SIZE_8K;
else if (info->fix.line_length > 2048)
- dv = DC_DV_LINE_SIZE_4096;
+ dv = DC_DV_CTL_DV_LINE_SIZE_4K;
else if (info->fix.line_length > 1024)
- dv = DC_DV_LINE_SIZE_2048;
+ dv = DC_DV_CTL_DV_LINE_SIZE_2K;
else
- dv = DC_DV_LINE_SIZE_1024;
+ dv = DC_DV_CTL_DV_LINE_SIZE_1K;
max = info->fix.line_length * info->var.yres;
max = (max + 0x3FF) & 0xFFFFFC00;
- writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP);
+ write_dc(par, DC_DV_TOP, max | DC_DV_TOP_DV_TOP_EN);
- val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK;
- writel(val | dv, par->dc_regs + DC_DV_CTL);
+ val = read_dc(par, DC_DV_CTL) & ~DC_DV_CTL_DV_LINE_SIZE;
+ write_dc(par, DC_DV_CTL, val | dv);
size = info->var.xres * (info->var.bits_per_pixel >> 3);
- writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH);
- writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE);
+ write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3);
+ write_dc(par, DC_LINE_SIZE, (size + 7) >> 3);
/* Set default watermark values */
- rdmsrl(MSR_LX_DC_SPARE, msrval);
-
- msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT |
- DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD |
- DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM);
- msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI;
- wrmsrl(MSR_LX_DC_SPARE, msrval);
-
- gcfg = DC_GCFG_DFLE; /* Display fifo enable */
- gcfg |= 0xB600; /* Set default priority */
- gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */
-
- dcfg = DC_DCFG_VDEN; /* Enable video data */
- dcfg |= DC_DCFG_GDEN; /* Enable graphics */
- dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */
- dcfg |= DC_DCFG_TRUP; /* Update timings immediately */
- dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */
- dcfg |= DC_DCFG_VISL;
- dcfg |= DC_DCFG_DCEN; /* Always center the display */
+ rdmsrl(MSR_LX_SPARE_MSR, msrval);
+
+ msrval &= ~(MSR_LX_SPARE_MSR_DIS_CFIFO_HGO
+ | MSR_LX_SPARE_MSR_VFIFO_ARB_SEL
+ | MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M
+ | MSR_LX_SPARE_MSR_WM_LPEN_OVRD);
+ msrval |= MSR_LX_SPARE_MSR_DIS_VIFO_WM |
+ MSR_LX_SPARE_MSR_DIS_INIT_V_PRI;
+ wrmsrl(MSR_LX_SPARE_MSR, msrval);
+
+ gcfg = DC_GENERAL_CFG_DFLE; /* Display fifo enable */
+ gcfg |= (0x6 << DC_GENERAL_CFG_DFHPSL_SHIFT) | /* default priority */
+ (0xb << DC_GENERAL_CFG_DFHPEL_SHIFT);
+ gcfg |= DC_GENERAL_CFG_FDTY; /* Set the frame dirty mode */
+
+ dcfg = DC_DISPLAY_CFG_VDEN; /* Enable video data */
+ dcfg |= DC_DISPLAY_CFG_GDEN; /* Enable graphics */
+ dcfg |= DC_DISPLAY_CFG_TGEN; /* Turn on the timing generator */
+ dcfg |= DC_DISPLAY_CFG_TRUP; /* Update timings immediately */
+ dcfg |= DC_DISPLAY_CFG_PALB; /* Palette bypass in > 8 bpp modes */
+ dcfg |= DC_DISPLAY_CFG_VISL;
+ dcfg |= DC_DISPLAY_CFG_DCEN; /* Always center the display */
/* Set the current BPP mode */
switch (info->var.bits_per_pixel) {
case 8:
- dcfg |= DC_DCFG_DISP_MODE_8BPP;
+ dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP;
break;
case 16:
- dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP;
+ dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP;
break;
case 32:
case 24:
- dcfg |= DC_DCFG_DISP_MODE_24BPP;
+ dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP;
break;
}
@@ -436,35 +493,31 @@ void lx_set_mode(struct fb_info *info)
vblankend = vsyncend + info->var.upper_margin;
vtotal = vblankend;
- writel((hactive - 1) | ((htotal - 1) << 16),
- par->dc_regs + DC_H_ACTIVE_TIMING);
- writel((hblankstart - 1) | ((hblankend - 1) << 16),
- par->dc_regs + DC_H_BLANK_TIMING);
- writel((hsyncstart - 1) | ((hsyncend - 1) << 16),
- par->dc_regs + DC_H_SYNC_TIMING);
-
- writel((vactive - 1) | ((vtotal - 1) << 16),
- par->dc_regs + DC_V_ACTIVE_TIMING);
+ write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | ((htotal - 1) << 16));
+ write_dc(par, DC_H_BLANK_TIMING,
+ (hblankstart - 1) | ((hblankend - 1) << 16));
+ write_dc(par, DC_H_SYNC_TIMING,
+ (hsyncstart - 1) | ((hsyncend - 1) << 16));
- writel((vblankstart - 1) | ((vblankend - 1) << 16),
- par->dc_regs + DC_V_BLANK_TIMING);
+ write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | ((vtotal - 1) << 16));
+ write_dc(par, DC_V_BLANK_TIMING,
+ (vblankstart - 1) | ((vblankend - 1) << 16));
+ write_dc(par, DC_V_SYNC_TIMING,
+ (vsyncstart - 1) | ((vsyncend - 1) << 16));
- writel((vsyncstart - 1) | ((vsyncend - 1) << 16),
- par->dc_regs + DC_V_SYNC_TIMING);
-
- writel( (info->var.xres - 1) << 16 | (info->var.yres - 1),
- par->dc_regs + DC_FB_ACTIVE);
+ write_dc(par, DC_FB_ACTIVE,
+ (info->var.xres - 1) << 16 | (info->var.yres - 1));
/* And re-enable the graphics output */
lx_graphics_enable(info);
/* Write the two main configuration registers */
- writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
- writel(0, par->dc_regs + DC_ARB_CFG);
- writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+ write_dc(par, DC_DISPLAY_CFG, dcfg);
+ write_dc(par, DC_ARB_CFG, 0);
+ write_dc(par, DC_GENERAL_CFG, gcfg);
/* Lock the DC registers */
- writel(0, par->dc_regs + DC_UNLOCK);
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
}
void lx_set_palette_reg(struct fb_info *info, unsigned regno,
@@ -479,58 +532,310 @@ void lx_set_palette_reg(struct fb_info *info, unsigned regno,
val |= (green) & 0x00ff00;
val |= (blue >> 8) & 0x0000ff;
- writel(regno, par->dc_regs + DC_PAL_ADDRESS);
- writel(val, par->dc_regs + DC_PAL_DATA);
+ write_dc(par, DC_PAL_ADDRESS, regno);
+ write_dc(par, DC_PAL_DATA, val);
}
int lx_blank_display(struct fb_info *info, int blank_mode)
{
struct lxfb_par *par = info->par;
u32 dcfg, fp_pm;
- int blank, hsync, vsync;
+ int blank, hsync, vsync, crt;
/* CRT power saving modes. */
switch (blank_mode) {
case FB_BLANK_UNBLANK:
- blank = 0; hsync = 1; vsync = 1;
+ blank = 0; hsync = 1; vsync = 1; crt = 1;
break;
case FB_BLANK_NORMAL:
- blank = 1; hsync = 1; vsync = 1;
+ blank = 1; hsync = 1; vsync = 1; crt = 1;
break;
case FB_BLANK_VSYNC_SUSPEND:
- blank = 1; hsync = 1; vsync = 0;
+ blank = 1; hsync = 1; vsync = 0; crt = 1;
break;
case FB_BLANK_HSYNC_SUSPEND:
- blank = 1; hsync = 0; vsync = 1;
+ blank = 1; hsync = 0; vsync = 1; crt = 1;
break;
case FB_BLANK_POWERDOWN:
- blank = 1; hsync = 0; vsync = 0;
+ blank = 1; hsync = 0; vsync = 0; crt = 0;
break;
default:
return -EINVAL;
}
- dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
- dcfg &= ~(DF_DCFG_DAC_BL_EN
- | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
+ dcfg = read_vp(par, VP_DCFG);
+ dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
+ VP_DCFG_CRT_EN);
if (!blank)
- dcfg |= DF_DCFG_DAC_BL_EN;
+ dcfg |= VP_DCFG_DAC_BL_EN;
if (hsync)
- dcfg |= DF_DCFG_HSYNC_EN;
+ dcfg |= VP_DCFG_HSYNC_EN;
if (vsync)
- dcfg |= DF_DCFG_VSYNC_EN;
- writel(dcfg, par->df_regs + DF_DISPLAY_CFG);
+ dcfg |= VP_DCFG_VSYNC_EN;
+ if (crt)
+ dcfg |= VP_DCFG_CRT_EN;
+ write_vp(par, VP_DCFG, dcfg);
/* Power on/off flat panel */
if (par->output & OUTPUT_PANEL) {
- fp_pm = readl(par->df_regs + DF_FP_PM);
+ fp_pm = read_fp(par, FP_PM);
if (blank_mode == FB_BLANK_POWERDOWN)
- fp_pm &= ~DF_FP_PM_P;
+ fp_pm &= ~FP_PM_P;
else
- fp_pm |= DF_FP_PM_P;
- writel(fp_pm, par->df_regs + DF_FP_PM);
+ fp_pm |= FP_PM_P;
+ write_fp(par, FP_PM, fp_pm);
}
return 0;
}
+
+#ifdef CONFIG_PM
+
+static void lx_save_regs(struct lxfb_par *par)
+{
+ uint32_t filt;
+ int i;
+
+ /* wait for the BLT engine to stop being busy */
+ do {
+ i = read_gp(par, GP_BLT_STATUS);
+ } while ((i & GP_BLT_STATUS_PB) || !(i & GP_BLT_STATUS_CE));
+
+ /* save MSRs */
+ rdmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel);
+ rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll);
+ rdmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg);
+ rdmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare);
+
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
+
+ /* save registers */
+ memcpy(par->gp, par->gp_regs, sizeof(par->gp));
+ memcpy(par->dc, par->dc_regs, sizeof(par->dc));
+ memcpy(par->vp, par->vp_regs, sizeof(par->vp));
+ memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp));
+
+ /* save the palette */
+ write_dc(par, DC_PAL_ADDRESS, 0);
+ for (i = 0; i < ARRAY_SIZE(par->pal); i++)
+ par->pal[i] = read_dc(par, DC_PAL_DATA);
+
+ /* save the horizontal filter coefficients */
+ filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
+ for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) {
+ write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
+ par->hcoeff[i] = read_dc(par, DC_FILT_COEFF1);
+ par->hcoeff[i + 1] = read_dc(par, DC_FILT_COEFF2);
+ }
+
+ /* save the vertical filter coefficients */
+ filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL;
+ for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) {
+ write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
+ par->vcoeff[i] = read_dc(par, DC_FILT_COEFF1);
+ }
+
+ /* save video coeff ram */
+ memcpy(par->vp_coeff, par->vp_regs + VP_VCR, sizeof(par->vp_coeff));
+}
+
+static void lx_restore_gfx_proc(struct lxfb_par *par)
+{
+ int i;
+
+ /* a bunch of registers require GP_RASTER_MODE to be set first */
+ write_gp(par, GP_RASTER_MODE, par->gp[GP_RASTER_MODE]);
+
+ for (i = 0; i < ARRAY_SIZE(par->gp); i++) {
+ switch (i) {
+ case GP_RASTER_MODE:
+ case GP_VECTOR_MODE:
+ case GP_BLT_MODE:
+ case GP_BLT_STATUS:
+ case GP_HST_SRC:
+ /* FIXME: restore LUT data */
+ case GP_LUT_INDEX:
+ case GP_LUT_DATA:
+ /* don't restore these registers */
+ break;
+
+ default:
+ write_gp(par, i, par->gp[i]);
+ }
+ }
+}
+
+static void lx_restore_display_ctlr(struct lxfb_par *par)
+{
+ uint32_t filt;
+ int i;
+
+ wrmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare);
+
+ for (i = 0; i < ARRAY_SIZE(par->dc); i++) {
+ switch (i) {
+ case DC_UNLOCK:
+ /* unlock the DC; runs first */
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
+ break;
+
+ case DC_GENERAL_CFG:
+ case DC_DISPLAY_CFG:
+ /* disable all while restoring */
+ write_dc(par, i, 0);
+ break;
+
+ case DC_DV_CTL:
+ /* set all ram to dirty */
+ write_dc(par, i, par->dc[i] | DC_DV_CTL_CLEAR_DV_RAM);
+
+ case DC_RSVD_1:
+ case DC_RSVD_2:
+ case DC_RSVD_3:
+ case DC_LINE_CNT:
+ case DC_PAL_ADDRESS:
+ case DC_PAL_DATA:
+ case DC_DFIFO_DIAG:
+ case DC_CFIFO_DIAG:
+ case DC_FILT_COEFF1:
+ case DC_FILT_COEFF2:
+ case DC_RSVD_4:
+ case DC_RSVD_5:
+ /* don't restore these registers */
+ break;
+
+ default:
+ write_dc(par, i, par->dc[i]);
+ }
+ }
+
+ /* restore the palette */
+ write_dc(par, DC_PAL_ADDRESS, 0);
+ for (i = 0; i < ARRAY_SIZE(par->pal); i++)
+ write_dc(par, DC_PAL_DATA, par->pal[i]);
+
+ /* restore the horizontal filter coefficients */
+ filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL;
+ for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) {
+ write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
+ write_dc(par, DC_FILT_COEFF1, par->hcoeff[i]);
+ write_dc(par, DC_FILT_COEFF2, par->hcoeff[i + 1]);
+ }
+
+ /* restore the vertical filter coefficients */
+ filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL;
+ for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) {
+ write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i);
+ write_dc(par, DC_FILT_COEFF1, par->vcoeff[i]);
+ }
+}
+
+static void lx_restore_video_proc(struct lxfb_par *par)
+{
+ int i;
+
+ wrmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg);
+ wrmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel);
+
+ for (i = 0; i < ARRAY_SIZE(par->vp); i++) {
+ switch (i) {
+ case VP_VCFG:
+ case VP_DCFG:
+ case VP_PAR:
+ case VP_PDR:
+ case VP_CCS:
+ case VP_RSVD_0:
+ /* case VP_VDC: */ /* why should this not be restored? */
+ case VP_RSVD_1:
+ case VP_CRC32:
+ /* don't restore these registers */
+ break;
+
+ default:
+ write_vp(par, i, par->vp[i]);
+ }
+ }
+
+ /* restore video coeff ram */
+ memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff));
+}
+
+static void lx_restore_regs(struct lxfb_par *par)
+{
+ int i;
+
+ lx_set_dotpll((u32) (par->msr.dotpll >> 32));
+ lx_restore_gfx_proc(par);
+ lx_restore_display_ctlr(par);
+ lx_restore_video_proc(par);
+
+ /* Flat Panel */
+ for (i = 0; i < ARRAY_SIZE(par->fp); i++) {
+ switch (i) {
+ case FP_PM:
+ case FP_RSVD_0:
+ case FP_RSVD_1:
+ case FP_RSVD_2:
+ case FP_RSVD_3:
+ case FP_RSVD_4:
+ /* don't restore these registers */
+ break;
+
+ default:
+ write_fp(par, i, par->fp[i]);
+ }
+ }
+
+ /* control the panel */
+ if (par->fp[FP_PM] & FP_PM_P) {
+ /* power on the panel if not already power{ed,ing} on */
+ if (!(read_fp(par, FP_PM) &
+ (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP)))
+ write_fp(par, FP_PM, par->fp[FP_PM]);
+ } else {
+ /* power down the panel if not already power{ed,ing} down */
+ if (!(read_fp(par, FP_PM) &
+ (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN)))
+ write_fp(par, FP_PM, par->fp[FP_PM]);
+ }
+
+ /* turn everything on */
+ write_vp(par, VP_VCFG, par->vp[VP_VCFG]);
+ write_vp(par, VP_DCFG, par->vp[VP_DCFG]);
+ write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]);
+ /* do this last; it will enable the FIFO load */
+ write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]);
+
+ /* lock the door behind us */
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
+}
+
+int lx_powerdown(struct fb_info *info)
+{
+ struct lxfb_par *par = info->par;
+
+ if (par->powered_down)
+ return 0;
+
+ lx_save_regs(par);
+ lx_graphics_disable(info);
+
+ par->powered_down = 1;
+ return 0;
+}
+
+int lx_powerup(struct fb_info *info)
+{
+ struct lxfb_par *par = info->par;
+
+ if (!par->powered_down)
+ return 0;
+
+ lx_restore_regs(par);
+
+ par->powered_down = 0;
+ return 0;
+}
+
+#endif
diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c
new file mode 100644
index 000000000000..9aff32ef8bb6
--- /dev/null
+++ b/drivers/video/geode/suspend_gx.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2008 Andres Salomon <dilinger@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/fb.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/geode.h>
+#include <asm/delay.h>
+
+#include "gxfb.h"
+
+#ifdef CONFIG_PM
+
+static void gx_save_regs(struct gxfb_par *par)
+{
+ int i;
+
+ /* wait for the BLT engine to stop being busy */
+ do {
+ i = read_gp(par, GP_BLT_STATUS);
+ } while (i & (GP_BLT_STATUS_BLT_PENDING | GP_BLT_STATUS_BLT_BUSY));
+
+ /* save MSRs */
+ rdmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel);
+ rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll);
+
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
+
+ /* save registers */
+ memcpy(par->gp, par->gp_regs, sizeof(par->gp));
+ memcpy(par->dc, par->dc_regs, sizeof(par->dc));
+ memcpy(par->vp, par->vid_regs, sizeof(par->vp));
+ memcpy(par->fp, par->vid_regs + VP_FP_START, sizeof(par->fp));
+
+ /* save the palette */
+ write_dc(par, DC_PAL_ADDRESS, 0);
+ for (i = 0; i < ARRAY_SIZE(par->pal); i++)
+ par->pal[i] = read_dc(par, DC_PAL_DATA);
+}
+
+static void gx_set_dotpll(uint32_t dotpll_hi)
+{
+ uint32_t dotpll_lo;
+ int i;
+
+ rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo);
+ dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET;
+ dotpll_lo &= ~MSR_GLCP_DOTPLL_BYPASS;
+ wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+
+ /* wait for the PLL to lock */
+ for (i = 0; i < 200; i++) {
+ rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo);
+ if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK)
+ break;
+ udelay(1);
+ }
+
+ /* PLL set, unlock */
+ dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET;
+ wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+}
+
+static void gx_restore_gfx_proc(struct gxfb_par *par)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(par->gp); i++) {
+ switch (i) {
+ case GP_VECTOR_MODE:
+ case GP_BLT_MODE:
+ case GP_BLT_STATUS:
+ case GP_HST_SRC:
+ /* don't restore these registers */
+ break;
+ default:
+ write_gp(par, i, par->gp[i]);
+ }
+ }
+}
+
+static void gx_restore_display_ctlr(struct gxfb_par *par)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(par->dc); i++) {
+ switch (i) {
+ case DC_UNLOCK:
+ /* unlock the DC; runs first */
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
+ break;
+
+ case DC_GENERAL_CFG:
+ /* write without the enables */
+ write_dc(par, i, par->dc[i] & ~(DC_GENERAL_CFG_VIDE |
+ DC_GENERAL_CFG_ICNE |
+ DC_GENERAL_CFG_CURE |
+ DC_GENERAL_CFG_DFLE));
+ break;
+
+ case DC_DISPLAY_CFG:
+ /* write without the enables */
+ write_dc(par, i, par->dc[i] & ~(DC_DISPLAY_CFG_VDEN |
+ DC_DISPLAY_CFG_GDEN |
+ DC_DISPLAY_CFG_TGEN));
+ break;
+
+ case DC_RSVD_0:
+ case DC_RSVD_1:
+ case DC_RSVD_2:
+ case DC_RSVD_3:
+ case DC_RSVD_4:
+ case DC_LINE_CNT:
+ case DC_PAL_ADDRESS:
+ case DC_PAL_DATA:
+ case DC_DFIFO_DIAG:
+ case DC_CFIFO_DIAG:
+ case DC_RSVD_5:
+ /* don't restore these registers */
+ break;
+ default:
+ write_dc(par, i, par->dc[i]);
+ }
+ }
+
+ /* restore the palette */
+ write_dc(par, DC_PAL_ADDRESS, 0);
+ for (i = 0; i < ARRAY_SIZE(par->pal); i++)
+ write_dc(par, DC_PAL_DATA, par->pal[i]);
+}
+
+static void gx_restore_video_proc(struct gxfb_par *par)
+{
+ int i;
+
+ wrmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel);
+
+ for (i = 0; i < ARRAY_SIZE(par->vp); i++) {
+ switch (i) {
+ case VP_VCFG:
+ /* don't enable video yet */
+ write_vp(par, i, par->vp[i] & ~VP_VCFG_VID_EN);
+ break;
+
+ case VP_DCFG:
+ /* don't enable CRT yet */
+ write_vp(par, i, par->vp[i] &
+ ~(VP_DCFG_DAC_BL_EN | VP_DCFG_VSYNC_EN |
+ VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN));
+ break;
+
+ case VP_GAR:
+ case VP_GDR:
+ case VP_RSVD_0:
+ case VP_RSVD_1:
+ case VP_RSVD_2:
+ case VP_RSVD_3:
+ case VP_CRC32:
+ case VP_AWT:
+ case VP_VTM:
+ /* don't restore these registers */
+ break;
+ default:
+ write_vp(par, i, par->vp[i]);
+ }
+ }
+}
+
+static void gx_restore_regs(struct gxfb_par *par)
+{
+ int i;
+
+ gx_set_dotpll((uint32_t) (par->msr.dotpll >> 32));
+ gx_restore_gfx_proc(par);
+ gx_restore_display_ctlr(par);
+ gx_restore_video_proc(par);
+
+ /* Flat Panel */
+ for (i = 0; i < ARRAY_SIZE(par->fp); i++) {
+ if (i != FP_PM && i != FP_RSVD_0)
+ write_fp(par, i, par->fp[i]);
+ }
+}
+
+static void gx_disable_graphics(struct gxfb_par *par)
+{
+ /* shut down the engine */
+ write_vp(par, VP_VCFG, par->vp[VP_VCFG] & ~VP_VCFG_VID_EN);
+ write_vp(par, VP_DCFG, par->vp[VP_DCFG] & ~(VP_DCFG_DAC_BL_EN |
+ VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN));
+
+ /* turn off the flat panel */
+ write_fp(par, FP_PM, par->fp[FP_PM] & ~FP_PM_P);
+
+
+ /* turn off display */
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK);
+ write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG] &
+ ~(DC_GENERAL_CFG_VIDE | DC_GENERAL_CFG_ICNE |
+ DC_GENERAL_CFG_CURE | DC_GENERAL_CFG_DFLE));
+ write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG] &
+ ~(DC_DISPLAY_CFG_VDEN | DC_DISPLAY_CFG_GDEN |
+ DC_DISPLAY_CFG_TGEN));
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
+}
+
+static void gx_enable_graphics(struct gxfb_par *par)
+{
+ uint32_t fp;
+
+ fp = read_fp(par, FP_PM);
+ if (par->fp[FP_PM] & FP_PM_P) {
+ /* power on the panel if not already power{ed,ing} on */
+ if (!(fp & (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP)))
+ write_fp(par, FP_PM, par->fp[FP_PM]);
+ } else {
+ /* power down the panel if not already power{ed,ing} down */
+ if (!(fp & (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN)))
+ write_fp(par, FP_PM, par->fp[FP_PM]);
+ }
+
+ /* turn everything on */
+ write_vp(par, VP_VCFG, par->vp[VP_VCFG]);
+ write_vp(par, VP_DCFG, par->vp[VP_DCFG]);
+ write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]);
+ /* do this last; it will enable the FIFO load */
+ write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]);
+
+ /* lock the door behind us */
+ write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK);
+}
+
+int gx_powerdown(struct fb_info *info)
+{
+ struct gxfb_par *par = info->par;
+
+ if (par->powered_down)
+ return 0;
+
+ gx_save_regs(par);
+ gx_disable_graphics(par);
+
+ par->powered_down = 1;
+ return 0;
+}
+
+int gx_powerup(struct fb_info *info)
+{
+ struct gxfb_par *par = info->par;
+
+ if (!par->powered_down)
+ return 0;
+
+ gx_restore_regs(par);
+ gx_enable_graphics(par);
+
+ par->powered_down = 0;
+ return 0;
+}
+
+#endif
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c
index febf09c63492..b8d52a8360db 100644
--- a/drivers/video/geode/video_gx.c
+++ b/drivers/video/geode/video_gx.c
@@ -16,9 +16,9 @@
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/msr.h>
+#include <asm/geode.h>
-#include "geodefb.h"
-#include "video_gx.h"
+#include "gxfb.h"
/*
@@ -117,7 +117,7 @@ static const struct gx_pll_entry gx_pll_table_14MHz[] = {
{ 4357, 0, 0x0000057D }, /* 229.5000 */
};
-static void gx_set_dclk_frequency(struct fb_info *info)
+void gx_set_dclk_frequency(struct fb_info *info)
{
const struct gx_pll_entry *pll_table;
int pll_table_len;
@@ -178,110 +178,116 @@ static void gx_set_dclk_frequency(struct fb_info *info)
static void
gx_configure_tft(struct fb_info *info)
{
- struct geodefb_par *par = info->par;
+ struct gxfb_par *par = info->par;
unsigned long val;
unsigned long fp;
/* Set up the DF pad select MSR */
- rdmsrl(GX_VP_MSR_PAD_SELECT, val);
- val &= ~GX_VP_PAD_SELECT_MASK;
- val |= GX_VP_PAD_SELECT_TFT;
- wrmsrl(GX_VP_MSR_PAD_SELECT, val);
+ rdmsrl(MSR_GX_MSR_PADSEL, val);
+ val &= ~MSR_GX_MSR_PADSEL_MASK;
+ val |= MSR_GX_MSR_PADSEL_TFT;
+ wrmsrl(MSR_GX_MSR_PADSEL, val);
/* Turn off the panel */
- fp = readl(par->vid_regs + GX_FP_PM);
- fp &= ~GX_FP_PM_P;
- writel(fp, par->vid_regs + GX_FP_PM);
+ fp = read_fp(par, FP_PM);
+ fp &= ~FP_PM_P;
+ write_fp(par, FP_PM, fp);
/* Set timing 1 */
- fp = readl(par->vid_regs + GX_FP_PT1);
- fp &= GX_FP_PT1_VSIZE_MASK;
- fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
- writel(fp, par->vid_regs + GX_FP_PT1);
+ fp = read_fp(par, FP_PT1);
+ fp &= FP_PT1_VSIZE_MASK;
+ fp |= info->var.yres << FP_PT1_VSIZE_SHIFT;
+ write_fp(par, FP_PT1, fp);
/* Timing 2 */
/* Set bits that are always on for TFT */
fp = 0x0F100000;
- /* Add sync polarity */
+ /* Configure sync polarity */
if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
- fp |= GX_FP_PT2_VSP;
+ fp |= FP_PT2_VSP;
if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
- fp |= GX_FP_PT2_HSP;
+ fp |= FP_PT2_HSP;
- writel(fp, par->vid_regs + GX_FP_PT2);
+ write_fp(par, FP_PT2, fp);
/* Set the dither control */
- writel(0x70, par->vid_regs + GX_FP_DFC);
+ write_fp(par, FP_DFC, FP_DFC_NFI);
/* Enable the FP data and power (in case the BIOS didn't) */
- fp = readl(par->vid_regs + GX_DCFG);
- fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN;
- writel(fp, par->vid_regs + GX_DCFG);
+ fp = read_vp(par, VP_DCFG);
+ fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN;
+ write_vp(par, VP_DCFG, fp);
/* Unblank the panel */
- fp = readl(par->vid_regs + GX_FP_PM);
- fp |= GX_FP_PM_P;
- writel(fp, par->vid_regs + GX_FP_PM);
+ fp = read_fp(par, FP_PM);
+ fp |= FP_PM_P;
+ write_fp(par, FP_PM, fp);
}
-static void gx_configure_display(struct fb_info *info)
+void gx_configure_display(struct fb_info *info)
{
- struct geodefb_par *par = info->par;
+ struct gxfb_par *par = info->par;
u32 dcfg, misc;
- /* Set up the MISC register */
-
- misc = readl(par->vid_regs + GX_MISC);
-
- /* Power up the DAC */
- misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
-
- /* Disable gamma correction */
- misc |= GX_MISC_GAM_EN;
-
- writel(misc, par->vid_regs + GX_MISC);
-
/* Write the display configuration */
- dcfg = readl(par->vid_regs + GX_DCFG);
+ dcfg = read_vp(par, VP_DCFG);
/* Disable hsync and vsync */
- dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
- writel(dcfg, par->vid_regs + GX_DCFG);
+ dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
+ write_vp(par, VP_DCFG, dcfg);
/* Clear bits from existing mode. */
- dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
- | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
- | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
+ dcfg &= ~(VP_DCFG_CRT_SYNC_SKW
+ | VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL
+ | VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
/* Set default sync skew. */
- dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT;
+ dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT;
/* Enable hsync and vsync. */
- dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN;
+ dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN;
- /* Sync polarities. */
- if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
- dcfg |= GX_DCFG_CRT_HSYNC_POL;
- if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
- dcfg |= GX_DCFG_CRT_VSYNC_POL;
+ misc = read_vp(par, VP_MISC);
+
+ /* Disable gamma correction */
+ misc |= VP_MISC_GAM_EN;
+
+ if (par->enable_crt) {
+
+ /* Power up the CRT DACs */
+ misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN);
+ write_vp(par, VP_MISC, misc);
+
+ /* Only change the sync polarities if we are running
+ * in CRT mode. The FP polarities will be handled in
+ * gxfb_configure_tft */
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ dcfg |= VP_DCFG_CRT_HSYNC_POL;
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ dcfg |= VP_DCFG_CRT_VSYNC_POL;
+ } else {
+ /* Power down the CRT DACs if in FP mode */
+ misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN);
+ write_vp(par, VP_MISC, misc);
+ }
/* Enable the display logic */
/* Set up the DACS to blank normally */
- dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
+ dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN;
/* Enable the external DAC VREF? */
- writel(dcfg, par->vid_regs + GX_DCFG);
+ write_vp(par, VP_DCFG, dcfg);
/* Set up the flat panel (if it is enabled) */
@@ -289,59 +295,55 @@ static void gx_configure_display(struct fb_info *info)
gx_configure_tft(info);
}
-static int gx_blank_display(struct fb_info *info, int blank_mode)
+int gx_blank_display(struct fb_info *info, int blank_mode)
{
- struct geodefb_par *par = info->par;
+ struct gxfb_par *par = info->par;
u32 dcfg, fp_pm;
- int blank, hsync, vsync;
+ int blank, hsync, vsync, crt;
/* CRT power saving modes. */
switch (blank_mode) {
case FB_BLANK_UNBLANK:
- blank = 0; hsync = 1; vsync = 1;
+ blank = 0; hsync = 1; vsync = 1; crt = 1;
break;
case FB_BLANK_NORMAL:
- blank = 1; hsync = 1; vsync = 1;
+ blank = 1; hsync = 1; vsync = 1; crt = 1;
break;
case FB_BLANK_VSYNC_SUSPEND:
- blank = 1; hsync = 1; vsync = 0;
+ blank = 1; hsync = 1; vsync = 0; crt = 1;
break;
case FB_BLANK_HSYNC_SUSPEND:
- blank = 1; hsync = 0; vsync = 1;
+ blank = 1; hsync = 0; vsync = 1; crt = 1;
break;
case FB_BLANK_POWERDOWN:
- blank = 1; hsync = 0; vsync = 0;
+ blank = 1; hsync = 0; vsync = 0; crt = 0;
break;
default:
return -EINVAL;
}
- dcfg = readl(par->vid_regs + GX_DCFG);
- dcfg &= ~(GX_DCFG_DAC_BL_EN
- | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN);
+ dcfg = read_vp(par, VP_DCFG);
+ dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
+ VP_DCFG_CRT_EN);
if (!blank)
- dcfg |= GX_DCFG_DAC_BL_EN;
+ dcfg |= VP_DCFG_DAC_BL_EN;
if (hsync)
- dcfg |= GX_DCFG_HSYNC_EN;
+ dcfg |= VP_DCFG_HSYNC_EN;
if (vsync)
- dcfg |= GX_DCFG_VSYNC_EN;
- writel(dcfg, par->vid_regs + GX_DCFG);
+ dcfg |= VP_DCFG_VSYNC_EN;
+ if (crt)
+ dcfg |= VP_DCFG_CRT_EN;
+ write_vp(par, VP_DCFG, dcfg);
/* Power on/off flat panel. */
if (par->enable_crt == 0) {
- fp_pm = readl(par->vid_regs + GX_FP_PM);
+ fp_pm = read_fp(par, FP_PM);
if (blank_mode == FB_BLANK_POWERDOWN)
- fp_pm &= ~GX_FP_PM_P;
+ fp_pm &= ~FP_PM_P;
else
- fp_pm |= GX_FP_PM_P;
- writel(fp_pm, par->vid_regs + GX_FP_PM);
+ fp_pm |= FP_PM_P;
+ write_fp(par, FP_PM, fp_pm);
}
return 0;
}
-
-struct geode_vid_ops gx_vid_ops = {
- .set_dclk = gx_set_dclk_frequency,
- .configure_display = gx_configure_display,
- .blank_display = gx_blank_display,
-};
diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h
deleted file mode 100644
index ce28d8f382dc..000000000000
--- a/drivers/video/geode/video_gx.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Geode GX video device
- *
- * Copyright (C) 2006 Arcom Control Systems Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-#ifndef __VIDEO_GX_H__
-#define __VIDEO_GX_H__
-
-extern struct geode_vid_ops gx_vid_ops;
-
-/* GX Flatpanel control MSR */
-#define GX_VP_MSR_PAD_SELECT 0xC0002011
-#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF
-#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF
-
-/* Geode GX video processor registers */
-
-#define GX_DCFG 0x0008
-# define GX_DCFG_CRT_EN 0x00000001
-# define GX_DCFG_HSYNC_EN 0x00000002
-# define GX_DCFG_VSYNC_EN 0x00000004
-# define GX_DCFG_DAC_BL_EN 0x00000008
-# define GX_DCFG_FP_PWR_EN 0x00000040
-# define GX_DCFG_FP_DATA_EN 0x00000080
-# define GX_DCFG_CRT_HSYNC_POL 0x00000100
-# define GX_DCFG_CRT_VSYNC_POL 0x00000200
-# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000
-# define GX_DCFG_CRT_SYNC_SKW_DFLT 0x00010000
-# define GX_DCFG_VG_CK 0x00100000
-# define GX_DCFG_GV_GAM 0x00200000
-# define GX_DCFG_DAC_VREF 0x04000000
-
-/* Geode GX MISC video configuration */
-
-#define GX_MISC 0x50
-#define GX_MISC_GAM_EN 0x00000001
-#define GX_MISC_DAC_PWRDN 0x00000400
-#define GX_MISC_A_PWRDN 0x00000800
-
-/* Geode GX flat panel display control registers */
-
-#define GX_FP_PT1 0x0400
-#define GX_FP_PT1_VSIZE_MASK 0x7FF0000
-#define GX_FP_PT1_VSIZE_SHIFT 16
-
-#define GX_FP_PT2 0x408
-#define GX_FP_PT2_VSP (1 << 23)
-#define GX_FP_PT2_HSP (1 << 22)
-
-#define GX_FP_PM 0x410
-# define GX_FP_PM_P 0x01000000
-
-#define GX_FP_DFC 0x418
-
-/* Geode GX clock control MSRs */
-
-#define MSR_GLCP_SYS_RSTPLL 0x4c000014
-# define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull)
-# define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull)
-# define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull)
-
-#define MSR_GLCP_DOTPLL 0x4c000015
-# define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull)
-# define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull)
-# define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull)
-
-#endif /* !__VIDEO_GX_H__ */
diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c
index e92337bef50d..564557792bed 100644
--- a/drivers/video/gxt4500.c
+++ b/drivers/video/gxt4500.c
@@ -238,7 +238,7 @@ static int calc_pll(int period_ps, struct gxt4500_par *par)
for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) {
for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) {
postdiv = pdiv1 * pdiv2;
- pll_period = (period_ps + postdiv - 1) / postdiv;
+ pll_period = DIV_ROUND_UP(period_ps, postdiv);
/* keep pll in range 350..600 MHz */
if (pll_period < 1666 || pll_period > 2857)
continue;
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c
index 94e0df8a6f60..0b4bffbe67c8 100644
--- a/drivers/video/hecubafb.c
+++ b/drivers/video/hecubafb.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller
+ * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller
*
* Copyright (C) 2006, Jaya Kumar
* This work was sponsored by CIS(M) Sdn Bhd
@@ -17,18 +17,13 @@
* values. There are other commands that the display is capable of,
* beyond the 5 used here but they are more complex.
*
- * This driver is written to be used with the Hecuba display controller
- * board, and tested with the EInk 800x600 display in 1 bit mode.
- * The interface between Hecuba and the host is TTL based GPIO. The
- * GPIO requirements are 8 writable data lines and 6 lines for control.
- * Only 4 of the controls are actually used here but 6 for future use.
- * The driver requires the IO addresses for data and control GPIO at
- * load time. It is also possible to use this display with a standard
- * PC parallel port.
+ * This driver is written to be used with the Hecuba display architecture.
+ * The actual display chip is called Apollo and the interface electronics
+ * it needs is called Hecuba.
*
- * General notes:
- * - User must set hecubafb_enable=1 to enable it
- * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR
+ * It is intended to be architecture independent. A board specific driver
+ * must be used to perform all the physical IO interactions. An example
+ * is provided as n411.c
*
*/
@@ -47,34 +42,12 @@
#include <linux/list.h>
#include <linux/uaccess.h>
-/* Apollo controller specific defines */
-#define APOLLO_START_NEW_IMG 0xA0
-#define APOLLO_STOP_IMG_DATA 0xA1
-#define APOLLO_DISPLAY_IMG 0xA2
-#define APOLLO_ERASE_DISPLAY 0xA3
-#define APOLLO_INIT_DISPLAY 0xA4
-
-/* Hecuba interface specific defines */
-/* WUP is inverted, CD is inverted, DS is inverted */
-#define HCB_NWUP_BIT 0x01
-#define HCB_NDS_BIT 0x02
-#define HCB_RW_BIT 0x04
-#define HCB_NCD_BIT 0x08
-#define HCB_ACK_BIT 0x80
+#include <video/hecubafb.h>
/* Display specific information */
#define DPY_W 600
#define DPY_H 800
-struct hecubafb_par {
- unsigned long dio_addr;
- unsigned long cio_addr;
- unsigned long c2io_addr;
- unsigned char ctl;
- struct fb_info *info;
- unsigned int irq;
-};
-
static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
.id = "hecubafb",
.type = FB_TYPE_PACKED_PIXELS,
@@ -82,6 +55,7 @@ static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
+ .line_length = DPY_W,
.accel = FB_ACCEL_NONE,
};
@@ -94,136 +68,51 @@ static struct fb_var_screeninfo hecubafb_var __devinitdata = {
.nonstd = 1,
};
-static unsigned long dio_addr;
-static unsigned long cio_addr;
-static unsigned long c2io_addr;
-static unsigned long splashval;
-static unsigned int nosplash;
-static unsigned int hecubafb_enable;
-static unsigned int irq;
-
-static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq);
-
-static void hcb_set_ctl(struct hecubafb_par *par)
-{
- outb(par->ctl, par->cio_addr);
-}
-
-static unsigned char hcb_get_ctl(struct hecubafb_par *par)
-{
- return inb(par->c2io_addr);
-}
-
-static void hcb_set_data(struct hecubafb_par *par, unsigned char value)
-{
- outb(value, par->dio_addr);
-}
-
-static int __devinit apollo_init_control(struct hecubafb_par *par)
-{
- unsigned char ctl;
- /* for init, we want the following setup to be set:
- WUP = lo
- ACK = hi
- DS = hi
- RW = hi
- CD = lo
- */
-
- /* write WUP to lo, DS to hi, RW to hi, CD to lo */
- par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ;
- par->ctl &= ~HCB_NDS_BIT;
- hcb_set_ctl(par);
-
- /* check ACK is not lo */
- ctl = hcb_get_ctl(par);
- if ((ctl & HCB_ACK_BIT)) {
- printk(KERN_ERR "Fail because ACK is already low\n");
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void hcb_wait_for_ack(struct hecubafb_par *par)
-{
-
- int timeout;
- unsigned char ctl;
-
- timeout=500;
- do {
- ctl = hcb_get_ctl(par);
- if ((ctl & HCB_ACK_BIT))
- return;
- udelay(1);
- } while (timeout--);
- printk(KERN_ERR "timed out waiting for ack\n");
-}
-
-static void hcb_wait_for_ack_clear(struct hecubafb_par *par)
-{
-
- int timeout;
- unsigned char ctl;
-
- timeout=500;
- do {
- ctl = hcb_get_ctl(par);
- if (!(ctl & HCB_ACK_BIT))
- return;
- udelay(1);
- } while (timeout--);
- printk(KERN_ERR "timed out waiting for clear\n");
-}
+/* main hecubafb functions */
static void apollo_send_data(struct hecubafb_par *par, unsigned char data)
{
/* set data */
- hcb_set_data(par, data);
+ par->board->set_data(par, data);
/* set DS low */
- par->ctl |= HCB_NDS_BIT;
- hcb_set_ctl(par);
+ par->board->set_ctl(par, HCB_DS_BIT, 0);
- hcb_wait_for_ack(par);
+ /* wait for ack */
+ par->board->wait_for_ack(par, 0);
/* set DS hi */
- par->ctl &= ~(HCB_NDS_BIT);
- hcb_set_ctl(par);
+ par->board->set_ctl(par, HCB_DS_BIT, 1);
- hcb_wait_for_ack_clear(par);
+ /* wait for ack to clear */
+ par->board->wait_for_ack(par, 1);
}
static void apollo_send_command(struct hecubafb_par *par, unsigned char data)
{
/* command so set CD to high */
- par->ctl &= ~(HCB_NCD_BIT);
- hcb_set_ctl(par);
+ par->board->set_ctl(par, HCB_CD_BIT, 1);
/* actually strobe with command */
apollo_send_data(par, data);
/* clear CD back to low */
- par->ctl |= (HCB_NCD_BIT);
- hcb_set_ctl(par);
+ par->board->set_ctl(par, HCB_CD_BIT, 0);
}
-/* main hecubafb functions */
-
static void hecubafb_dpy_update(struct hecubafb_par *par)
{
int i;
unsigned char *buf = (unsigned char __force *)par->info->screen_base;
- apollo_send_command(par, 0xA0);
+ apollo_send_command(par, APOLLO_START_NEW_IMG);
for (i=0; i < (DPY_W*DPY_H/8); i++) {
apollo_send_data(par, *(buf++));
}
- apollo_send_command(par, 0xA1);
- apollo_send_command(par, 0xA2);
+ apollo_send_command(par, APOLLO_STOP_IMG_DATA);
+ apollo_send_command(par, APOLLO_DISPLAY_IMG);
}
/* this is called back from the deferred io workqueue */
@@ -270,41 +159,43 @@ static void hecubafb_imageblit(struct fb_info *info,
static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long p;
- int err=-EINVAL;
- struct hecubafb_par *par;
- unsigned int xres;
- unsigned int fbmemlength;
+ struct hecubafb_par *par = info->par;
+ unsigned long p = *ppos;
+ void *dst;
+ int err = 0;
+ unsigned long total_size;
- p = *ppos;
- par = info->par;
- xres = info->var.xres;
- fbmemlength = (xres * info->var.yres)/8;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
- if (p > fbmemlength)
- return -ENOSPC;
+ total_size = info->fix.smem_len;
- err = 0;
- if ((count + p) > fbmemlength) {
- count = fbmemlength - p;
- err = -ENOSPC;
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
}
- if (count) {
- char *base_addr;
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
- base_addr = (char __force *)info->screen_base;
- count -= copy_from_user(base_addr + p, buf, count);
- *ppos += count;
- err = -EFAULT;
+ count = total_size - p;
}
- hecubafb_dpy_update(par);
+ dst = (void __force *) (info->screen_base + p);
+
+ if (copy_from_user(dst, buf, count))
+ err = -EFAULT;
- if (count)
- return count;
+ if (!err)
+ *ppos += count;
- return err;
+ hecubafb_dpy_update(par);
+
+ return (err) ? err : count;
}
static struct fb_ops hecubafb_ops = {
@@ -324,11 +215,21 @@ static struct fb_deferred_io hecubafb_defio = {
static int __devinit hecubafb_probe(struct platform_device *dev)
{
struct fb_info *info;
+ struct hecuba_board *board;
int retval = -ENOMEM;
int videomemorysize;
unsigned char *videomemory;
struct hecubafb_par *par;
+ /* pick up board specific routines */
+ board = dev->dev.platform_data;
+ if (!board)
+ return -EINVAL;
+
+ /* try to count device specific driver, if can't, platform recalls */
+ if (!try_module_get(board->owner))
+ return -ENODEV;
+
videomemorysize = (DPY_W*DPY_H)/8;
if (!(videomemory = vmalloc(videomemorysize)))
@@ -338,9 +239,9 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
if (!info)
- goto err;
+ goto err_fballoc;
- info->screen_base = (char __iomem *) videomemory;
+ info->screen_base = (char __force __iomem *)videomemory;
info->fbops = &hecubafb_ops;
info->var = hecubafb_var;
@@ -348,14 +249,10 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
info->fix.smem_len = videomemorysize;
par = info->par;
par->info = info;
+ par->board = board;
+ par->send_command = apollo_send_command;
+ par->send_data = apollo_send_data;
- if (!dio_addr || !cio_addr || !c2io_addr) {
- printk(KERN_WARNING "no IO addresses supplied\n");
- goto err1;
- }
- par->dio_addr = dio_addr;
- par->cio_addr = cio_addr;
- par->c2io_addr = c2io_addr;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbdefio = &hecubafb_defio;
@@ -363,7 +260,7 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
retval = register_framebuffer(info);
if (retval < 0)
- goto err1;
+ goto err_fbreg;
platform_set_drvdata(dev, info);
printk(KERN_INFO
@@ -371,25 +268,16 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
info->node, videomemorysize >> 10);
/* this inits the dpy */
- apollo_init_control(par);
-
- apollo_send_command(par, APOLLO_INIT_DISPLAY);
- apollo_send_data(par, 0x81);
-
- /* have to wait while display resets */
- udelay(1000);
-
- /* if we were told to splash the screen, we just clear it */
- if (!nosplash) {
- apollo_send_command(par, APOLLO_ERASE_DISPLAY);
- apollo_send_data(par, splashval);
- }
+ retval = par->board->init(par);
+ if (retval < 0)
+ goto err_fbreg;
return 0;
-err1:
+err_fbreg:
framebuffer_release(info);
-err:
+err_fballoc:
vfree(videomemory);
+ module_put(board->owner);
return retval;
}
@@ -398,9 +286,13 @@ static int __devexit hecubafb_remove(struct platform_device *dev)
struct fb_info *info = platform_get_drvdata(dev);
if (info) {
+ struct hecubafb_par *par = info->par;
fb_deferred_io_cleanup(info);
unregister_framebuffer(info);
vfree((void __force *)info->screen_base);
+ if (par->board->remove)
+ par->board->remove(par);
+ module_put(par->board->owner);
framebuffer_release(info);
}
return 0;
@@ -410,62 +302,24 @@ static struct platform_driver hecubafb_driver = {
.probe = hecubafb_probe,
.remove = hecubafb_remove,
.driver = {
+ .owner = THIS_MODULE,
.name = "hecubafb",
},
};
-static struct platform_device *hecubafb_device;
-
static int __init hecubafb_init(void)
{
- int ret;
-
- if (!hecubafb_enable) {
- printk(KERN_ERR "Use hecubafb_enable to enable the device\n");
- return -ENXIO;
- }
-
- ret = platform_driver_register(&hecubafb_driver);
- if (!ret) {
- hecubafb_device = platform_device_alloc("hecubafb", 0);
- if (hecubafb_device)
- ret = platform_device_add(hecubafb_device);
- else
- ret = -ENOMEM;
-
- if (ret) {
- platform_device_put(hecubafb_device);
- platform_driver_unregister(&hecubafb_driver);
- }
- }
- return ret;
-
+ return platform_driver_register(&hecubafb_driver);
}
static void __exit hecubafb_exit(void)
{
- platform_device_unregister(hecubafb_device);
platform_driver_unregister(&hecubafb_driver);
}
-module_param(nosplash, uint, 0);
-MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
-module_param(hecubafb_enable, uint, 0);
-MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board");
-module_param(dio_addr, ulong, 0);
-MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
-module_param(cio_addr, ulong, 0);
-MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
-module_param(c2io_addr, ulong, 0);
-MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
-module_param(splashval, ulong, 0);
-MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white");
-module_param(irq, uint, 0);
-MODULE_PARM_DESC(irq, "IRQ for the Hecuba board");
-
module_init(hecubafb_init);
module_exit(hecubafb_exit);
-MODULE_DESCRIPTION("fbdev driver for Hecuba board");
+MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller");
MODULE_AUTHOR("Jaya Kumar");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 3ab91bf21576..15d50b9906ce 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -1151,8 +1151,10 @@ imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc
par->cmap_regs[TVPCRDAT] = 0xff; eieio();
}
par->cmap_regs[TVPCADRW] = 0x00; eieio();
- for (x = 0; x < 12; x++)
- par->cmap_regs[TVPCDATA] = fgc; eieio();
+ for (x = 0; x < 12; x++) {
+ par->cmap_regs[TVPCDATA] = fgc;
+ eieio();
+ }
}
return 1;
}
@@ -1476,7 +1478,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dp = pci_device_to_OF_node(pdev);
if(dp)
- printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name);
+ printk(KERN_INFO "%s: OF name %s\n",__func__, dp->name);
else
printk(KERN_ERR "imsttfb: no OF node for pci device\n");
#endif /* CONFIG_PPC_OF */
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 11609552a387..94e4d3ac1a05 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -415,7 +415,7 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi)
static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
{
struct imxfb_info *fbi = platform_get_drvdata(dev);
- pr_debug("%s\n",__FUNCTION__);
+ pr_debug("%s\n",__func__);
imxfb_disable_controller(fbi);
return 0;
@@ -424,7 +424,7 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
static int imxfb_resume(struct platform_device *dev)
{
struct imxfb_info *fbi = platform_get_drvdata(dev);
- pr_debug("%s\n",__FUNCTION__);
+ pr_debug("%s\n",__func__);
imxfb_enable_controller(fbi);
return 0;
@@ -440,7 +440,7 @@ static int __init imxfb_init_fbinfo(struct device *dev)
struct fb_info *info = dev_get_drvdata(dev);
struct imxfb_info *fbi = info->par;
- pr_debug("%s\n",__FUNCTION__);
+ pr_debug("%s\n",__func__);
info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL);
if (!info->pseudo_palette)
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 836796177942..3325fbd68ab3 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -12,9 +12,9 @@
#endif
/*** Version/name ***/
-#define INTELFB_VERSION "0.9.4"
+#define INTELFB_VERSION "0.9.5"
#define INTELFB_MODULE_NAME "intelfb"
-#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM"
+#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM"
/*** Debug/feature defines ***/
@@ -58,6 +58,8 @@
#define PCI_DEVICE_ID_INTEL_915GM 0x2592
#define PCI_DEVICE_ID_INTEL_945G 0x2772
#define PCI_DEVICE_ID_INTEL_945GM 0x27A2
+#define PCI_DEVICE_ID_INTEL_965G 0x29A2
+#define PCI_DEVICE_ID_INTEL_965GM 0x2A02
/* Size of MMIO region */
#define INTEL_REG_SIZE 0x80000
@@ -158,6 +160,8 @@ enum intel_chips {
INTEL_915GM,
INTEL_945G,
INTEL_945GM,
+ INTEL_965G,
+ INTEL_965GM,
};
struct intelfb_hwstate {
@@ -358,7 +362,9 @@ struct intelfb_info {
#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \
((dinfo)->chipset == INTEL_915GM) || \
((dinfo)->chipset == INTEL_945G) || \
- ((dinfo)->chipset==INTEL_945GM))
+ ((dinfo)->chipset == INTEL_945GM) || \
+ ((dinfo)->chipset == INTEL_965G) || \
+ ((dinfo)->chipset == INTEL_965GM))
#ifndef FBIO_WAITFORVSYNC
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index 94c08bb5acf1..ca95f09d8b43 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -169,6 +169,8 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
/* has some LVDS + tv-out */
case INTEL_945G:
case INTEL_945GM:
+ case INTEL_965G:
+ case INTEL_965GM:
/* SDVO ports have a single control bus - 2 devices */
dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 481d58f7535d..e44303f9bc52 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -2,7 +2,7 @@
* intelfb
*
* Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
- * 945G/945GM integrated graphics chips.
+ * 945G/945GM/965G/965GM integrated graphics chips.
*
* Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer
@@ -99,6 +99,9 @@
* Add vram option to reserve more memory than stolen by BIOS
* Fix intelfbhw_pan_display typo
* Add __initdata annotations
+ *
+ * 04/2008 - Version 0.9.5
+ * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>)
*/
#include <linux/module.h>
@@ -180,6 +183,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM },
{ 0, }
};
@@ -549,7 +554,10 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev,
if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
(ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
(ent->device == PCI_DEVICE_ID_INTEL_945G) ||
- (ent->device == PCI_DEVICE_ID_INTEL_945GM)) {
+ (ent->device == PCI_DEVICE_ID_INTEL_945GM) ||
+ (ent->device == PCI_DEVICE_ID_INTEL_965G) ||
+ (ent->device == PCI_DEVICE_ID_INTEL_965GM)) {
+
aperture_bar = 2;
mmio_bar = 0;
}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index fa1fff553565..8e6d6a4db0ad 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -143,6 +143,18 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
dinfo->mobile = 1;
dinfo->pll_index = PLLS_I9xx;
return 0;
+ case PCI_DEVICE_ID_INTEL_965G:
+ dinfo->name = "Intel(R) 965G";
+ dinfo->chipset = INTEL_965G;
+ dinfo->mobile = 0;
+ dinfo->pll_index = PLLS_I9xx;
+ return 0;
+ case PCI_DEVICE_ID_INTEL_965GM:
+ dinfo->name = "Intel(R) 965GM";
+ dinfo->chipset = INTEL_965GM;
+ dinfo->mobile = 1;
+ dinfo->pll_index = PLLS_I9xx;
+ return 0;
default:
return 1;
}
@@ -174,7 +186,9 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
case PCI_DEVICE_ID_INTEL_915GM:
case PCI_DEVICE_ID_INTEL_945G:
case PCI_DEVICE_ID_INTEL_945GM:
- /* 915 and 945 chipsets support a 256MB aperture.
+ case PCI_DEVICE_ID_INTEL_965G:
+ case PCI_DEVICE_ID_INTEL_965GM:
+ /* 915, 945 and 965 chipsets support a 256MB aperture.
Aperture size is determined by inspected the
base address of the aperture. */
if (pci_resource_start(pdev, 2) & 0x08000000)
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 45b9a5d55dec..f3160fc29795 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -614,7 +614,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id *
dev_set_drvdata(&op->dev, info);
- printk("%s: leo at %lx:%lx\n",
+ printk(KERN_INFO "%s: leo at %lx:%lx\n",
dp->full_name,
par->which_io, par->physbase);
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
index c4b570b4a4df..0ce3b0a89798 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.c
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -37,7 +37,7 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi
unsigned int fvco;
unsigned int p;
- DBG(__FUNCTION__)
+ DBG(__func__)
/* only for devices older than G450 */
@@ -83,7 +83,7 @@ static const unsigned char MGA1064_DAC[] = {
static void DAC1064_setpclk(WPMINFO unsigned long fout) {
unsigned int m, n, p;
- DBG(__FUNCTION__)
+ DBG(__func__)
DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
ACCESS_FBINFO(hw).DACclk[0] = m;
@@ -95,7 +95,7 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
u_int32_t mx;
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (ACCESS_FBINFO(devflags.noinit)) {
/* read MCLK and give up... */
@@ -338,7 +338,7 @@ void DAC1064_global_restore(WPMINFO2) {
static int DAC1064_init_1(WPMINFO struct my_timming* m) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
@@ -374,7 +374,7 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m) {
static int DAC1064_init_2(WPMINFO struct my_timming* m) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */
int i;
@@ -418,7 +418,7 @@ static void DAC1064_restore_1(WPMINFO2) {
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
@@ -448,7 +448,7 @@ static void DAC1064_restore_2(WPMINFO2) {
unsigned int i;
#endif
- DBG(__FUNCTION__)
+ DBG(__func__)
#ifdef DEBUG
dprintk(KERN_DEBUG "DAC1064regs ");
@@ -521,7 +521,7 @@ static struct matrox_altout g450out = {
static int MGA1064_init(WPMINFO struct my_timming* m) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (DAC1064_init_1(PMINFO m)) return 1;
if (matroxfb_vgaHWinit(PMINFO m)) return 1;
@@ -543,7 +543,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m) {
static int MGAG100_init(WPMINFO struct my_timming* m) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (DAC1064_init_1(PMINFO m)) return 1;
hw->MXoptionReg &= ~0x2000;
@@ -565,7 +565,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m) {
#ifdef CONFIG_FB_MATROX_MYSTIQUE
static void MGA1064_ramdac_init(WPMINFO2) {
- DBG(__FUNCTION__)
+ DBG(__func__)
/* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
@@ -594,7 +594,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) {
int selClk;
int clk;
- DBG(__FUNCTION__)
+ DBG(__func__)
outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
M1064_XPIXCLKCTRL_PLL_UP);
@@ -636,7 +636,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) {
static void MGAG100_setPixClock(CPMINFO int flags, int freq) {
unsigned int m, n, p;
- DBG(__FUNCTION__)
+ DBG(__func__)
DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
MGAG100_progPixClock(PMINFO flags, m, n, p);
@@ -650,7 +650,7 @@ static int MGA1064_preinit(WPMINFO2) {
2048, 0};
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
/* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
ACCESS_FBINFO(capable.text) = 1;
@@ -683,7 +683,7 @@ static int MGA1064_preinit(WPMINFO2) {
static void MGA1064_reset(WPMINFO2) {
- DBG(__FUNCTION__);
+ DBG(__func__);
MGA1064_ramdac_init(PMINFO2);
}
@@ -819,7 +819,7 @@ static int MGAG100_preinit(WPMINFO2) {
u_int32_t q;
#endif
- DBG(__FUNCTION__)
+ DBG(__func__)
/* there are some instabilities if in_div > 19 && vco < 61000 */
if (ACCESS_FBINFO(devflags.g450dac)) {
@@ -956,7 +956,7 @@ static void MGAG100_reset(WPMINFO2) {
u_int8_t b;
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
{
#ifdef G100_BROKEN_IBM_82351
@@ -1015,7 +1015,7 @@ static void MGA1064_restore(WPMINFO2) {
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
@@ -1041,7 +1041,7 @@ static void MGAG100_restore(WPMINFO2) {
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index 9445cdb759b1..13524821e242 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -283,7 +283,7 @@ static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* i
unsigned int fvco;
unsigned int lin, lfeed, lpost;
- DBG(__FUNCTION__)
+ DBG(__func__)
fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
fvco >>= (*post = lpost);
@@ -297,7 +297,7 @@ static int Ti3026_setpclk(WPMINFO int clk) {
unsigned int pixfeed, pixin, pixpost;
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
@@ -365,7 +365,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m) {
u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
@@ -440,7 +440,7 @@ static void ti3026_setMCLK(WPMINFO int fout){
unsigned int rfhcnt, mclk_ctl;
int tmout;
- DBG(__FUNCTION__)
+ DBG(__func__)
f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
@@ -534,7 +534,7 @@ static void ti3026_setMCLK(WPMINFO int fout){
static void ti3026_ramdac_init(WPMINFO2) {
- DBG(__FUNCTION__)
+ DBG(__func__)
ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
ACCESS_FBINFO(features.pll.ref_freq) = 114545;
@@ -554,7 +554,7 @@ static void Ti3026_restore(WPMINFO2) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
#ifdef DEBUG
dprintk(KERN_INFO "EXTVGA regs: ");
@@ -662,7 +662,7 @@ static void Ti3026_restore(WPMINFO2) {
static void Ti3026_reset(WPMINFO2) {
- DBG(__FUNCTION__)
+ DBG(__func__)
ti3026_ramdac_init(PMINFO2);
}
@@ -680,7 +680,7 @@ static int Ti3026_preinit(WPMINFO2) {
2048, 0};
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
ACCESS_FBINFO(millenium) = 1;
ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
index 3660d2673bdc..9c3aeee1cc4f 100644
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -113,7 +113,7 @@ void matrox_cfbX_init(WPMINFO2) {
u_int32_t mopmode;
int accel;
- DBG(__FUNCTION__)
+ DBG(__func__)
mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual;
@@ -199,7 +199,7 @@ static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx
int start, end;
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
@@ -235,7 +235,7 @@ static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, in
int start, end;
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
@@ -287,7 +287,7 @@ static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int he
int width) {
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
@@ -315,7 +315,7 @@ static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int heigh
int whattodo;
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
CRITBEGIN
@@ -388,7 +388,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
int easy;
CRITFLAGS
- DBG_HEAVY(__FUNCTION__);
+ DBG_HEAVY(__func__);
step = (width + 7) >> 3;
charcell = height * step;
@@ -469,7 +469,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
MINFO_FROM_INFO(info);
- DBG_HEAVY(__FUNCTION__);
+ DBG_HEAVY(__func__);
if (image->depth == 1) {
u_int32_t fgx, bgx;
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index b25972ac6eeb..54e82f35353d 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -312,7 +312,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
if (ACCESS_FBINFO(dead))
return;
@@ -392,7 +392,7 @@ static int matroxfb_open(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
- DBG_LOOP(__FUNCTION__)
+ DBG_LOOP(__func__)
if (ACCESS_FBINFO(dead)) {
return -ENXIO;
@@ -408,7 +408,7 @@ static int matroxfb_release(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
- DBG_LOOP(__FUNCTION__)
+ DBG_LOOP(__func__)
if (user) {
if (0 == --ACCESS_FBINFO(userusecount)) {
@@ -425,7 +425,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info* info) {
MINFO_FROM_INFO(info);
- DBG(__FUNCTION__)
+ DBG(__func__)
matrox_pan_var(PMINFO var);
return 0;
@@ -434,7 +434,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var,
static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
int bppshft2;
- DBG(__FUNCTION__)
+ DBG(__func__)
bppshft2 = bpp;
if (!bppshft2) {
@@ -451,7 +451,7 @@ static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
int over;
int rounding;
- DBG(__FUNCTION__)
+ DBG(__func__)
switch (bpp) {
case 0: return xres;
@@ -482,7 +482,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
const int* width;
int xres_new;
- DBG(__FUNCTION__)
+ DBG(__func__)
if (!bpp) return xres;
@@ -504,7 +504,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
- DBG(__FUNCTION__)
+ DBG(__func__)
switch (var->bits_per_pixel) {
case 4:
@@ -548,7 +548,7 @@ static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visua
unsigned int vramlen;
unsigned int memlen;
- DBG(__FUNCTION__)
+ DBG(__func__)
switch (bpp) {
case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
@@ -648,7 +648,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
#endif
- DBG(__FUNCTION__)
+ DBG(__func__)
/*
* Set a single color register. The values supplied are
@@ -707,7 +707,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
static void matroxfb_init_fix(WPMINFO2)
{
struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
- DBG(__FUNCTION__)
+ DBG(__func__)
strcpy(fix->id,"MATROX");
@@ -722,7 +722,7 @@ static void matroxfb_init_fix(WPMINFO2)
static void matroxfb_update_fix(WPMINFO2)
{
struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
- DBG(__FUNCTION__)
+ DBG(__func__)
fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
@@ -753,7 +753,7 @@ static int matroxfb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var;
MINFO_FROM_INFO(info);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (ACCESS_FBINFO(dead)) {
return -ENXIO;
@@ -876,7 +876,7 @@ static int matroxfb_ioctl(struct fb_info *info,
void __user *argp = (void __user *)arg;
MINFO_FROM_INFO(info);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (ACCESS_FBINFO(dead)) {
return -ENXIO;
@@ -1175,7 +1175,7 @@ static int matroxfb_blank(int blank, struct fb_info *info)
CRITFLAGS
MINFO_FROM_INFO(info);
- DBG(__FUNCTION__)
+ DBG(__func__)
if (ACCESS_FBINFO(dead))
return 1;
@@ -1287,7 +1287,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
unsigned char bytes[32];
unsigned char* tmp;
- DBG(__FUNCTION__)
+ DBG(__func__)
vm = ACCESS_FBINFO(video.vbase);
maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
@@ -1593,7 +1593,7 @@ static int initMatrox2(WPMINFO struct board* b){
{ },
};
- DBG(__FUNCTION__)
+ DBG(__func__)
/* set default values... */
vesafb_defined.accel_flags = FB_ACCELF_TEXT;
@@ -2006,7 +2006,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
#ifndef CONFIG_FB_MATROX_MULTIHEAD
static int registered = 0;
#endif
- DBG(__FUNCTION__)
+ DBG(__func__)
svid = pdev->subsystem_vendor;
sid = pdev->subsystem_device;
@@ -2301,7 +2301,7 @@ static void __exit matrox_done(void) {
static int __init matroxfb_setup(char *options) {
char *this_opt;
- DBG(__FUNCTION__)
+ DBG(__func__)
if (!options || !*options)
return 0;
@@ -2444,7 +2444,7 @@ static int __init matroxfb_init(void)
char *option = NULL;
int err = 0;
- DBG(__FUNCTION__)
+ DBG(__func__)
if (fb_get_options("matroxfb", &option))
return -ENODEV;
@@ -2556,7 +2556,7 @@ MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit defau
int __init init_module(void){
- DBG(__FUNCTION__)
+ DBG(__func__)
if (disabled)
return -ENXIO;
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index a6ab5b6a58d0..7ac4c5f6145d 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -420,7 +420,7 @@ static int matroxfb_dh_ioctl(struct fb_info *info,
#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
MINFO_FROM(m2info->primary_dev);
- DBG(__FUNCTION__)
+ DBG(__func__)
switch (cmd) {
case FBIOGET_VBLANK:
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 0cd58f84fb46..89da27bd5c49 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -220,7 +220,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
unsigned int scrlen;
unsigned int fmax;
- DBG(__FUNCTION__)
+ DBG(__func__)
scrlen = htotal * (vtotal - 1);
fwant = htotal * vtotal;
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index ab7fb50bc1de..aaa3e538e5da 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -90,13 +90,13 @@
#include <linux/matroxfb.h>
void matroxfb_DAC_out(CPMINFO int reg, int val) {
- DBG_REG(__FUNCTION__)
+ DBG_REG(__func__)
mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
}
int matroxfb_DAC_in(CPMINFO int reg) {
- DBG_REG(__FUNCTION__)
+ DBG_REG(__func__)
mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
}
@@ -104,7 +104,7 @@ int matroxfb_DAC_in(CPMINFO int reg) {
void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
unsigned int pixclock = var->pixclock;
- DBG(__FUNCTION__)
+ DBG(__func__)
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
mt->pixclock = 1000000000 / pixclock;
@@ -131,7 +131,7 @@ int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int f
unsigned int fwant;
unsigned int p;
- DBG(__FUNCTION__)
+ DBG(__func__)
fwant = freq;
@@ -192,7 +192,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) {
int i;
struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
- DBG(__FUNCTION__)
+ DBG(__func__)
hw->SEQ[0] = 0x00;
hw->SEQ[1] = 0x01; /* or 0x09 */
@@ -336,7 +336,7 @@ void matroxfb_vgaHWrestore(WPMINFO2) {
struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw);
CRITFLAGS
- DBG(__FUNCTION__)
+ DBG(__func__)
dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
dprintk(KERN_INFO "SEQ regs: ");
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index e9a89fd82757..249791286367 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -13,12 +13,10 @@
* Corporation. http://support.eink.com/community
*
* This driver is written to be used with the Metronome display controller.
- * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board
- * using the Lyre interface board.
+ * It is intended to be architecture independent. A board specific driver
+ * must be used to perform all the physical IO interactions. An example
+ * is provided as am200epd.c
*
- * General notes:
- * - User must set metronomefb_enable=1 to enable it.
- * - See Documentation/fb/metronomefb.txt for how metronome works.
*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -38,9 +36,11 @@
#include <linux/uaccess.h>
#include <linux/irq.h>
-#include <asm/arch/pxa-regs.h>
+#include <video/metronomefb.h>
+
#include <asm/unaligned.h>
+
#define DEBUG 1
#ifdef DEBUG
#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
@@ -53,35 +53,6 @@
#define DPY_W 832
#define DPY_H 622
-struct metromem_desc {
- u32 mFDADR0;
- u32 mFSADR0;
- u32 mFIDR0;
- u32 mLDCMD0;
-};
-
-struct metromem_cmd {
- u16 opcode;
- u16 args[((64-2)/2)];
- u16 csum;
-};
-
-struct metronomefb_par {
- unsigned char *metromem;
- struct metromem_desc *metromem_desc;
- struct metromem_cmd *metromem_cmd;
- unsigned char *metromem_wfm;
- unsigned char *metromem_img;
- u16 *metromem_img_csum;
- u16 *csum_table;
- int metromemsize;
- dma_addr_t metromem_dma;
- dma_addr_t metromem_desc_dma;
- struct fb_info *info;
- wait_queue_head_t waitq;
- u8 frame_count;
-};
-
/* frame differs from image. frame includes non-visible pixels */
struct epd_frame {
int fw; /* frame width */
@@ -120,8 +91,7 @@ static struct fb_var_screeninfo metronomefb_var __devinitdata = {
.transp = { 0, 0, 0 },
};
-static unsigned int metronomefb_enable;
-
+/* the waveform structure that is coming from userspace firmware */
struct waveform_hdr {
u8 stuff[32];
@@ -301,165 +271,6 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
return 0;
}
-/* register offsets for gpio control */
-#define LED_GPIO_PIN 51
-#define STDBY_GPIO_PIN 48
-#define RST_GPIO_PIN 49
-#define RDY_GPIO_PIN 32
-#define ERR_GPIO_PIN 17
-#define PCBPWR_GPIO_PIN 16
-
-#define AF_SEL_GPIO_N 0x3
-#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
-#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
-#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
-#define GPDR1_OFFSET(pin) (pin - 32)
-#define GPCR1_OFFSET(pin) (pin - 32)
-#define GPSR1_OFFSET(pin) (pin - 32)
-#define GPCR0_OFFSET(pin) (pin)
-#define GPSR0_OFFSET(pin) (pin)
-
-static void metronome_set_gpio_output(int pin, int val)
-{
- u8 index;
-
- index = pin >> 4;
-
- switch (index) {
- case 1:
- if (val)
- GPSR0 |= (1 << GPSR0_OFFSET(pin));
- else
- GPCR0 |= (1 << GPCR0_OFFSET(pin));
- break;
- case 2:
- break;
- case 3:
- if (val)
- GPSR1 |= (1 << GPSR1_OFFSET(pin));
- else
- GPCR1 |= (1 << GPCR1_OFFSET(pin));
- break;
- default:
- printk(KERN_ERR "unimplemented\n");
- }
-}
-
-static void __devinit metronome_init_gpio_pin(int pin, int dir)
-{
- u8 index;
- /* dir 0 is output, 1 is input
- - do 2 things here:
- - set gpio alternate function to standard gpio
- - set gpio direction to input or output */
-
- index = pin >> 4;
- switch (index) {
- case 1:
- GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
-
- if (dir)
- GPDR0 &= ~(1 << pin);
- else
- GPDR0 |= (1 << pin);
- break;
- case 2:
- GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
-
- if (dir)
- GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
- else
- GPDR1 |= (1 << GPDR1_OFFSET(pin));
- break;
- case 3:
- GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
-
- if (dir)
- GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
- else
- GPDR1 |= (1 << GPDR1_OFFSET(pin));
- break;
- default:
- printk(KERN_ERR "unimplemented\n");
- }
-}
-
-static void __devinit metronome_init_gpio_regs(void)
-{
- metronome_init_gpio_pin(LED_GPIO_PIN, 0);
- metronome_set_gpio_output(LED_GPIO_PIN, 0);
-
- metronome_init_gpio_pin(STDBY_GPIO_PIN, 0);
- metronome_set_gpio_output(STDBY_GPIO_PIN, 0);
-
- metronome_init_gpio_pin(RST_GPIO_PIN, 0);
- metronome_set_gpio_output(RST_GPIO_PIN, 0);
-
- metronome_init_gpio_pin(RDY_GPIO_PIN, 1);
-
- metronome_init_gpio_pin(ERR_GPIO_PIN, 1);
-
- metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
- metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0);
-}
-
-static void metronome_disable_lcd_controller(struct metronomefb_par *par)
-{
- LCSR = 0xffffffff; /* Clear LCD Status Register */
- LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
-
- /* we reset and just wait for things to settle */
- msleep(200);
-}
-
-static void metronome_enable_lcd_controller(struct metronomefb_par *par)
-{
- LCSR = 0xffffffff;
- FDADR0 = par->metromem_desc_dma;
- LCCR0 |= LCCR0_ENB;
-}
-
-static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par)
-{
- /* here we do:
- - disable the lcd controller
- - setup lcd control registers
- - setup dma descriptor
- - reenable lcd controller
- */
-
- /* disable the lcd controller */
- metronome_disable_lcd_controller(par);
-
- /* setup lcd control registers */
- LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
- | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
-
- LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */
- | (27 << 10) /* hsync pulse width - 1 */
- | (33 << 16) /* eol pixel count */
- | (33 << 24); /* bol pixel count */
-
- LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */
- | (24 << 10) /* vsync pulse width - 1 */
- | (2 << 16) /* eof pixel count */
- | (0 << 24); /* bof pixel count */
-
- LCCR3 = 2 /* pixel clock divisor */
- | (24 << 8) /* AC Bias pin freq */
- | LCCR3_16BPP /* BPP */
- | LCCR3_PCP; /* PCP falling edge */
-
- /* setup dma descriptor */
- par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
- par->metromem_desc->mFSADR0 = par->metromem_dma;
- par->metromem_desc->mFIDR0 = 0;
- par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw
- * epd_frame_table[0].fh;
- /* reenable lcd controller */
- metronome_enable_lcd_controller(par);
-}
-
static int metronome_display_cmd(struct metronomefb_par *par)
{
int i;
@@ -493,8 +304,7 @@ static int metronome_display_cmd(struct metronomefb_par *par)
par->metromem_cmd->csum = cs;
par->metromem_cmd->opcode = opcode; /* display cmd */
- i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
- return i;
+ return par->board->met_wait_event_intr(par);
}
static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
@@ -518,13 +328,12 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
par->metromem_cmd->csum = cs;
msleep(1);
- metronome_set_gpio_output(RST_GPIO_PIN, 1);
+ par->board->set_rst(par, 1);
msleep(1);
- metronome_set_gpio_output(STDBY_GPIO_PIN, 1);
+ par->board->set_stdby(par, 1);
- i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
- return i;
+ return par->board->met_wait_event(par);
}
static int __devinit metronome_config_cmd(struct metronomefb_par *par)
@@ -569,8 +378,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par)
par->metromem_cmd->csum = cs;
par->metromem_cmd->opcode = 0xCC10; /* config cmd */
- i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
- return i;
+ return par->board->met_wait_event(par);
}
static int __devinit metronome_init_cmd(struct metronomefb_par *par)
@@ -596,16 +404,19 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par)
par->metromem_cmd->csum = cs;
par->metromem_cmd->opcode = 0xCC20; /* init cmd */
- i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
- return i;
+ return par->board->met_wait_event(par);
}
static int __devinit metronome_init_regs(struct metronomefb_par *par)
{
int res;
- metronome_init_gpio_regs();
- metronome_init_lcdc_regs(par);
+ par->board->init_gpio_regs(par);
+
+ par->board->init_lcdc_regs(par);
+
+ /* now that lcd is setup, setup dma descriptor */
+ par->board->post_dma_setup(par);
res = metronome_powerup_cmd(par);
if (res)
@@ -616,8 +427,6 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
return res;
res = metronome_init_cmd(par);
- if (res)
- return res;
return res;
}
@@ -632,7 +441,7 @@ static void metronomefb_dpy_update(struct metronomefb_par *par)
cksum = calc_img_cksum((u16 *) par->metromem_img,
(epd_frame_table[0].fw * DPY_H)/2);
- *((u16 *) (par->metromem_img) +
+ *((u16 *)(par->metromem_img) +
(epd_frame_table[0].fw * DPY_H)/2) = cksum;
metronome_display_cmd(par);
}
@@ -641,8 +450,8 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
{
int i;
u16 csum = 0;
- u16 *buf = (u16 __force *) (par->info->screen_base + index);
- u16 *img = (u16 *) (par->metromem_img + index);
+ u16 *buf = (u16 __force *)(par->info->screen_base + index);
+ u16 *img = (u16 *)(par->metromem_img + index);
/* swizzle from vm to metromem and recalc cksum at the same time*/
for (i = 0; i < PAGE_SIZE/2; i++) {
@@ -678,7 +487,7 @@ static void metronomefb_fillrect(struct fb_info *info,
{
struct metronomefb_par *par = info->par;
- cfb_fillrect(info, rect);
+ sys_fillrect(info, rect);
metronomefb_dpy_update(par);
}
@@ -687,7 +496,7 @@ static void metronomefb_copyarea(struct fb_info *info,
{
struct metronomefb_par *par = info->par;
- cfb_copyarea(info, area);
+ sys_copyarea(info, area);
metronomefb_dpy_update(par);
}
@@ -696,7 +505,7 @@ static void metronomefb_imageblit(struct fb_info *info,
{
struct metronomefb_par *par = info->par;
- cfb_imageblit(info, image);
+ sys_imageblit(info, image);
metronomefb_dpy_update(par);
}
@@ -733,7 +542,7 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
count = total_size - p;
}
- dst = (void __force *) (info->screen_base + p);
+ dst = (void __force *)(info->screen_base + p);
if (copy_from_user(dst, buf, count))
err = -EFAULT;
@@ -759,18 +568,10 @@ static struct fb_deferred_io metronomefb_defio = {
.deferred_io = metronomefb_dpy_deferred_io,
};
-static irqreturn_t metronome_handle_irq(int irq, void *dev_id)
-{
- struct fb_info *info = dev_id;
- struct metronomefb_par *par = info->par;
-
- wake_up_interruptible(&par->waitq);
- return IRQ_HANDLED;
-}
-
static int __devinit metronomefb_probe(struct platform_device *dev)
{
struct fb_info *info;
+ struct metronome_board *board;
int retval = -ENOMEM;
int videomemorysize;
unsigned char *videomemory;
@@ -779,17 +580,26 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
int cmd_size, wfm_size, img_size, padding_size, totalsize;
int i;
+ /* pick up board specific routines */
+ board = dev->dev.platform_data;
+ if (!board)
+ return -EINVAL;
+
+ /* try to count device specific driver, if can't, platform recalls */
+ if (!try_module_get(board->owner))
+ return -ENODEV;
+
/* we have two blocks of memory.
info->screen_base which is vm, and is the fb used by apps.
par->metromem which is physically contiguous memory and
contains the display controller commands, waveform,
processed image data and padding. this is the data pulled
- by the pxa255's LCD controller and pushed to Metronome */
+ by the device's LCD controller and pushed to Metronome */
videomemorysize = (DPY_W*DPY_H);
videomemory = vmalloc(videomemorysize);
if (!videomemory)
- return retval;
+ return -ENOMEM;
memset(videomemory, 0, videomemorysize);
@@ -797,7 +607,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
if (!info)
goto err_vfree;
- info->screen_base = (char __iomem *) videomemory;
+ info->screen_base = (char __force __iomem *)videomemory;
info->fbops = &metronomefb_ops;
info->var = metronomefb_var;
@@ -805,6 +615,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
info->fix.smem_len = videomemorysize;
par = info->par;
par->info = info;
+ par->board = board;
init_waitqueue_head(&par->waitq);
/* this table caches per page csum values. */
@@ -849,11 +660,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
+ img_size + padding_size;
- /* load the waveform in. assume mode 3, temp 31 for now */
- /* a) request the waveform file from userspace
+ /* load the waveform in. assume mode 3, temp 31 for now
+ a) request the waveform file from userspace
b) process waveform and decode into metromem */
-
- retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev);
+ retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
if (retval < 0) {
printk(KERN_ERR "metronomefb: couldn't get waveform\n");
goto err_dma_free;
@@ -861,19 +671,14 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
par->metromem_wfm, 3, 31, &par->frame_count);
+ release_firmware(fw_entry);
if (retval < 0) {
printk(KERN_ERR "metronomefb: couldn't process waveform\n");
- goto err_ld_wfm;
+ goto err_dma_free;
}
- release_firmware(fw_entry);
- retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq,
- IRQF_DISABLED, "Metronome", info);
- if (retval) {
- dev_err(&dev->dev, "request_irq failed: %d\n", retval);
- goto err_ld_wfm;
- }
- set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
+ if (board->setup_irq(info))
+ goto err_dma_free;
retval = metronome_init_regs(par);
if (retval < 0)
@@ -913,9 +718,7 @@ err_cmap:
err_fb_rel:
framebuffer_release(info);
err_free_irq:
- free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
-err_ld_wfm:
- release_firmware(fw_entry);
+ board->free_irq(info);
err_dma_free:
dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
par->metromem_dma);
@@ -923,6 +726,7 @@ err_csum_table:
vfree(par->csum_table);
err_vfree:
vfree(videomemory);
+ module_put(board->owner);
return retval;
}
@@ -939,7 +743,8 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
vfree(par->csum_table);
unregister_framebuffer(info);
vfree((void __force *)info->screen_base);
- free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
+ par->board->free_irq(info);
+ module_put(par->board->owner);
framebuffer_release(info);
}
return 0;
@@ -949,48 +754,21 @@ static struct platform_driver metronomefb_driver = {
.probe = metronomefb_probe,
.remove = metronomefb_remove,
.driver = {
+ .owner = THIS_MODULE,
.name = "metronomefb",
},
};
-static struct platform_device *metronomefb_device;
-
static int __init metronomefb_init(void)
{
- int ret;
-
- if (!metronomefb_enable) {
- printk(KERN_ERR
- "Use metronomefb_enable to enable the device\n");
- return -ENXIO;
- }
-
- ret = platform_driver_register(&metronomefb_driver);
- if (!ret) {
- metronomefb_device = platform_device_alloc("metronomefb", 0);
- if (metronomefb_device)
- ret = platform_device_add(metronomefb_device);
- else
- ret = -ENOMEM;
-
- if (ret) {
- platform_device_put(metronomefb_device);
- platform_driver_unregister(&metronomefb_driver);
- }
- }
- return ret;
-
+ return platform_driver_register(&metronomefb_driver);
}
static void __exit metronomefb_exit(void)
{
- platform_device_unregister(metronomefb_device);
platform_driver_unregister(&metronomefb_driver);
}
-module_param(metronomefb_enable, uint, 0);
-MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome");
-
module_init(metronomefb_init);
module_exit(metronomefb_exit);
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 08d072552233..473562191586 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -22,7 +22,7 @@
((v).xres == (x) && (v).yres == (y))
#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __FUNCTION__ , ## args)
+#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __func__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
@@ -522,7 +522,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
- u32 best, diff;
+ u32 best, diff, tdiff;
for (i = namelen-1; i >= 0; i--) {
switch (name[i]) {
@@ -651,19 +651,27 @@ done:
return (refresh_specified) ? 2 : 1;
}
- diff = xres + yres;
+ diff = 2 * (xres + yres);
best = -1;
DPRINTK("Trying best-fit modes\n");
for (i = 0; i < dbsize; i++) {
- if (xres <= db[i].xres && yres <= db[i].yres) {
DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres);
if (!fb_try_mode(var, info, &db[i], bpp)) {
- if (diff > (db[i].xres - xres) + (db[i].yres - yres)) {
- diff = (db[i].xres - xres) + (db[i].yres - yres);
- best = i;
- }
+ tdiff = abs(db[i].xres - xres) +
+ abs(db[i].yres - yres);
+
+ /*
+ * Penalize modes with resolutions smaller
+ * than requested.
+ */
+ if (xres > db[i].xres || yres > db[i].yres)
+ tdiff += xres + yres;
+
+ if (diff > tdiff) {
+ diff = tdiff;
+ best = i;
+ }
}
- }
}
if (best != -1) {
fb_try_mode(var, info, &db[best], bpp);
diff --git a/drivers/video/n411.c b/drivers/video/n411.c
new file mode 100644
index 000000000000..935830fea7b6
--- /dev/null
+++ b/drivers/video/n411.c
@@ -0,0 +1,202 @@
+/*
+ * linux/drivers/video/n411.c -- Platform device for N411 EPD kit
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * 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.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This driver is written to be used with the Hecuba display controller
+ * board, and tested with the EInk 800x600 display in 1 bit mode.
+ * The interface between Hecuba and the host is TTL based GPIO. The
+ * GPIO requirements are 8 writable data lines and 6 lines for control.
+ * Only 4 of the controls are actually used here but 6 for future use.
+ * The driver requires the IO addresses for data and control GPIO at
+ * load time. It is also possible to use this display with a standard
+ * PC parallel port.
+ *
+ * General notes:
+ * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+
+#include <video/hecubafb.h>
+
+static unsigned long dio_addr;
+static unsigned long cio_addr;
+static unsigned long c2io_addr;
+static unsigned long splashval;
+static unsigned int nosplash;
+static unsigned char ctl;
+
+static void n411_set_ctl(struct hecubafb_par *par, unsigned char bit, unsigned
+ char state)
+{
+ switch (bit) {
+ case HCB_CD_BIT:
+ if (state)
+ ctl &= ~(HCB_CD_BIT);
+ else
+ ctl |= HCB_CD_BIT;
+ break;
+ case HCB_DS_BIT:
+ if (state)
+ ctl &= ~(HCB_DS_BIT);
+ else
+ ctl |= HCB_DS_BIT;
+ break;
+ }
+ outb(ctl, cio_addr);
+}
+
+static unsigned char n411_get_ctl(struct hecubafb_par *par)
+{
+ return inb(c2io_addr);
+}
+
+static void n411_set_data(struct hecubafb_par *par, unsigned char value)
+{
+ outb(value, dio_addr);
+}
+
+static void n411_wait_for_ack(struct hecubafb_par *par, int clear)
+{
+ int timeout;
+ unsigned char tmp;
+
+ timeout = 500;
+ do {
+ tmp = n411_get_ctl(par);
+ if ((tmp & HCB_ACK_BIT) && (!clear))
+ return;
+ else if (!(tmp & HCB_ACK_BIT) && (clear))
+ return;
+ udelay(1);
+ } while (timeout--);
+ printk(KERN_ERR "timed out waiting for ack\n");
+}
+
+static int n411_init_control(struct hecubafb_par *par)
+{
+ unsigned char tmp;
+ /* for init, we want the following setup to be set:
+ WUP = lo
+ ACK = hi
+ DS = hi
+ RW = hi
+ CD = lo
+ */
+
+ /* write WUP to lo, DS to hi, RW to hi, CD to lo */
+ ctl = HCB_WUP_BIT | HCB_RW_BIT | HCB_CD_BIT ;
+ n411_set_ctl(par, HCB_DS_BIT, 1);
+
+ /* check ACK is not lo */
+ tmp = n411_get_ctl(par);
+ if (tmp & HCB_ACK_BIT) {
+ printk(KERN_ERR "Fail because ACK is already low\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+
+static int n411_init_board(struct hecubafb_par *par)
+{
+ int retval;
+
+ retval = n411_init_control(par);
+ if (retval)
+ return retval;
+
+ par->send_command(par, APOLLO_INIT_DISPLAY);
+ par->send_data(par, 0x81);
+
+ /* have to wait while display resets */
+ udelay(1000);
+
+ /* if we were told to splash the screen, we just clear it */
+ if (!nosplash) {
+ par->send_command(par, APOLLO_ERASE_DISPLAY);
+ par->send_data(par, splashval);
+ }
+
+ return 0;
+}
+
+static struct hecuba_board n411_board = {
+ .owner = THIS_MODULE,
+ .init = n411_init_board,
+ .set_ctl = n411_set_ctl,
+ .set_data = n411_set_data,
+ .wait_for_ack = n411_wait_for_ack,
+};
+
+static struct platform_device *n411_device;
+static int __init n411_init(void)
+{
+ int ret;
+ if (!dio_addr || !cio_addr || !c2io_addr) {
+ printk(KERN_WARNING "no IO addresses supplied\n");
+ return -EINVAL;
+ }
+
+ /* request our platform independent driver */
+ request_module("hecubafb");
+
+ n411_device = platform_device_alloc("hecubafb", -1);
+ if (!n411_device)
+ return -ENOMEM;
+
+ platform_device_add_data(n411_device, &n411_board, sizeof(n411_board));
+
+ /* this _add binds hecubafb to n411. hecubafb refcounts n411 */
+ ret = platform_device_add(n411_device);
+
+ if (ret)
+ platform_device_put(n411_device);
+
+ return ret;
+
+}
+
+static void __exit n411_exit(void)
+{
+ platform_device_unregister(n411_device);
+}
+
+module_init(n411_init);
+module_exit(n411_exit);
+
+module_param(nosplash, uint, 0);
+MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
+module_param(dio_addr, ulong, 0);
+MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
+module_param(cio_addr, ulong, 0);
+MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
+module_param(c2io_addr, ulong, 0);
+MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
+module_param(splashval, ulong, 0);
+MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white");
+
+MODULE_DESCRIPTION("board driver for n411 hecuba/apollo epd kit");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index d1a10549f543..ed20a9871b33 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -129,7 +129,7 @@ typedef struct {
int nvclk_khz;
char mem_page_miss;
char mem_latency;
- int memory_type;
+ u32 memory_type;
int memory_width;
char enable_video;
char gr_during_vid;
@@ -719,7 +719,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk,
memctrl >>= 16;
if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
- int dimm[3];
+ u32 dimm[3];
dev = pci_get_bus_and_slot(0, 2);
pci_read_config_dword(dev, 0x40, &dimm[0]);
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
index 82579d3a9970..d9627b57eb4d 100644
--- a/drivers/video/nvidia/nv_setup.c
+++ b/drivers/video/nvidia/nv_setup.c
@@ -265,12 +265,12 @@ static void nv10GetConfig(struct nvidia_par *par)
dev = pci_get_bus_and_slot(0, 1);
if ((par->Chipset & 0xffff) == 0x01a0) {
- int amt = 0;
+ u32 amt;
pci_read_config_dword(dev, 0x7c, &amt);
par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
} else if ((par->Chipset & 0xffff) == 0x01f0) {
- int amt = 0;
+ u32 amt;
pci_read_config_dword(dev, 0x84, &amt);
par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 596652d2831f..9dbb5a5a267b 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -43,14 +43,14 @@
#define NVTRACE if (0) printk
#endif
-#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__)
-#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__)
+#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__)
+#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__)
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define assert(expr) \
if (!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n",\
- #expr,__FILE__,__FUNCTION__,__LINE__); \
+ #expr,__FILE__,__func__,__LINE__); \
BUG(); \
}
#else
@@ -1559,7 +1559,6 @@ static int __devinit nvidiafb_init(void)
module_init(nvidiafb_init);
-#ifdef MODULE
static void __exit nvidiafb_exit(void)
{
pci_unregister_driver(&nvidiafb_driver);
@@ -1615,5 +1614,3 @@ MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
MODULE_AUTHOR("Antonino Daplas");
MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset");
MODULE_LICENSE("GPL");
-#endif /* MODULE */
-
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 452433d46973..d7b3dcc0dc43 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -248,7 +248,7 @@ static void __iomem *offb_map_reg(struct device_node *np, int index,
static void __init offb_init_fb(const char *name, const char *full_name,
int width, int height, int depth,
int pitch, unsigned long address,
- struct device_node *dp)
+ int foreign_endian, struct device_node *dp)
{
unsigned long res_size = pitch * height * (depth + 7) / 8;
struct offb_par *par = &default_par;
@@ -397,7 +397,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
info->screen_base = ioremap(address, fix->smem_len);
info->par = par;
info->pseudo_palette = (void *) (info + 1);
- info->flags = FBINFO_DEFAULT;
+ info->flags = FBINFO_DEFAULT | foreign_endian;
fb_alloc_cmap(&info->cmap, 256, 0);
@@ -424,6 +424,15 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
u64 rstart, address = OF_BAD_ADDR;
const u32 *pp, *addrp, *up;
u64 asize;
+ int foreign_endian = 0;
+
+#ifdef __BIG_ENDIAN
+ if (of_get_property(dp, "little-endian", NULL))
+ foreign_endian = FBINFO_FOREIGN_ENDIAN;
+#else
+ if (of_get_property(dp, "big-endian", NULL))
+ foreign_endian = FBINFO_FOREIGN_ENDIAN;
+#endif
pp = of_get_property(dp, "linux,bootx-depth", &len);
if (pp == NULL)
@@ -509,7 +518,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
offb_init_fb(no_real_node ? "bootx" : dp->name,
no_real_node ? "display" : dp->full_name,
width, height, depth, pitch, address,
- no_real_node ? NULL : dp);
+ foreign_endian, no_real_node ? NULL : dp);
}
}
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 58496061142d..c95874fe9076 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -310,7 +310,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
dev_set_drvdata(&op->dev, info);
- printk("%s: p9100 at %lx:%lx\n",
+ printk(KERN_INFO "%s: p9100 at %lx:%lx\n",
dp->full_name,
par->which_io, par->physbase);
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 30181b593829..3f1ca2adda3d 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -56,7 +56,7 @@
#undef PM2FB_MASTER_DEBUG
#ifdef PM2FB_MASTER_DEBUG
#define DPRINTK(a, b...) \
- printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
+ printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b)
#else
#define DPRINTK(a, b...)
#endif
@@ -67,7 +67,7 @@
* Driver data
*/
static int hwcursor = 1;
-static char *mode __devinitdata;
+static char *mode_option __devinitdata;
/*
* The XFree GLINT driver will (I think to implement hardware cursor
@@ -1680,17 +1680,19 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
info->pixmap.scan_align = 1;
}
- if (!mode)
- mode = "640x480@60";
+ if (!mode_option)
+ mode_option = "640x480@60";
- err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8);
+ err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
if (!err || err == 4)
info->var = pm2fb_var;
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0)
goto err_exit_both;
- if (register_framebuffer(info) < 0)
+ retval = register_framebuffer(info);
+ if (retval < 0)
goto err_exit_all;
printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n",
@@ -1797,7 +1799,7 @@ static int __init pm2fb_setup(char *options)
else if (!strncmp(this_opt, "noaccel", 7))
noaccel = 1;
else
- mode = this_opt;
+ mode_option = this_opt;
}
return 0;
}
@@ -1833,8 +1835,10 @@ static void __exit pm2fb_exit(void)
#ifdef MODULE
module_exit(pm2fb_exit);
-module_param(mode, charp, 0);
-MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
+module_param_named(mode, mode_option, charp, 0);
+MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
module_param(lowhsync, bool, 0);
MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
module_param(lowvsync, bool, 0);
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 5dba8cdd0517..68089d1456c2 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -45,7 +45,7 @@
#undef PM3FB_MASTER_DEBUG
#ifdef PM3FB_MASTER_DEBUG
#define DPRINTK(a, b...) \
- printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+ printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b)
#else
#define DPRINTK(a, b...)
#endif
@@ -1571,6 +1571,8 @@ module_exit(pm3fb_exit);
#endif
module_init(pm3fb_init);
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
module_param(noaccel, bool, 0);
MODULE_PARM_DESC(noaccel, "Disable acceleration");
module_param(hwcursor, int, 0644);
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 5c47968e7f21..d94c57ffbdb1 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -56,10 +56,6 @@
#include "rivafb.h"
#include "nvreg.h"
-#ifndef CONFIG_PCI /* sanity check */
-#error This driver requires PCI support.
-#endif
-
/* version number of this driver */
#define RIVAFB_VERSION "0.9.5b"
@@ -74,14 +70,14 @@
#define NVTRACE if(0) printk
#endif
-#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__)
-#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__)
+#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__)
+#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__)
#ifdef CONFIG_FB_RIVA_DEBUG
#define assert(expr) \
if(!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n",\
- #expr,__FILE__,__FUNCTION__,__LINE__); \
+ #expr,__FILE__,__func__,__LINE__); \
BUG(); \
}
#else
@@ -2213,14 +2209,12 @@ static int __devinit rivafb_init(void)
module_init(rivafb_init);
-#ifdef MODULE
static void __exit rivafb_exit(void)
{
pci_unregister_driver(&rivafb_driver);
}
module_exit(rivafb_exit);
-#endif /* MODULE */
module_param(noaccel, bool, 0);
MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c
index a11026812d1b..f3694cf17e58 100644
--- a/drivers/video/riva/nv_driver.c
+++ b/drivers/video/riva/nv_driver.c
@@ -41,11 +41,6 @@
#include "rivafb.h"
#include "nvreg.h"
-
-#ifndef CONFIG_PCI /* sanity check */
-#error This driver requires PCI support.
-#endif
-
#define PFX "rivafb: "
static inline unsigned char MISCin(struct riva_par *par)
@@ -163,7 +158,7 @@ unsigned long riva_get_memlen(struct riva_par *par)
unsigned long memlen = 0;
unsigned int chipset = par->Chipset;
struct pci_dev* dev;
- int amt;
+ u32 amt;
switch (chip->Architecture) {
case NV_ARCH_03:
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
index 13307703a9f0..78fdbf5178d7 100644
--- a/drivers/video/riva/riva_hw.c
+++ b/drivers/video/riva/riva_hw.c
@@ -231,7 +231,7 @@ typedef struct {
int nvclk_khz;
char mem_page_miss;
char mem_latency;
- int memory_type;
+ u32 memory_type;
int memory_width;
char enable_video;
char gr_during_vid;
@@ -2107,7 +2107,7 @@ static void nv10GetConfig
)
{
struct pci_dev* dev;
- int amt;
+ u32 amt;
#ifdef __BIG_ENDIAN
/* turn on big endian register access */
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 71fa6edb5c47..13b38cbbe4cf 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -430,9 +430,9 @@ static void s3c2410fb_activate_var(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;
- dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
- dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
- dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
+ dprintk("%s: var->xres = %d\n", __func__, var->xres);
+ dprintk("%s: var->yres = %d\n", __func__, var->yres);
+ dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel);
if (type == S3C2410_LCDCON1_TFT) {
s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 7d53bc23b9c7..2972f112dbed 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -132,10 +132,10 @@ static const struct svga_timing_regs s3_timing_regs = {
/* Module parameters */
-static char *mode = "640x480-8@60";
+static char *mode_option __devinitdata = "640x480-8@60";
#ifdef CONFIG_MTRR
-static int mtrr = 1;
+static int mtrr __devinitdata = 1;
#endif
static int fasttext = 1;
@@ -145,8 +145,10 @@ MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge");
-module_param(mode, charp, 0444);
-MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+module_param(mode_option, charp, 0444);
+MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
+module_param_named(mode, mode_option, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)");
#ifdef CONFIG_MTRR
module_param(mtrr, int, 0444);
@@ -886,7 +888,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
}
/* Allocate and fill driver data structure */
- info = framebuffer_alloc(sizeof(struct s3fb_info), NULL);
+ info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev));
if (!info) {
dev_err(&(dev->dev), "cannot allocate memory\n");
return -ENOMEM;
@@ -901,13 +903,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
/* Prepare PCI device */
rc = pci_enable_device(dev);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot enable PCI device\n");
+ dev_err(info->dev, "cannot enable PCI device\n");
goto err_enable_device;
}
rc = pci_request_regions(dev, "s3fb");
if (rc < 0) {
- dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ dev_err(info->dev, "cannot reserve framebuffer region\n");
goto err_request_regions;
}
@@ -919,7 +921,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
info->screen_base = pci_iomap(dev, 0, 0);
if (! info->screen_base) {
rc = -ENOMEM;
- dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ dev_err(info->dev, "iomap for framebuffer failed\n");
goto err_iomap;
}
@@ -960,22 +962,22 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
info->pseudo_palette = (void*) (par->pseudo_palette);
/* Prepare startup mode */
- rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
if (! ((rc == 1) || (rc == 2))) {
rc = -EINVAL;
- dev_err(&(dev->dev), "mode %s not found\n", mode);
+ dev_err(info->dev, "mode %s not found\n", mode_option);
goto err_find_mode;
}
rc = fb_alloc_cmap(&info->cmap, 256, 0);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot allocate colormap\n");
+ dev_err(info->dev, "cannot allocate colormap\n");
goto err_alloc_cmap;
}
rc = register_framebuffer(info);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot register framebuffer\n");
+ dev_err(info->dev, "cannot register framebuffer\n");
goto err_reg_fb;
}
@@ -1051,7 +1053,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
struct fb_info *info = pci_get_drvdata(dev);
struct s3fb_info *par = info->par;
- dev_info(&(dev->dev), "suspend\n");
+ dev_info(info->dev, "suspend\n");
acquire_console_sem();
mutex_lock(&(par->open_lock));
@@ -1083,7 +1085,7 @@ static int s3_pci_resume(struct pci_dev* dev)
struct s3fb_info *par = info->par;
int err;
- dev_info(&(dev->dev), "resume\n");
+ dev_info(info->dev, "resume\n");
acquire_console_sem();
mutex_lock(&(par->open_lock));
@@ -1100,7 +1102,7 @@ static int s3_pci_resume(struct pci_dev* dev)
if (err) {
mutex_unlock(&(par->open_lock));
release_console_sem();
- dev_err(&(dev->dev), "error %d enabling device for resume\n", err);
+ dev_err(info->dev, "error %d enabling device for resume\n", err);
return err;
}
pci_set_master(dev);
@@ -1168,7 +1170,7 @@ static int __init s3fb_setup(char *options)
else if (!strncmp(opt, "fasttext:", 9))
fasttext = simple_strtoul(opt + 9, NULL, 0);
else
- mode = opt;
+ mode_option = opt;
}
return 0;
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 48066ef3af05..f465b27ed860 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -132,7 +132,7 @@ struct sa1100fb_info {
* Debug macros
*/
#if DEBUG
-# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 35c1ce62b216..783d4adffb93 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -140,7 +140,7 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
chan->adapter.id = I2C_HW_B_SAVAGE;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pcidev->dev;
- chan->algo.udelay = 40;
+ chan->algo.udelay = 10;
chan->algo.timeout = 20;
chan->algo.data = chan;
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index 9b05da6268f7..a14e82211037 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -55,7 +55,7 @@
#undef SISFBDEBUG
#ifdef SISFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
#define TWDEBUG(x) printk(KERN_INFO x "\n");
#else
#define DPRINTK(fmt, args...)
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 97784f9c184d..5b11a00f49bc 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1006,7 +1006,7 @@ static int sst_set_pll_att_ti(struct fb_info *info,
break;
default:
dprintk("%s: wrong clock code '%d'\n",
- __FUNCTION__, clock);
+ __func__, clock);
return 0;
}
udelay(300);
@@ -1048,7 +1048,7 @@ static int sst_set_pll_ics(struct fb_info *info,
break;
default:
dprintk("%s: wrong clock code '%d'\n",
- __FUNCTION__, clock);
+ __func__, clock);
return 0;
}
udelay(300);
@@ -1079,7 +1079,7 @@ static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp)
sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP);
break;
default:
- dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
+ dprintk("%s: bad depth '%u'\n", __func__, bpp);
break;
}
}
@@ -1093,7 +1093,7 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP);
break;
default:
- dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
+ dprintk("%s: bad depth '%u'\n", __func__, bpp);
break;
}
}
@@ -1133,7 +1133,7 @@ static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *
}
if (!ret)
return 0;
- f_dprintk("%s found %s\n", __FUNCTION__, dacs[i].name);
+ f_dprintk("%s found %s\n", __func__, dacs[i].name);
par->dac_sw = dacs[i];
return 1;
}
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index f98be301140c..598d35eff935 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -164,11 +164,11 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
# define DEBUG_ON() debug_on=1
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
- __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
+ __func__, reg, value, READ_BYTE(fb,reg)); \
gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
- __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
+ __func__, reg, value, READ_WORD(fb,reg)); \
gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */
diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c
index 37af10ab8f52..a352d5f46bbf 100644
--- a/drivers/video/syscopyarea.c
+++ b/drivers/video/syscopyarea.c
@@ -26,15 +26,15 @@
*/
static void
-bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
- int src_idx, int bits, unsigned n)
+bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
+ const unsigned long *src, int src_idx, int bits, unsigned n)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
int left, right;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (!shift) {
/* Same alignment for source and dest */
@@ -167,8 +167,8 @@ bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
*/
static void
-bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
- int src_idx, int bits, unsigned n)
+bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
+ const unsigned long *src, int src_idx, int bits, unsigned n)
{
unsigned long first, last;
int shift;
@@ -186,8 +186,8 @@ bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
shift = dst_idx-src_idx;
- first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
- last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
+ first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
+ last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
if (!shift) {
/* Same alignment for source and dest */
@@ -353,7 +353,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
- bitcpy_rev(dst, dst_idx, src, src_idx, bits,
+ bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel);
}
} else {
@@ -362,7 +362,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
- bitcpy(dst, dst_idx, src, src_idx, bits,
+ bitcpy(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel);
dst_idx += bits_per_line;
src_idx += bits_per_line;
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
index a261e9e6a675..f94d6b6e29ee 100644
--- a/drivers/video/sysfillrect.c
+++ b/drivers/video/sysfillrect.c
@@ -22,16 +22,16 @@
*/
static void
-bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
- unsigned n, int bits)
+bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
+ unsigned long pat, unsigned n, int bits)
{
unsigned long first, last;
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) {
/* Single word */
@@ -78,16 +78,16 @@ bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
*/
static void
-bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
- int left, int right, unsigned n, int bits)
+bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
+ unsigned long pat, int left, int right, unsigned n, int bits)
{
unsigned long first, last;
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) {
/* Single word */
@@ -132,8 +132,8 @@ bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
* Aligned pattern invert using 32/64-bit memory accesses
*/
static void
-bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
- unsigned n, int bits)
+bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
+ unsigned long pat, unsigned n, int bits)
{
unsigned long val = pat;
unsigned long first, last;
@@ -141,8 +141,8 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) {
/* Single word */
@@ -188,16 +188,17 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
*/
static void
-bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
- int left, int right, unsigned n, int bits)
+bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
+ unsigned long pat, int left, int right, unsigned n,
+ int bits)
{
unsigned long first, last;
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
if (dst_idx+n <= bits) {
/* Single word */
@@ -267,9 +268,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
if (p->fbops->fb_sync)
p->fbops->fb_sync(p);
if (!left) {
- void (*fill_op32)(unsigned long *dst, int dst_idx,
- unsigned long pat, unsigned n, int bits) =
- NULL;
+ void (*fill_op32)(struct fb_info *p, unsigned long *dst,
+ int dst_idx, unsigned long pat, unsigned n,
+ int bits) = NULL;
switch (rect->rop) {
case ROP_XOR:
@@ -287,16 +288,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bits - 1);
- fill_op32(dst, dst_idx, pat, width*bpp, bits);
+ fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
dst_idx += p->fix.line_length*8;
}
} else {
int right;
int r;
int rot = (left-dst_idx) % bpp;
- void (*fill_op)(unsigned long *dst, int dst_idx,
- unsigned long pat, int left, int right,
- unsigned n, int bits) = NULL;
+ void (*fill_op)(struct fb_info *p, unsigned long *dst,
+ int dst_idx, unsigned long pat, int left,
+ int right, unsigned n, int bits) = NULL;
/* rotate pattern to correct start position */
pat = pat << rot | pat >> (bpp-rot);
@@ -318,7 +319,7 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bits - 1);
- fill_op(dst, dst_idx, pat, left, right,
+ fill_op(p, dst, dst_idx, pat, left, right,
width*bpp, bits);
r = (p->fix.line_length*8) % bpp;
pat = pat << (bpp-r) | pat >> r;
diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c
index bd7e7e9d155f..186c6f607be2 100644
--- a/drivers/video/sysimgblt.c
+++ b/drivers/video/sysimgblt.c
@@ -18,35 +18,31 @@
#define DEBUG
#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
#else
#define DPRINTK(fmt, args...)
#endif
-static const u32 cfb_tab8[] = {
-#if defined(__BIG_ENDIAN)
+static const u32 cfb_tab8_be[] = {
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
0xffff0000,0xffff00ff,0xffffff00,0xffffffff
-#elif defined(__LITTLE_ENDIAN)
+};
+
+static const u32 cfb_tab8_le[] = {
0x00000000,0xff000000,0x00ff0000,0xffff0000,
0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
-#else
-#error FIXME: No endianness??
-#endif
};
-static const u32 cfb_tab16[] = {
-#if defined(__BIG_ENDIAN)
+static const u32 cfb_tab16_be[] = {
0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
-#elif defined(__LITTLE_ENDIAN)
+};
+
+static const u32 cfb_tab16_le[] = {
0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
-#else
-#error FIXME: No endianness??
-#endif
};
static const u32 cfb_tab32[] = {
@@ -72,7 +68,7 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p,
val = 0;
if (start_index) {
- u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,
+ u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
start_index));
val = *dst & start_mask;
shift = start_index;
@@ -83,20 +79,20 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p,
color = palette[*src];
else
color = *src;
- color <<= FB_LEFT_POS(bpp);
- val |= FB_SHIFT_HIGH(color, shift);
+ color <<= FB_LEFT_POS(p, bpp);
+ val |= FB_SHIFT_HIGH(p, color, shift);
if (shift >= null_bits) {
*dst++ = val;
val = (shift == null_bits) ? 0 :
- FB_SHIFT_LOW(color, 32 - shift);
+ FB_SHIFT_LOW(p, color, 32 - shift);
}
shift += bpp;
shift &= (32 - 1);
src++;
}
if (shift) {
- u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+ u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
*dst &= end_mask;
*dst |= val;
@@ -125,8 +121,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
u32 i, j, l;
dst2 = dst1;
- fgcolor <<= FB_LEFT_POS(bpp);
- bgcolor <<= FB_LEFT_POS(bpp);
+ fgcolor <<= FB_LEFT_POS(p, bpp);
+ bgcolor <<= FB_LEFT_POS(p, bpp);
for (i = image->height; i--; ) {
shift = val = 0;
@@ -137,7 +133,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
/* write leading bits */
if (start_index) {
- u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
+ u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
+ start_index));
val = *dst & start_mask;
shift = start_index;
}
@@ -145,13 +142,13 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
while (j--) {
l--;
color = (*s & (1 << l)) ? fgcolor : bgcolor;
- val |= FB_SHIFT_HIGH(color, shift);
+ val |= FB_SHIFT_HIGH(p, color, shift);
/* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) {
*dst++ = val;
val = (shift == null_bits) ? 0 :
- FB_SHIFT_LOW(color,32 - shift);
+ FB_SHIFT_LOW(p, color, 32 - shift);
}
shift += bpp;
shift &= (32 - 1);
@@ -160,7 +157,7 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
/* write trailing bits */
if (shift) {
- u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+ u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
*dst &= end_mask;
*dst |= val;
@@ -199,10 +196,10 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
switch (bpp) {
case 8:
- tab = cfb_tab8;
+ tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
break;
case 16:
- tab = cfb_tab16;
+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
break;
case 32:
default:
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index e5a9ddb3c8be..a71774305772 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -419,7 +419,7 @@ static int __devinit tcx_init_one(struct of_device *op)
par->mmap_map[6].size = SBUS_MMAP_EMPTY;
}
- par->physbase = 0;
+ par->physbase = op->resource[0].start;
par->which_io = op->resource[0].flags & IORESOURCE_BITS;
for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
@@ -470,10 +470,10 @@ static int __devinit tcx_init_one(struct of_device *op)
dev_set_drvdata(&op->dev, info);
- printk("%s: TCX at %lx:%lx, %s\n",
+ printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n",
dp->full_name,
par->which_io,
- op->resource[0].start,
+ par->physbase,
par->lowdepth ? "8-bit only" : "24-bit depth");
return 0;
@@ -527,7 +527,7 @@ static struct of_platform_driver tcx_driver = {
.remove = __devexit_p(tcx_remove),
};
-int __init tcx_init(void)
+static int __init tcx_init(void)
{
if (fb_get_options("tcxfb", NULL))
return -ENODEV;
@@ -535,7 +535,7 @@ int __init tcx_init(void)
return of_register_driver(&tcx_driver, &of_bus_type);
}
-void __exit tcx_exit(void)
+static void __exit tcx_exit(void)
{
of_unregister_driver(&tcx_driver);
}
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 71e179ea5f95..ea9f19d25597 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -70,7 +70,7 @@
#include <video/tdfx.h>
-#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b)
+#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b)
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 0a4e07d43d2d..bd54cd0de39a 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -58,7 +58,7 @@ static int displaytype;
/* defaults which are normally overriden by user values */
/* video mode */
-static char *mode = "640x480";
+static char *mode_option __devinitdata = "640x480";
static int bpp = 8;
static int noaccel;
@@ -73,7 +73,10 @@ static int memsize;
static int memdiff;
static int nativex;
-module_param(mode, charp, 0);
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
+module_param_named(mode, mode_option, charp, 0);
+MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
module_param(bpp, int, 0);
module_param(center, int, 0);
module_param(stretch, int, 0);
@@ -1297,7 +1300,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev,
#endif
fb_info.pseudo_palette = pseudo_pal;
- if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) {
+ if (!fb_find_mode(&default_var, &fb_info,
+ mode_option, NULL, 0, NULL, bpp)) {
err = -EINVAL;
goto out_unmap2;
}
@@ -1385,7 +1389,7 @@ static struct pci_driver tridentfb_pci_driver = {
* video=trident:800x600,bpp=16,noaccel
*/
#ifndef MODULE
-static int tridentfb_setup(char *options)
+static int __init tridentfb_setup(char *options)
{
char *opt;
if (!options || !*options)
@@ -1412,7 +1416,7 @@ static int tridentfb_setup(char *options)
else if (!strncmp(opt, "nativex=", 8))
nativex = simple_strtoul(opt + 8, NULL, 0);
else
- mode = opt;
+ mode_option = opt;
}
return 0;
}
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 93361656316c..cdbb56edb6cb 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -181,7 +181,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
/* If all slots are taken -- bail out. */
if (uvfb_tasks[seq]) {
mutex_unlock(&uvfb_lock);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
/* Save a pointer to the kernel part of the task struct. */
@@ -205,7 +206,6 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
err = cn_netlink_send(m, 0, gfp_any());
}
}
- kfree(m);
if (!err && !(task->t.flags & TF_EXIT))
err = !wait_for_completion_timeout(task->done,
@@ -218,7 +218,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
seq++;
if (seq >= UVESAFB_TASKS_MAX)
seq = 0;
-
+out:
+ kfree(m);
return err;
}
@@ -885,7 +886,7 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
}
/* fb_find_mode() failed */
- if (i == 0 || i >= 3) {
+ if (i == 0) {
info->var.xres = 640;
info->var.yres = 480;
mode = (struct fb_videomode *)
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index 2aa71eb67c2b..c18f1884b550 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -112,8 +112,9 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
/*
* It seems like __get_free_pages only ups the usage count
- * of the first page. This doesn't work with nopage mapping, so
- * up the usage count once more.
+ * of the first page. This doesn't work with fault mapping, so
+ * up the usage count once more (XXX: should use split_page or
+ * compound page).
*/
memset((void *)va->logical, 0x00, va->size);
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index 4c3a63308df1..536ab11623f0 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -100,7 +100,7 @@ static struct svga_timing_regs vt8623_timing_regs = {
/* Module parameters */
-static char *mode = "640x480-8@60";
+static char *mode_option = "640x480-8@60";
#ifdef CONFIG_MTRR
static int mtrr = 1;
@@ -110,8 +110,10 @@ MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
-module_param(mode, charp, 0644);
-MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+module_param(mode_option, charp, 0644);
+MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
+module_param_named(mode, mode_option, charp, 0);
+MODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)");
#ifdef CONFIG_MTRR
module_param(mtrr, int, 0444);
@@ -434,6 +436,10 @@ static int vt8623fb_set_par(struct fb_info *info)
svga_wcrt_multi(vt8623_offset_regs, offset_value);
svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+ /* Clear H/V Skew */
+ svga_wcrt_mask(0x03, 0x00, 0x60);
+ svga_wcrt_mask(0x05, 0x00, 0x60);
+
if (info->var.vmode & FB_VMODE_DOUBLE)
svga_wcrt_mask(0x09, 0x80, 0x80);
else
@@ -655,7 +661,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
}
/* Allocate and fill driver data structure */
- info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL);
+ info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev));
if (! info) {
dev_err(&(dev->dev), "cannot allocate memory\n");
return -ENOMEM;
@@ -671,13 +677,13 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
rc = pci_enable_device(dev);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot enable PCI device\n");
+ dev_err(info->dev, "cannot enable PCI device\n");
goto err_enable_device;
}
rc = pci_request_regions(dev, "vt8623fb");
if (rc < 0) {
- dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ dev_err(info->dev, "cannot reserve framebuffer region\n");
goto err_request_regions;
}
@@ -690,14 +696,14 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
info->screen_base = pci_iomap(dev, 0, 0);
if (! info->screen_base) {
rc = -ENOMEM;
- dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ dev_err(info->dev, "iomap for framebuffer failed\n");
goto err_iomap_1;
}
par->mmio_base = pci_iomap(dev, 1, 0);
if (! par->mmio_base) {
rc = -ENOMEM;
- dev_err(&(dev->dev), "iomap for MMIO failed\n");
+ dev_err(info->dev, "iomap for MMIO failed\n");
goto err_iomap_2;
}
@@ -708,7 +714,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
info->screen_size = memsize1 << 20;
else {
- dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
+ dev_err(info->dev, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
info->screen_size = 16 << 20;
}
@@ -722,22 +728,22 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
/* Prepare startup mode */
- rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
if (! ((rc == 1) || (rc == 2))) {
rc = -EINVAL;
- dev_err(&(dev->dev), "mode %s not found\n", mode);
+ dev_err(info->dev, "mode %s not found\n", mode_option);
goto err_find_mode;
}
rc = fb_alloc_cmap(&info->cmap, 256, 0);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot allocate colormap\n");
+ dev_err(info->dev, "cannot allocate colormap\n");
goto err_alloc_cmap;
}
rc = register_framebuffer(info);
if (rc < 0) {
- dev_err(&(dev->dev), "cannot register framebugger\n");
+ dev_err(info->dev, "cannot register framebugger\n");
goto err_reg_fb;
}
@@ -811,7 +817,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
struct fb_info *info = pci_get_drvdata(dev);
struct vt8623fb_info *par = info->par;
- dev_info(&(dev->dev), "suspend\n");
+ dev_info(info->dev, "suspend\n");
acquire_console_sem();
mutex_lock(&(par->open_lock));
@@ -842,7 +848,7 @@ static int vt8623_pci_resume(struct pci_dev* dev)
struct fb_info *info = pci_get_drvdata(dev);
struct vt8623fb_info *par = info->par;
- dev_info(&(dev->dev), "resume\n");
+ dev_info(info->dev, "resume\n");
acquire_console_sem();
mutex_lock(&(par->open_lock));
@@ -913,7 +919,7 @@ static int __init vt8623fb_init(void)
return -ENODEV;
if (option && *option)
- mode = option;
+ mode_option = option;
#endif
pr_debug("vt8623fb: initializing\n");
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 003c49a490eb..30469bf906e5 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -765,8 +765,10 @@ int __init w100fb_probe(struct platform_device *pdev)
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
return 0;
out:
- fb_dealloc_cmap(&info->cmap);
- kfree(info->pseudo_palette);
+ if (info) {
+ fb_dealloc_cmap(&info->cmap);
+ kfree(info->pseudo_palette);
+ }
if (remapped_fbuf != NULL)
iounmap(remapped_fbuf);
if (remapped_regs != NULL)
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
new file mode 100644
index 000000000000..619a6f8d65a2
--- /dev/null
+++ b/drivers/video/xen-fbfront.c
@@ -0,0 +1,550 @@
+/*
+ * Xen para-virtual frame buffer device
+ *
+ * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ * Based on linux/drivers/video/q40fb.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+/*
+ * TODO:
+ *
+ * Switch to grant tables when they become capable of dealing with the
+ * frame buffer.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/interface/io/protocols.h>
+#include <xen/xenbus.h>
+
+struct xenfb_info {
+ unsigned char *fb;
+ struct fb_info *fb_info;
+ int x1, y1, x2, y2; /* dirty rectangle,
+ protected by dirty_lock */
+ spinlock_t dirty_lock;
+ int nr_pages;
+ int irq;
+ struct xenfb_page *page;
+ unsigned long *mfns;
+ int update_wanted; /* XENFB_TYPE_UPDATE wanted */
+
+ struct xenbus_device *xbdev;
+};
+
+static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
+
+static int xenfb_remove(struct xenbus_device *);
+static void xenfb_init_shared_page(struct xenfb_info *);
+static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
+static void xenfb_disconnect_backend(struct xenfb_info *);
+
+static void xenfb_do_update(struct xenfb_info *info,
+ int x, int y, int w, int h)
+{
+ union xenfb_out_event event;
+ u32 prod;
+
+ event.type = XENFB_TYPE_UPDATE;
+ event.update.x = x;
+ event.update.y = y;
+ event.update.width = w;
+ event.update.height = h;
+
+ prod = info->page->out_prod;
+ /* caller ensures !xenfb_queue_full() */
+ mb(); /* ensure ring space available */
+ XENFB_OUT_RING_REF(info->page, prod) = event;
+ wmb(); /* ensure ring contents visible */
+ info->page->out_prod = prod + 1;
+
+ notify_remote_via_irq(info->irq);
+}
+
+static int xenfb_queue_full(struct xenfb_info *info)
+{
+ u32 cons, prod;
+
+ prod = info->page->out_prod;
+ cons = info->page->out_cons;
+ return prod - cons == XENFB_OUT_RING_LEN;
+}
+
+static void xenfb_refresh(struct xenfb_info *info,
+ int x1, int y1, int w, int h)
+{
+ unsigned long flags;
+ int y2 = y1 + h - 1;
+ int x2 = x1 + w - 1;
+
+ if (!info->update_wanted)
+ return;
+
+ spin_lock_irqsave(&info->dirty_lock, flags);
+
+ /* Combine with dirty rectangle: */
+ if (info->y1 < y1)
+ y1 = info->y1;
+ if (info->y2 > y2)
+ y2 = info->y2;
+ if (info->x1 < x1)
+ x1 = info->x1;
+ if (info->x2 > x2)
+ x2 = info->x2;
+
+ if (xenfb_queue_full(info)) {
+ /* Can't send right now, stash it in the dirty rectangle */
+ info->x1 = x1;
+ info->x2 = x2;
+ info->y1 = y1;
+ info->y2 = y2;
+ spin_unlock_irqrestore(&info->dirty_lock, flags);
+ return;
+ }
+
+ /* Clear dirty rectangle: */
+ info->x1 = info->y1 = INT_MAX;
+ info->x2 = info->y2 = 0;
+
+ spin_unlock_irqrestore(&info->dirty_lock, flags);
+
+ if (x1 <= x2 && y1 <= y2)
+ xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+}
+
+static void xenfb_deferred_io(struct fb_info *fb_info,
+ struct list_head *pagelist)
+{
+ struct xenfb_info *info = fb_info->par;
+ struct page *page;
+ unsigned long beg, end;
+ int y1, y2, miny, maxy;
+
+ miny = INT_MAX;
+ maxy = 0;
+ list_for_each_entry(page, pagelist, lru) {
+ beg = page->index << PAGE_SHIFT;
+ end = beg + PAGE_SIZE - 1;
+ y1 = beg / fb_info->fix.line_length;
+ y2 = end / fb_info->fix.line_length;
+ if (y2 >= fb_info->var.yres)
+ y2 = fb_info->var.yres - 1;
+ if (miny > y1)
+ miny = y1;
+ if (maxy < y2)
+ maxy = y2;
+ }
+ xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1);
+}
+
+static struct fb_deferred_io xenfb_defio = {
+ .delay = HZ / 20,
+ .deferred_io = xenfb_deferred_io,
+};
+
+static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ u32 v;
+
+ if (regno > info->cmap.len)
+ return 1;
+
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ case 24:
+ case 32:
+ ((u32 *)info->pseudo_palette)[regno] = v;
+ break;
+ }
+
+ return 0;
+}
+
+static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+ struct xenfb_info *info = p->par;
+
+ sys_fillrect(p, rect);
+ xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
+}
+
+static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+ struct xenfb_info *info = p->par;
+
+ sys_imageblit(p, image);
+ xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
+}
+
+static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+ struct xenfb_info *info = p->par;
+
+ sys_copyarea(p, area);
+ xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
+}
+
+static ssize_t xenfb_write(struct fb_info *p, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct xenfb_info *info = p->par;
+ ssize_t res;
+
+ res = fb_sys_write(p, buf, count, ppos);
+ xenfb_refresh(info, 0, 0, info->page->width, info->page->height);
+ return res;
+}
+
+static struct fb_ops xenfb_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = xenfb_write,
+ .fb_setcolreg = xenfb_setcolreg,
+ .fb_fillrect = xenfb_fillrect,
+ .fb_copyarea = xenfb_copyarea,
+ .fb_imageblit = xenfb_imageblit,
+};
+
+static irqreturn_t xenfb_event_handler(int rq, void *dev_id)
+{
+ /*
+ * No in events recognized, simply ignore them all.
+ * If you need to recognize some, see xen-kbdfront's
+ * input_handler() for how to do that.
+ */
+ struct xenfb_info *info = dev_id;
+ struct xenfb_page *page = info->page;
+
+ if (page->in_cons != page->in_prod) {
+ info->page->in_cons = info->page->in_prod;
+ notify_remote_via_irq(info->irq);
+ }
+
+ /* Flush dirty rectangle: */
+ xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit xenfb_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ struct xenfb_info *info;
+ struct fb_info *fb_info;
+ int ret;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+ return -ENOMEM;
+ }
+ dev->dev.driver_data = info;
+ info->xbdev = dev;
+ info->irq = -1;
+ info->x1 = info->y1 = INT_MAX;
+ spin_lock_init(&info->dirty_lock);
+
+ info->fb = vmalloc(xenfb_mem_len);
+ if (info->fb == NULL)
+ goto error_nomem;
+ memset(info->fb, 0, xenfb_mem_len);
+
+ info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
+ if (!info->mfns)
+ goto error_nomem;
+
+ /* set up shared page */
+ info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+ if (!info->page)
+ goto error_nomem;
+
+ xenfb_init_shared_page(info);
+
+ /* abusing framebuffer_alloc() to allocate pseudo_palette */
+ fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
+ if (fb_info == NULL)
+ goto error_nomem;
+
+ /* complete the abuse: */
+ fb_info->pseudo_palette = fb_info->par;
+ fb_info->par = info;
+
+ fb_info->screen_base = info->fb;
+
+ fb_info->fbops = &xenfb_fb_ops;
+ fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
+ fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
+ fb_info->var.bits_per_pixel = info->page->depth;
+
+ fb_info->var.red = (struct fb_bitfield){16, 8, 0};
+ fb_info->var.green = (struct fb_bitfield){8, 8, 0};
+ fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
+
+ fb_info->var.activate = FB_ACTIVATE_NOW;
+ fb_info->var.height = -1;
+ fb_info->var.width = -1;
+ fb_info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
+ fb_info->fix.line_length = info->page->line_length;
+ fb_info->fix.smem_start = 0;
+ fb_info->fix.smem_len = xenfb_mem_len;
+ strcpy(fb_info->fix.id, "xen");
+ fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
+ fb_info->fix.accel = FB_ACCEL_NONE;
+
+ fb_info->flags = FBINFO_FLAG_DEFAULT;
+
+ ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
+ if (ret < 0) {
+ framebuffer_release(fb_info);
+ xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
+ goto error;
+ }
+
+ fb_info->fbdefio = &xenfb_defio;
+ fb_deferred_io_init(fb_info);
+
+ ret = register_framebuffer(fb_info);
+ if (ret) {
+ fb_deferred_io_cleanup(fb_info);
+ fb_dealloc_cmap(&fb_info->cmap);
+ framebuffer_release(fb_info);
+ xenbus_dev_fatal(dev, ret, "register_framebuffer");
+ goto error;
+ }
+ info->fb_info = fb_info;
+
+ ret = xenfb_connect_backend(dev, info);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+ error_nomem:
+ ret = -ENOMEM;
+ xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+ xenfb_remove(dev);
+ return ret;
+}
+
+static int xenfb_resume(struct xenbus_device *dev)
+{
+ struct xenfb_info *info = dev->dev.driver_data;
+
+ xenfb_disconnect_backend(info);
+ xenfb_init_shared_page(info);
+ return xenfb_connect_backend(dev, info);
+}
+
+static int xenfb_remove(struct xenbus_device *dev)
+{
+ struct xenfb_info *info = dev->dev.driver_data;
+
+ xenfb_disconnect_backend(info);
+ if (info->fb_info) {
+ fb_deferred_io_cleanup(info->fb_info);
+ unregister_framebuffer(info->fb_info);
+ fb_dealloc_cmap(&info->fb_info->cmap);
+ framebuffer_release(info->fb_info);
+ }
+ free_page((unsigned long)info->page);
+ vfree(info->mfns);
+ vfree(info->fb);
+ kfree(info);
+
+ return 0;
+}
+
+static unsigned long vmalloc_to_mfn(void *address)
+{
+ return pfn_to_mfn(vmalloc_to_pfn(address));
+}
+
+static void xenfb_init_shared_page(struct xenfb_info *info)
+{
+ int i;
+
+ for (i = 0; i < info->nr_pages; i++)
+ info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
+
+ info->page->pd[0] = vmalloc_to_mfn(info->mfns);
+ info->page->pd[1] = 0;
+ info->page->width = XENFB_WIDTH;
+ info->page->height = XENFB_HEIGHT;
+ info->page->depth = XENFB_DEPTH;
+ info->page->line_length = (info->page->depth / 8) * info->page->width;
+ info->page->mem_length = xenfb_mem_len;
+ info->page->in_cons = info->page->in_prod = 0;
+ info->page->out_cons = info->page->out_prod = 0;
+}
+
+static int xenfb_connect_backend(struct xenbus_device *dev,
+ struct xenfb_info *info)
+{
+ int ret, evtchn;
+ struct xenbus_transaction xbt;
+
+ ret = xenbus_alloc_evtchn(dev, &evtchn);
+ if (ret)
+ return ret;
+ ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
+ 0, dev->devicetype, info);
+ if (ret < 0) {
+ xenbus_free_evtchn(dev, evtchn);
+ xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+ return ret;
+ }
+ info->irq = ret;
+
+ again:
+ ret = xenbus_transaction_start(&xbt);
+ if (ret) {
+ xenbus_dev_fatal(dev, ret, "starting transaction");
+ return ret;
+ }
+ ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+ virt_to_mfn(info->page));
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+ evtchn);
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
+ XEN_IO_PROTO_ABI_NATIVE);
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
+ if (ret)
+ goto error_xenbus;
+ ret = xenbus_transaction_end(xbt, 0);
+ if (ret) {
+ if (ret == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, ret, "completing transaction");
+ return ret;
+ }
+
+ xenbus_switch_state(dev, XenbusStateInitialised);
+ return 0;
+
+ error_xenbus:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(dev, ret, "writing xenstore");
+ return ret;
+}
+
+static void xenfb_disconnect_backend(struct xenfb_info *info)
+{
+ if (info->irq >= 0)
+ unbind_from_irqhandler(info->irq, info);
+ info->irq = -1;
+}
+
+static void xenfb_backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct xenfb_info *info = dev->dev.driver_data;
+ int val;
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitialised:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateInitWait:
+InitWait:
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateConnected:
+ /*
+ * Work around xenbus race condition: If backend goes
+ * through InitWait to Connected fast enough, we can
+ * get Connected twice here.
+ */
+ if (dev->state != XenbusStateConnected)
+ goto InitWait; /* no InitWait seen yet, fudge it */
+
+ if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+ "request-update", "%d", &val) < 0)
+ val = 0;
+ if (val)
+ info->update_wanted = 1;
+ break;
+
+ case XenbusStateClosing:
+ xenbus_frontend_closed(dev);
+ break;
+ }
+}
+
+static struct xenbus_device_id xenfb_ids[] = {
+ { "vfb" },
+ { "" }
+};
+
+static struct xenbus_driver xenfb = {
+ .name = "vfb",
+ .owner = THIS_MODULE,
+ .ids = xenfb_ids,
+ .probe = xenfb_probe,
+ .remove = xenfb_remove,
+ .resume = xenfb_resume,
+ .otherend_changed = xenfb_backend_changed,
+};
+
+static int __init xenfb_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ /* Nothing to do if running in dom0. */
+ if (is_initial_xendomain())
+ return -ENODEV;
+
+ return xenbus_register_frontend(&xenfb);
+}
+
+static void __exit xenfb_cleanup(void)
+{
+ xenbus_unregister_driver(&xenfb);
+}
+
+module_init(xenfb_init);
+module_exit(xenfb_cleanup);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
new file mode 100644
index 000000000000..4b75a16de009
--- /dev/null
+++ b/drivers/xen/Kconfig
@@ -0,0 +1,19 @@
+config XEN_BALLOON
+ bool "Xen memory balloon driver"
+ depends on XEN
+ default y
+ help
+ The balloon driver allows the Xen domain to request more memory from
+ the system to expand the domain's memory allocation, or alternatively
+ return unneeded memory to the system.
+
+config XEN_SCRUB_PAGES
+ bool "Scrub pages before returning them to system"
+ depends on XEN_BALLOON
+ default y
+ help
+ Scrub pages before returning them to the system for reuse by
+ other domains. This makes sure that any confidential data
+ is not accidentally visible to other domains. Is it more
+ secure, but slightly less efficient.
+ If in doubt, say yes.
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 56592f0d6cef..37af04f1ffd9 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,2 +1,4 @@
-obj-y += grant-table.o
+obj-y += grant-table.o features.o events.o
obj-y += xenbus/
+obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
+obj-$(CONFIG_XEN_BALLOON) += balloon.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
new file mode 100644
index 000000000000..ab25ba6cbbb9
--- /dev/null
+++ b/drivers/xen/balloon.c
@@ -0,0 +1,712 @@
+/******************************************************************************
+ * balloon.c
+ *
+ * Xen balloon driver - enables returning/claiming memory to/from Xen.
+ *
+ * Copyright (c) 2003, B Dragovic
+ * Copyright (c) 2003-2004, M Williamson, K Fraser
+ * Copyright (c) 2005 Dan M. Smith, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/mutex.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#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>
+
+#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
+
+#define BALLOON_CLASS_NAME "memory"
+
+struct balloon_stats {
+ /* We aim for 'current allocation' == 'target allocation'. */
+ unsigned long current_pages;
+ unsigned long target_pages;
+ /* We may hit the hard limit in Xen. If we do then we remember it. */
+ unsigned long hard_limit;
+ /*
+ * Drivers may alter the memory reservation independently, but they
+ * must inform the balloon driver so we avoid hitting the hard limit.
+ */
+ unsigned long driver_pages;
+ /* Number of pages in high- and low-memory balloons. */
+ unsigned long balloon_low;
+ unsigned long balloon_high;
+};
+
+static DEFINE_MUTEX(balloon_mutex);
+
+static struct sys_device balloon_sysdev;
+
+static int register_balloon(struct sys_device *sysdev);
+
+/*
+ * Protects atomic reservation decrease/increase against concurrent increases.
+ * Also protects non-atomic updates of current_pages and driver_pages, and
+ * balloon lists.
+ */
+static DEFINE_SPINLOCK(balloon_lock);
+
+static struct balloon_stats balloon_stats;
+
+/* We increase/decrease in batches which fit in a page */
+static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
+
+/* VM /proc information for memory */
+extern unsigned long totalram_pages;
+
+#ifdef CONFIG_HIGHMEM
+extern unsigned long totalhigh_pages;
+#define inc_totalhigh_pages() (totalhigh_pages++)
+#define dec_totalhigh_pages() (totalhigh_pages--)
+#else
+#define inc_totalhigh_pages() do {} while(0)
+#define dec_totalhigh_pages() do {} while(0)
+#endif
+
+/* List of ballooned pages, threaded through the mem_map array. */
+static LIST_HEAD(ballooned_pages);
+
+/* Main work function, always executed in process context. */
+static void balloon_process(struct work_struct *work);
+static DECLARE_WORK(balloon_worker, balloon_process);
+static struct timer_list balloon_timer;
+
+/* When ballooning out (allocating memory to return to Xen) we don't really
+ want the kernel to try too hard since that can trigger the oom killer. */
+#define GFP_BALLOON \
+ (GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC)
+
+static void scrub_page(struct page *page)
+{
+#ifdef CONFIG_XEN_SCRUB_PAGES
+ if (PageHighMem(page)) {
+ void *v = kmap(page);
+ clear_page(v);
+ kunmap(v);
+ } else {
+ void *v = page_address(page);
+ clear_page(v);
+ }
+#endif
+}
+
+/* balloon_append: add the given page to the balloon. */
+static void balloon_append(struct page *page)
+{
+ /* Lowmem is re-populated first, so highmem pages go at list tail. */
+ if (PageHighMem(page)) {
+ list_add_tail(&page->lru, &ballooned_pages);
+ balloon_stats.balloon_high++;
+ dec_totalhigh_pages();
+ } else {
+ list_add(&page->lru, &ballooned_pages);
+ balloon_stats.balloon_low++;
+ }
+}
+
+/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
+static struct page *balloon_retrieve(void)
+{
+ struct page *page;
+
+ if (list_empty(&ballooned_pages))
+ return NULL;
+
+ page = list_entry(ballooned_pages.next, struct page, lru);
+ list_del(&page->lru);
+
+ if (PageHighMem(page)) {
+ balloon_stats.balloon_high--;
+ inc_totalhigh_pages();
+ }
+ else
+ balloon_stats.balloon_low--;
+
+ return page;
+}
+
+static struct page *balloon_first_page(void)
+{
+ if (list_empty(&ballooned_pages))
+ return NULL;
+ return list_entry(ballooned_pages.next, struct page, lru);
+}
+
+static struct page *balloon_next_page(struct page *page)
+{
+ struct list_head *next = page->lru.next;
+ if (next == &ballooned_pages)
+ return NULL;
+ return list_entry(next, struct page, lru);
+}
+
+static void balloon_alarm(unsigned long unused)
+{
+ schedule_work(&balloon_worker);
+}
+
+static unsigned long current_target(void)
+{
+ unsigned long target = min(balloon_stats.target_pages, balloon_stats.hard_limit);
+
+ target = min(target,
+ balloon_stats.current_pages +
+ balloon_stats.balloon_low +
+ balloon_stats.balloon_high);
+
+ return target;
+}
+
+static int increase_reservation(unsigned long nr_pages)
+{
+ unsigned long pfn, i, flags;
+ struct page *page;
+ long rc;
+ struct xen_memory_reservation reservation = {
+ .address_bits = 0,
+ .extent_order = 0,
+ .domid = DOMID_SELF
+ };
+
+ if (nr_pages > ARRAY_SIZE(frame_list))
+ nr_pages = ARRAY_SIZE(frame_list);
+
+ spin_lock_irqsave(&balloon_lock, flags);
+
+ page = balloon_first_page();
+ for (i = 0; i < nr_pages; i++) {
+ BUG_ON(page == NULL);
+ frame_list[i] = page_to_pfn(page);;
+ page = balloon_next_page(page);
+ }
+
+ reservation.extent_start = (unsigned long)frame_list;
+ reservation.nr_extents = nr_pages;
+ rc = HYPERVISOR_memory_op(
+ XENMEM_populate_physmap, &reservation);
+ if (rc < nr_pages) {
+ if (rc > 0) {
+ int ret;
+
+ /* We hit the Xen hard limit: reprobe. */
+ reservation.nr_extents = rc;
+ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+ &reservation);
+ BUG_ON(ret != rc);
+ }
+ if (rc >= 0)
+ balloon_stats.hard_limit = (balloon_stats.current_pages + rc -
+ balloon_stats.driver_pages);
+ goto out;
+ }
+
+ for (i = 0; i < nr_pages; i++) {
+ page = balloon_retrieve();
+ BUG_ON(page == NULL);
+
+ pfn = page_to_pfn(page);
+ BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) &&
+ phys_to_machine_mapping_valid(pfn));
+
+ set_phys_to_machine(pfn, frame_list[i]);
+
+ /* Link back into the page tables if not highmem. */
+ if (pfn < max_low_pfn) {
+ int ret;
+ ret = HYPERVISOR_update_va_mapping(
+ (unsigned long)__va(pfn << PAGE_SHIFT),
+ mfn_pte(frame_list[i], PAGE_KERNEL),
+ 0);
+ BUG_ON(ret);
+ }
+
+ /* Relinquish the page back to the allocator. */
+ ClearPageReserved(page);
+ init_page_count(page);
+ __free_page(page);
+ }
+
+ balloon_stats.current_pages += nr_pages;
+ totalram_pages = balloon_stats.current_pages;
+
+ out:
+ spin_unlock_irqrestore(&balloon_lock, flags);
+
+ return 0;
+}
+
+static int decrease_reservation(unsigned long nr_pages)
+{
+ unsigned long pfn, i, flags;
+ struct page *page;
+ int need_sleep = 0;
+ int ret;
+ struct xen_memory_reservation reservation = {
+ .address_bits = 0,
+ .extent_order = 0,
+ .domid = DOMID_SELF
+ };
+
+ if (nr_pages > ARRAY_SIZE(frame_list))
+ nr_pages = ARRAY_SIZE(frame_list);
+
+ for (i = 0; i < nr_pages; i++) {
+ if ((page = alloc_page(GFP_BALLOON)) == NULL) {
+ nr_pages = i;
+ need_sleep = 1;
+ break;
+ }
+
+ pfn = page_to_pfn(page);
+ frame_list[i] = pfn_to_mfn(pfn);
+
+ scrub_page(page);
+ }
+
+ /* Ensure that ballooned highmem pages don't have kmaps. */
+ kmap_flush_unused();
+ flush_tlb_all();
+
+ spin_lock_irqsave(&balloon_lock, flags);
+
+ /* No more mappings: invalidate P2M and add to balloon. */
+ for (i = 0; i < nr_pages; i++) {
+ pfn = mfn_to_pfn(frame_list[i]);
+ set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+ balloon_append(pfn_to_page(pfn));
+ }
+
+ reservation.extent_start = (unsigned long)frame_list;
+ reservation.nr_extents = nr_pages;
+ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
+ BUG_ON(ret != nr_pages);
+
+ balloon_stats.current_pages -= nr_pages;
+ totalram_pages = balloon_stats.current_pages;
+
+ spin_unlock_irqrestore(&balloon_lock, flags);
+
+ return need_sleep;
+}
+
+/*
+ * We avoid multiple worker processes conflicting via the balloon mutex.
+ * We may of course race updates of the target counts (which are protected
+ * by the balloon lock), or with changes to the Xen hard limit, but we will
+ * recover from these in time.
+ */
+static void balloon_process(struct work_struct *work)
+{
+ int need_sleep = 0;
+ long credit;
+
+ mutex_lock(&balloon_mutex);
+
+ do {
+ credit = current_target() - balloon_stats.current_pages;
+ if (credit > 0)
+ need_sleep = (increase_reservation(credit) != 0);
+ if (credit < 0)
+ need_sleep = (decrease_reservation(-credit) != 0);
+
+#ifndef CONFIG_PREEMPT
+ if (need_resched())
+ schedule();
+#endif
+ } while ((credit != 0) && !need_sleep);
+
+ /* Schedule more work if there is some still to be done. */
+ if (current_target() != balloon_stats.current_pages)
+ mod_timer(&balloon_timer, jiffies + HZ);
+
+ mutex_unlock(&balloon_mutex);
+}
+
+/* Resets the Xen limit, sets new target, and kicks off processing. */
+void balloon_set_new_target(unsigned long target)
+{
+ /* No need for lock. Not read-modify-write updates. */
+ balloon_stats.hard_limit = ~0UL;
+ balloon_stats.target_pages = target;
+ schedule_work(&balloon_worker);
+}
+
+static struct xenbus_watch target_watch =
+{
+ .node = "memory/target"
+};
+
+/* React to a change in the target key */
+static void watch_target(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ unsigned long long new_target;
+ int err;
+
+ err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
+ if (err != 1) {
+ /* This is ok (for domain0 at least) - so just return */
+ return;
+ }
+
+ /* The given memory/target value is in KiB, so it needs converting to
+ * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
+ */
+ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
+}
+
+static int balloon_init_watcher(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ int err;
+
+ err = register_xenbus_watch(&target_watch);
+ if (err)
+ printk(KERN_ERR "Failed to set balloon watcher\n");
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xenstore_notifier;
+
+static int __init balloon_init(void)
+{
+ unsigned long pfn;
+ struct page *page;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ pr_info("xen_balloon: Initialising balloon driver.\n");
+
+ balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn);
+ totalram_pages = balloon_stats.current_pages;
+ balloon_stats.target_pages = balloon_stats.current_pages;
+ balloon_stats.balloon_low = 0;
+ balloon_stats.balloon_high = 0;
+ balloon_stats.driver_pages = 0UL;
+ balloon_stats.hard_limit = ~0UL;
+
+ init_timer(&balloon_timer);
+ balloon_timer.data = 0;
+ balloon_timer.function = balloon_alarm;
+
+ register_balloon(&balloon_sysdev);
+
+ /* Initialise the balloon with excess memory space. */
+ for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
+ page = pfn_to_page(pfn);
+ if (!PageReserved(page))
+ balloon_append(page);
+ }
+
+ target_watch.callback = watch_target;
+ xenstore_notifier.notifier_call = balloon_init_watcher;
+
+ register_xenstore_notifier(&xenstore_notifier);
+
+ return 0;
+}
+
+subsys_initcall(balloon_init);
+
+static void balloon_exit(void)
+{
+ /* XXX - release balloon here */
+ return;
+}
+
+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
+ };
+ reservation.extent_start = (unsigned long)&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
+ };
+ reservation.extent_start = (unsigned long)&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); \
+ } \
+ static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
+
+BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
+BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
+BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
+BALLOON_SHOW(hard_limit_kb,
+ (balloon_stats.hard_limit!=~0UL) ? "%lu\n" : "???\n",
+ (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)
+{
+ return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
+}
+
+static ssize_t store_target_kb(struct sys_device *dev,
+ const char *buf,
+ size_t count)
+{
+ char memstring[64], *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(memstring, &endchar);
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
+
+ return count;
+}
+
+static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
+ show_target_kb, store_target_kb);
+
+static struct sysdev_attribute *balloon_attrs[] = {
+ &attr_target_kb,
+};
+
+static struct attribute *balloon_info_attrs[] = {
+ &attr_current_kb.attr,
+ &attr_low_kb.attr,
+ &attr_high_kb.attr,
+ &attr_hard_limit_kb.attr,
+ &attr_driver_kb.attr,
+ NULL
+};
+
+static struct attribute_group balloon_info_group = {
+ .name = "info",
+ .attrs = balloon_info_attrs,
+};
+
+static struct sysdev_class balloon_sysdev_class = {
+ .name = BALLOON_CLASS_NAME,
+};
+
+static int register_balloon(struct sys_device *sysdev)
+{
+ int i, error;
+
+ error = sysdev_class_register(&balloon_sysdev_class);
+ if (error)
+ return error;
+
+ sysdev->id = 0;
+ sysdev->cls = &balloon_sysdev_class;
+
+ error = sysdev_register(sysdev);
+ if (error) {
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
+ error = sysdev_create_file(sysdev, balloon_attrs[i]);
+ if (error)
+ goto fail;
+ }
+
+ error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
+ if (error)
+ goto fail;
+
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ sysdev_remove_file(sysdev, balloon_attrs[i]);
+ sysdev_unregister(sysdev);
+ sysdev_class_unregister(&balloon_sysdev_class);
+ 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/arch/x86/xen/events.c b/drivers/xen/events.c
index dcf613e17581..4f0f22b020ea 100644
--- a/arch/x86/xen/events.c
+++ b/drivers/xen/events.c
@@ -33,12 +33,11 @@
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
+#include <xen/xen-ops.h>
#include <xen/events.h>
#include <xen/interface/xen.h>
#include <xen/interface/event_channel.h>
-#include "xen-ops.h"
-
/*
* This lock protects updates to the following mapping and reference-count
* arrays. The lock does not need to be acquired to read the mapping tables.
@@ -455,6 +454,53 @@ void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
notify_remote_via_irq(irq);
}
+irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
+{
+ struct shared_info *sh = HYPERVISOR_shared_info;
+ int cpu = smp_processor_id();
+ int i;
+ unsigned long flags;
+ static DEFINE_SPINLOCK(debug_lock);
+
+ spin_lock_irqsave(&debug_lock, flags);
+
+ printk("vcpu %d\n ", cpu);
+
+ for_each_online_cpu(i) {
+ struct vcpu_info *v = per_cpu(xen_vcpu, i);
+ printk("%d: masked=%d pending=%d event_sel %08lx\n ", i,
+ (get_irq_regs() && i == cpu) ? xen_irqs_disabled(get_irq_regs()) : v->evtchn_upcall_mask,
+ v->evtchn_upcall_pending,
+ v->evtchn_pending_sel);
+ }
+ printk("pending:\n ");
+ for(i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
+ printk("%08lx%s", sh->evtchn_pending[i],
+ i % 8 == 0 ? "\n " : " ");
+ printk("\nmasks:\n ");
+ for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
+ printk("%08lx%s", sh->evtchn_mask[i],
+ i % 8 == 0 ? "\n " : " ");
+
+ printk("\nunmasked:\n ");
+ for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
+ printk("%08lx%s", sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
+ i % 8 == 0 ? "\n " : " ");
+
+ printk("\npending list:\n");
+ for(i = 0; i < NR_EVENT_CHANNELS; i++) {
+ if (sync_test_bit(i, sh->evtchn_pending)) {
+ printk(" %d: event %d -> irq %d\n",
+ cpu_evtchn[i], i,
+ evtchn_to_irq[i]);
+ }
+ }
+
+ spin_unlock_irqrestore(&debug_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
/*
* Search the CPUs pending events bitmasks. For each one found, map
@@ -470,29 +516,44 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
int cpu = get_cpu();
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
- unsigned long pending_words;
+ static DEFINE_PER_CPU(unsigned, nesting_count);
+ unsigned count;
- vcpu_info->evtchn_upcall_pending = 0;
+ do {
+ unsigned long pending_words;
- /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
- pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
- while (pending_words != 0) {
- unsigned long pending_bits;
- int word_idx = __ffs(pending_words);
- pending_words &= ~(1UL << word_idx);
+ vcpu_info->evtchn_upcall_pending = 0;
- while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
- int bit_idx = __ffs(pending_bits);
- int port = (word_idx * BITS_PER_LONG) + bit_idx;
- int irq = evtchn_to_irq[port];
+ if (__get_cpu_var(nesting_count)++)
+ goto out;
- if (irq != -1) {
- regs->orig_ax = ~irq;
- do_IRQ(regs);
+#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
+ /* Clear master flag /before/ clearing selector flag. */
+ rmb();
+#endif
+ pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
+ while (pending_words != 0) {
+ unsigned long pending_bits;
+ int word_idx = __ffs(pending_words);
+ pending_words &= ~(1UL << word_idx);
+
+ while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
+ int bit_idx = __ffs(pending_bits);
+ int port = (word_idx * BITS_PER_LONG) + bit_idx;
+ int irq = evtchn_to_irq[port];
+
+ if (irq != -1)
+ xen_do_IRQ(irq, regs);
}
}
- }
+ BUG_ON(!irqs_disabled());
+
+ count = __get_cpu_var(nesting_count);
+ __get_cpu_var(nesting_count) = 0;
+ } while(count != 1);
+
+out:
put_cpu();
}
@@ -525,6 +586,22 @@ static void set_affinity_irq(unsigned irq, cpumask_t dest)
rebind_irq_to_cpu(irq, tcpu);
}
+int resend_irq_on_evtchn(unsigned int irq)
+{
+ int masked, evtchn = evtchn_from_irq(irq);
+ struct shared_info *s = HYPERVISOR_shared_info;
+
+ if (!VALID_EVTCHN(evtchn))
+ return 1;
+
+ masked = sync_test_and_set_bit(evtchn, s->evtchn_mask);
+ sync_set_bit(evtchn, s->evtchn_pending);
+ if (!masked)
+ unmask_evtchn(evtchn);
+
+ return 1;
+}
+
static void enable_dynirq(unsigned int irq)
{
int evtchn = evtchn_from_irq(irq);
@@ -554,10 +631,16 @@ static void ack_dynirq(unsigned int irq)
static int retrigger_dynirq(unsigned int irq)
{
int evtchn = evtchn_from_irq(irq);
+ struct shared_info *sh = HYPERVISOR_shared_info;
int ret = 0;
if (VALID_EVTCHN(evtchn)) {
- set_evtchn(evtchn);
+ int masked;
+
+ masked = sync_test_and_set_bit(evtchn, sh->evtchn_mask);
+ sync_set_bit(evtchn, sh->evtchn_pending);
+ if (!masked)
+ unmask_evtchn(evtchn);
ret = 1;
}
diff --git a/arch/x86/xen/features.c b/drivers/xen/features.c
index 0707714e40d6..0707714e40d6 100644
--- a/arch/x86/xen/features.c
+++ b/drivers/xen/features.c
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index d85dc6d41c2a..52b6b41b909d 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -439,24 +439,6 @@ static inline unsigned int max_nr_grant_frames(void)
return xen_max;
}
-static int map_pte_fn(pte_t *pte, struct page *pmd_page,
- unsigned long addr, void *data)
-{
- unsigned long **frames = (unsigned long **)data;
-
- set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
- (*frames)++;
- return 0;
-}
-
-static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
- unsigned long addr, void *data)
-{
-
- set_pte_at(&init_mm, addr, pte, __pte(0));
- return 0;
-}
-
static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
struct gnttab_setup_table setup;
@@ -470,7 +452,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
setup.dom = DOMID_SELF;
setup.nr_frames = nr_gframes;
- setup.frame_list = frames;
+ set_xen_guest_handle(setup.frame_list, frames);
rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
if (rc == -ENOSYS) {
@@ -480,17 +462,9 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
BUG_ON(rc || setup.status);
- if (shared == NULL) {
- struct vm_struct *area;
- area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
- BUG_ON(area == NULL);
- shared = area->addr;
- }
- rc = apply_to_page_range(&init_mm, (unsigned long)shared,
- PAGE_SIZE * nr_gframes,
- map_pte_fn, &frames);
+ rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(),
+ &shared);
BUG_ON(rc);
- frames -= nr_gframes; /* adjust after map_pte_fn() */
kfree(frames);
@@ -506,10 +480,7 @@ static int gnttab_resume(void)
static int gnttab_suspend(void)
{
- apply_to_page_range(&init_mm, (unsigned long)shared,
- PAGE_SIZE * nr_grant_frames,
- unmap_pte_fn, NULL);
-
+ arch_gnttab_unmap_shared(shared, nr_grant_frames);
return 0;
}
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 9fd2f70ab46d..0f86b0ff7879 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -399,7 +399,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
*vaddr = NULL;
- area = alloc_vm_area(PAGE_SIZE);
+ area = xen_alloc_vm_area(PAGE_SIZE);
if (!area)
return -ENOMEM;
@@ -409,7 +409,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
BUG();
if (op.status != GNTST_okay) {
- free_vm_area(area);
+ xen_free_vm_area(area);
xenbus_dev_fatal(dev, op.status,
"mapping in shared page %d from domain %d",
gnt_ref, dev->otherend_id);
@@ -508,7 +508,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
BUG();
if (op.status == GNTST_okay)
- free_vm_area(area);
+ xen_free_vm_area(area);
else
xenbus_dev_error(dev, op.status,
"unmapping page at handle %d error %d",
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 4750de316ad3..57ceb5346b74 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -88,6 +88,16 @@ int xenbus_match(struct device *_dev, struct device_driver *_drv)
return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
}
+static int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+
+ if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype))
+ return -ENOMEM;
+
+ return 0;
+}
+
/* device/<type>/<id> => <type>-<id> */
static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
{
@@ -166,6 +176,7 @@ static struct xen_bus_type xenbus_frontend = {
.bus = {
.name = "xen",
.match = xenbus_match,
+ .uevent = xenbus_uevent,
.probe = xenbus_dev_probe,
.remove = xenbus_dev_remove,
.shutdown = xenbus_dev_shutdown,
@@ -438,6 +449,12 @@ static ssize_t xendev_show_devtype(struct device *dev,
}
DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+static ssize_t xendev_show_modalias(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "xen:%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL);
int xenbus_probe_node(struct xen_bus_type *bus,
const char *type,
@@ -492,10 +509,16 @@ int xenbus_probe_node(struct xen_bus_type *bus,
err = device_create_file(&xendev->dev, &dev_attr_devtype);
if (err)
- goto fail_remove_file;
+ goto fail_remove_nodename;
+
+ err = device_create_file(&xendev->dev, &dev_attr_modalias);
+ if (err)
+ goto fail_remove_devtype;
return 0;
-fail_remove_file:
+fail_remove_devtype:
+ device_remove_file(&xendev->dev, &dev_attr_devtype);
+fail_remove_nodename:
device_remove_file(&xendev->dev, &dev_attr_nodename);
fail_unregister:
device_unregister(&xendev->dev);
@@ -846,6 +869,7 @@ static int is_disconnected_device(struct device *dev, void *data)
{
struct xenbus_device *xendev = to_xenbus_device(dev);
struct device_driver *drv = data;
+ struct xenbus_driver *xendrv;
/*
* A device with no driver will never connect. We care only about
@@ -858,7 +882,9 @@ static int is_disconnected_device(struct device *dev, void *data)
if (drv && (dev->driver != drv))
return 0;
- return (xendev->state != XenbusStateConnected);
+ xendrv = to_xenbus_driver(dev->driver);
+ return (xendev->state != XenbusStateConnected ||
+ (xendrv->is_ready && !xendrv->is_ready(xendev)));
}
static int exists_disconnected_device(struct device_driver *drv)
diff --git a/drivers/xen/xencomm.c b/drivers/xen/xencomm.c
new file mode 100644
index 000000000000..797cb4e31f07
--- /dev/null
+++ b/drivers/xen/xencomm.c
@@ -0,0 +1,232 @@
+/*
+ * 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
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <xen/xencomm.h>
+#include <xen/interface/xen.h>
+#ifdef __ia64__
+#include <asm/xen/xencomm.h> /* for is_kern_addr() */
+#endif
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+static int xencomm_init(struct xencomm_desc *desc,
+ void *buffer, unsigned long bytes)
+{
+ unsigned long recorded = 0;
+ int i = 0;
+
+ while ((recorded < bytes) && (i < desc->nr_addrs)) {
+ unsigned long vaddr = (unsigned long)buffer + recorded;
+ unsigned long paddr;
+ int offset;
+ int chunksz;
+
+ offset = vaddr % PAGE_SIZE; /* handle partial pages */
+ chunksz = min(PAGE_SIZE - offset, bytes - recorded);
+
+ paddr = xencomm_vtop(vaddr);
+ if (paddr == ~0UL) {
+ printk(KERN_DEBUG "%s: couldn't translate vaddr %lx\n",
+ __func__, vaddr);
+ return -EINVAL;
+ }
+
+ desc->address[i++] = paddr;
+ recorded += chunksz;
+ }
+
+ if (recorded < bytes) {
+ printk(KERN_DEBUG
+ "%s: could only translate %ld of %ld bytes\n",
+ __func__, recorded, bytes);
+ return -ENOSPC;
+ }
+
+ /* mark remaining addresses invalid (just for safety) */
+ while (i < desc->nr_addrs)
+ desc->address[i++] = XENCOMM_INVALID;
+
+ desc->magic = XENCOMM_MAGIC;
+
+ return 0;
+}
+
+static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask,
+ void *buffer, unsigned long bytes)
+{
+ struct xencomm_desc *desc;
+ unsigned long buffer_ulong = (unsigned long)buffer;
+ unsigned long start = buffer_ulong & PAGE_MASK;
+ unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK;
+ unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT;
+ unsigned long size = sizeof(*desc) +
+ sizeof(desc->address[0]) * nr_addrs;
+
+ /*
+ * slab allocator returns at least sizeof(void*) aligned pointer.
+ * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might
+ * cross page boundary.
+ */
+ if (sizeof(*desc) > sizeof(void *)) {
+ unsigned long order = get_order(size);
+ desc = (struct xencomm_desc *)__get_free_pages(gfp_mask,
+ order);
+ if (desc == NULL)
+ return NULL;
+
+ desc->nr_addrs =
+ ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) /
+ sizeof(*desc->address);
+ } else {
+ desc = kmalloc(size, gfp_mask);
+ if (desc == NULL)
+ return NULL;
+
+ desc->nr_addrs = nr_addrs;
+ }
+ return desc;
+}
+
+void xencomm_free(struct xencomm_handle *desc)
+{
+ if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) {
+ struct xencomm_desc *desc__ = (struct xencomm_desc *)desc;
+ if (sizeof(*desc__) > sizeof(void *)) {
+ unsigned long size = sizeof(*desc__) +
+ sizeof(desc__->address[0]) * desc__->nr_addrs;
+ unsigned long order = get_order(size);
+ free_pages((unsigned long)__va(desc), order);
+ } else
+ kfree(__va(desc));
+ }
+}
+
+static int xencomm_create(void *buffer, unsigned long bytes,
+ struct xencomm_desc **ret, gfp_t gfp_mask)
+{
+ struct xencomm_desc *desc;
+ int rc;
+
+ pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes);
+
+ if (bytes == 0) {
+ /* don't create a descriptor; Xen recognizes NULL. */
+ BUG_ON(buffer != NULL);
+ *ret = NULL;
+ return 0;
+ }
+
+ BUG_ON(buffer == NULL); /* 'bytes' is non-zero */
+
+ desc = xencomm_alloc(gfp_mask, buffer, bytes);
+ if (!desc) {
+ printk(KERN_DEBUG "%s failure\n", "xencomm_alloc");
+ return -ENOMEM;
+ }
+
+ rc = xencomm_init(desc, buffer, bytes);
+ if (rc) {
+ printk(KERN_DEBUG "%s failure: %d\n", "xencomm_init", rc);
+ xencomm_free((struct xencomm_handle *)__pa(desc));
+ return rc;
+ }
+
+ *ret = desc;
+ return 0;
+}
+
+/* check if memory address is within VMALLOC region */
+static int is_phys_contiguous(unsigned long addr)
+{
+ if (!is_kernel_addr(addr))
+ return 0;
+
+ return (addr < VMALLOC_START) || (addr >= VMALLOC_END);
+}
+
+static struct xencomm_handle *xencomm_create_inline(void *ptr)
+{
+ unsigned long paddr;
+
+ BUG_ON(!is_phys_contiguous((unsigned long)ptr));
+
+ paddr = (unsigned long)xencomm_pa(ptr);
+ BUG_ON(paddr & XENCOMM_INLINE_FLAG);
+ return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
+}
+
+/* "mini" routine, for stack-based communications: */
+static int xencomm_create_mini(void *buffer,
+ unsigned long bytes, struct xencomm_mini *xc_desc,
+ struct xencomm_desc **ret)
+{
+ int rc = 0;
+ struct xencomm_desc *desc;
+ BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0);
+
+ desc = (void *)xc_desc;
+
+ desc->nr_addrs = XENCOMM_MINI_ADDRS;
+
+ rc = xencomm_init(desc, buffer, bytes);
+ if (!rc)
+ *ret = desc;
+
+ return rc;
+}
+
+struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes)
+{
+ int rc;
+ struct xencomm_desc *desc;
+
+ if (is_phys_contiguous((unsigned long)ptr))
+ return xencomm_create_inline(ptr);
+
+ rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL);
+
+ if (rc || desc == NULL)
+ return NULL;
+
+ return xencomm_pa(desc);
+}
+
+struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes,
+ struct xencomm_mini *xc_desc)
+{
+ int rc;
+ struct xencomm_desc *desc = NULL;
+
+ if (is_phys_contiguous((unsigned long)ptr))
+ return xencomm_create_inline(ptr);
+
+ rc = xencomm_create_mini(ptr, bytes, xc_desc,
+ &desc);
+
+ if (rc)
+ return NULL;
+
+ return xencomm_pa(desc);
+}
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 678c02f1ae23..a452ac67fc94 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -224,12 +224,11 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
}
static void
-v9fs_umount_begin(struct vfsmount *vfsmnt, int flags)
+v9fs_umount_begin(struct super_block *sb)
{
- struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info;
+ struct v9fs_session_info *v9ses = sb->s_fs_info;
- if (flags & MNT_FORCE)
- v9fs_session_cancel(v9ses);
+ v9fs_session_cancel(v9ses);
}
static const struct super_operations v9fs_super_ops = {
diff --git a/fs/aio.c b/fs/aio.c
index 228368610dfa..ae94e1dea266 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1166,7 +1166,10 @@ retry:
break;
if (min_nr <= i)
break;
- ret = 0;
+ if (unlikely(ctx->dead)) {
+ ret = -EINVAL;
+ break;
+ }
if (to.timed_out) /* Only check after read evt */
break;
/* Try to only show up in io wait if there are ops
@@ -1231,6 +1234,13 @@ static void io_destroy(struct kioctx *ioctx)
aio_cancel_all(ioctx);
wait_for_all_aios(ioctx);
+
+ /*
+ * Wake up any waiters. The setting of ctx->dead must be seen
+ * by other CPUs at this point. Right now, we rely on the
+ * locking done by the above calls to ensure this consistency.
+ */
+ wake_up(&ioctx->wait);
put_ioctx(ioctx); /* once for the lookup */
}
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 5e1a4fb5cacb..9924581df6f6 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
- struct files_struct *files;
int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0;
struct {
@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto out_free_ph;
}
- files = current->files; /* Refcounted so ok */
- retval = unshare_files();
- if (retval < 0)
- goto out_free_ph;
- if (files == current->files) {
- put_files_struct(files);
- files = NULL;
- }
-
- /* exec will make our files private anyway, but for the a.out
- loader stuff we need to do it earlier */
retval = get_unused_fd();
if (retval < 0)
- goto out_free_fh;
+ goto out_free_ph;
get_file(bprm->file);
fd_install(elf_exec_fileno = retval, bprm->file);
@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval)
goto out_free_dentry;
- /* Discard our unneeded old files struct */
- if (files) {
- put_files_struct(files);
- files = NULL;
- }
-
/* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
@@ -1016,9 +998,6 @@ out_free_interp:
kfree(elf_interpreter);
out_free_file:
sys_close(elf_exec_fileno);
-out_free_fh:
- if (files)
- reset_files_struct(current, files);
out_free_ph:
kfree(elf_phdata);
goto out;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index b53c7e5f41bb..dbf0ac0523de 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
char *iname_addr = iname;
int retval;
int fd_binary = -1;
- struct files_struct *files = NULL;
retval = -ENOEXEC;
if (!enabled)
@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (fmt->flags & MISC_FMT_OPEN_BINARY) {
- files = current->files;
- retval = unshare_files();
- if (retval < 0)
- goto _ret;
- if (files == current->files) {
- put_files_struct(files);
- files = NULL;
- }
/* if the binary should be opened on behalf of the
* interpreter than keep it open and assign descriptor
* to it */
fd_binary = get_unused_fd();
if (fd_binary < 0) {
retval = fd_binary;
- goto _unshare;
+ goto _ret;
}
fd_install(fd_binary, bprm->file);
@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval < 0)
goto _error;
- if (files) {
- put_files_struct(files);
- files = NULL;
- }
_ret:
return retval;
_error:
@@ -216,9 +203,6 @@ _error:
sys_close(fd_binary);
bprm->interp_flags = 0;
bprm->interp_data = 0;
-_unshare:
- if (files)
- reset_files_struct(current, files);
goto _ret;
}
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 14c63527c762..fdc36bfd6a7b 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned long som_entry;
struct som_hdr *som_ex;
struct som_exec_auxhdr *hpuxhdr;
- struct files_struct *files;
/* Get the exec-header */
som_ex = (struct som_hdr *) bprm->buf;
@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out_free;
}
- files = current->files; /* Refcounted so ok */
- retval = unshare_files();
- if (retval < 0)
- goto out_free;
- if (files == current->files) {
- put_files_struct(files);
- files = NULL;
- }
-
retval = get_unused_fd();
if (retval < 0)
goto out_free;
diff --git a/fs/buffer.c b/fs/buffer.c
index 39ff14403d13..3db4a26adc44 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -360,16 +360,19 @@ void invalidate_bdev(struct block_device *bdev)
*/
static void free_more_memory(void)
{
- struct zone **zones;
- pg_data_t *pgdat;
+ struct zone *zone;
+ int nid;
wakeup_pdflush(1024);
yield();
- for_each_online_pgdat(pgdat) {
- zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones;
- if (*zones)
- try_to_free_pages(zones, 0, GFP_NOFS);
+ for_each_online_node(nid) {
+ (void)first_zones_zonelist(node_zonelist(nid, GFP_NOFS),
+ gfp_zone(GFP_NOFS), NULL,
+ &zone);
+ if (zone)
+ try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0,
+ GFP_NOFS);
}
}
@@ -2243,6 +2246,8 @@ int cont_expand_zero(struct file *file, struct address_space *mapping,
goto out;
BUG_ON(err != len);
err = 0;
+
+ balance_dirty_pages_ratelimited(mapping);
}
/* page covers the boundary, find the boundary offset */
@@ -3180,8 +3185,7 @@ static void recalc_bh_state(void)
struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
{
- struct buffer_head *ret = kmem_cache_alloc(bh_cachep,
- set_migrateflags(gfp_flags, __GFP_RECLAIMABLE));
+ struct buffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);
if (ret) {
INIT_LIST_HEAD(&ret->b_assoc_buffers);
get_cpu_var(bh_accounting).nr++;
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index f53f41ff1665..95024c066d89 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -25,14 +25,26 @@
static LIST_HEAD(cifs_dfs_automount_list);
-/*
- * DFS functions
-*/
+static void cifs_dfs_expire_automounts(struct work_struct *work);
+static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
+ cifs_dfs_expire_automounts);
+static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
+
+static void cifs_dfs_expire_automounts(struct work_struct *work)
+{
+ struct list_head *list = &cifs_dfs_automount_list;
+
+ mark_mounts_for_expiry(list);
+ if (!list_empty(list))
+ schedule_delayed_work(&cifs_dfs_automount_task,
+ cifs_dfs_mountpoint_expiry_timeout);
+}
-void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
+void cifs_dfs_release_automount_timer(void)
{
- mark_mounts_for_expiry(&cifs_dfs_automount_list);
- mark_mounts_for_expiry(&cifs_dfs_automount_list);
+ BUG_ON(!list_empty(&cifs_dfs_automount_list));
+ cancel_delayed_work(&cifs_dfs_automount_task);
+ flush_scheduled_work();
}
/**
@@ -261,10 +273,11 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist);
switch (err) {
case 0:
- dput(nd->path.dentry);
- mntput(nd->path.mnt);
+ path_put(&nd->path);
nd->path.mnt = newmnt;
nd->path.dentry = dget(newmnt->mnt_root);
+ schedule_delayed_work(&cifs_dfs_automount_task,
+ cifs_dfs_mountpoint_expiry_timeout);
break;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index a04b17e5a9d0..39c2cbdface7 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = {
};
#endif
-static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
+static void cifs_umount_begin(struct super_block *sb)
{
- struct cifs_sb_info *cifs_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *tcon;
- dfs_shrink_umount_helper(vfsmnt);
-
- if (!(flags & MNT_FORCE))
- return;
- cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
if (cifs_sb == NULL)
return;
@@ -1100,6 +1095,7 @@ exit_cifs(void)
cFYI(DBG2, ("exit_cifs"));
cifs_proc_clean();
#ifdef CONFIG_CIFS_DFS_UPCALL
+ cifs_dfs_release_automount_timer();
unregister_key_type(&key_type_dns_resolver);
#endif
#ifdef CONFIG_CIFS_UPCALL
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0c83da4a7dab..50f9fdae19b3 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -104,13 +104,7 @@ extern int mode_to_acl(struct inode *inode, const char *path, __u64);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
-#ifdef CONFIG_CIFS_DFS_UPCALL
-extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
-#else
-static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
-{
-}
-#endif /* DFS_UPCALL */
+extern void cifs_dfs_release_automount_timer(void);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/dquot.c b/fs/dquot.c
index 41b9dbd68b0e..dfba1623cccb 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -289,7 +289,15 @@ static void wait_on_dquot(struct dquot *dquot)
mutex_unlock(&dquot->dq_lock);
}
-#define mark_dquot_dirty(dquot) ((dquot)->dq_sb->dq_op->mark_dirty(dquot))
+static inline int dquot_dirty(struct dquot *dquot)
+{
+ return test_bit(DQ_MOD_B, &dquot->dq_flags);
+}
+
+static inline int mark_dquot_dirty(struct dquot *dquot)
+{
+ return dquot->dq_sb->dq_op->mark_dirty(dquot);
+}
int dquot_mark_dquot_dirty(struct dquot *dquot)
{
@@ -1441,31 +1449,43 @@ static inline void set_enable_flags(struct quota_info *dqopt, int type)
switch (type) {
case USRQUOTA:
dqopt->flags |= DQUOT_USR_ENABLED;
+ dqopt->flags &= ~DQUOT_USR_SUSPENDED;
break;
case GRPQUOTA:
dqopt->flags |= DQUOT_GRP_ENABLED;
+ dqopt->flags &= ~DQUOT_GRP_SUSPENDED;
break;
}
}
-static inline void reset_enable_flags(struct quota_info *dqopt, int type)
+static inline void reset_enable_flags(struct quota_info *dqopt, int type,
+ int remount)
{
switch (type) {
case USRQUOTA:
dqopt->flags &= ~DQUOT_USR_ENABLED;
+ if (remount)
+ dqopt->flags |= DQUOT_USR_SUSPENDED;
+ else
+ dqopt->flags &= ~DQUOT_USR_SUSPENDED;
break;
case GRPQUOTA:
dqopt->flags &= ~DQUOT_GRP_ENABLED;
+ if (remount)
+ dqopt->flags |= DQUOT_GRP_SUSPENDED;
+ else
+ dqopt->flags &= ~DQUOT_GRP_SUSPENDED;
break;
}
}
+
/*
* Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
*/
-int vfs_quota_off(struct super_block *sb, int type)
+int vfs_quota_off(struct super_block *sb, int type, int remount)
{
- int cnt;
+ int cnt, ret = 0;
struct quota_info *dqopt = sb_dqopt(sb);
struct inode *toputinode[MAXQUOTAS];
@@ -1475,9 +1495,17 @@ int vfs_quota_off(struct super_block *sb, int type)
toputinode[cnt] = NULL;
if (type != -1 && cnt != type)
continue;
+ /* If we keep inodes of quota files after remount and quotaoff
+ * is called, drop kept inodes. */
+ if (!remount && sb_has_quota_suspended(sb, cnt)) {
+ iput(dqopt->files[cnt]);
+ dqopt->files[cnt] = NULL;
+ reset_enable_flags(dqopt, cnt, 0);
+ continue;
+ }
if (!sb_has_quota_enabled(sb, cnt))
continue;
- reset_enable_flags(dqopt, cnt);
+ reset_enable_flags(dqopt, cnt, remount);
/* Note: these are blocking operations */
drop_dquot_ref(sb, cnt);
@@ -1493,7 +1521,8 @@ int vfs_quota_off(struct super_block *sb, int type)
put_quota_format(dqopt->info[cnt].dqi_format);
toputinode[cnt] = dqopt->files[cnt];
- dqopt->files[cnt] = NULL;
+ if (!remount)
+ dqopt->files[cnt] = NULL;
dqopt->info[cnt].dqi_flags = 0;
dqopt->info[cnt].dqi_igrace = 0;
dqopt->info[cnt].dqi_bgrace = 0;
@@ -1523,12 +1552,19 @@ int vfs_quota_off(struct super_block *sb, int type)
mutex_unlock(&toputinode[cnt]->i_mutex);
mark_inode_dirty(toputinode[cnt]);
}
- iput(toputinode[cnt]);
mutex_unlock(&dqopt->dqonoff_mutex);
+ /* On remount RO, we keep the inode pointer so that we
+ * can reenable quota on the subsequent remount RW.
+ * But we have better not keep inode pointer when there
+ * is pending delete on the quota file... */
+ if (!remount)
+ iput(toputinode[cnt]);
+ else if (!toputinode[cnt]->i_nlink)
+ ret = -EBUSY;
}
if (sb->s_bdev)
invalidate_bdev(sb->s_bdev);
- return 0;
+ return ret;
}
/*
@@ -1566,7 +1602,8 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id)
invalidate_bdev(sb->s_bdev);
mutex_lock(&inode->i_mutex);
mutex_lock(&dqopt->dqonoff_mutex);
- if (sb_has_quota_enabled(sb, type)) {
+ if (sb_has_quota_enabled(sb, type) ||
+ sb_has_quota_suspended(sb, type)) {
error = -EBUSY;
goto out_lock;
}
@@ -1589,6 +1626,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id)
dqopt->ops[type] = fmt->qf_ops;
dqopt->info[type].dqi_format = fmt;
+ dqopt->info[type].dqi_fmt_id = format_id;
INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
mutex_lock(&dqopt->dqio_mutex);
if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) {
@@ -1624,12 +1662,41 @@ out_fmt:
return error;
}
+/* Reenable quotas on remount RW */
+static int vfs_quota_on_remount(struct super_block *sb, int type)
+{
+ struct quota_info *dqopt = sb_dqopt(sb);
+ struct inode *inode;
+ int ret;
+
+ mutex_lock(&dqopt->dqonoff_mutex);
+ if (!sb_has_quota_suspended(sb, type)) {
+ mutex_unlock(&dqopt->dqonoff_mutex);
+ return 0;
+ }
+ BUG_ON(sb_has_quota_enabled(sb, type));
+
+ inode = dqopt->files[type];
+ dqopt->files[type] = NULL;
+ reset_enable_flags(dqopt, type, 0);
+ mutex_unlock(&dqopt->dqonoff_mutex);
+
+ ret = vfs_quota_on_inode(inode, type, dqopt->info[type].dqi_fmt_id);
+ iput(inode);
+
+ return ret;
+}
+
/* Actual function called from quotactl() */
-int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
+int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path,
+ int remount)
{
struct nameidata nd;
int error;
+ if (remount)
+ return vfs_quota_on_remount(sb, type);
+
error = path_lookup(path, LOOKUP_FOLLOW, &nd);
if (error < 0)
return error;
@@ -1709,10 +1776,19 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
}
/* Generic routine for setting common part of quota structure */
-static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
{
struct mem_dqblk *dm = &dquot->dq_dqb;
int check_blim = 0, check_ilim = 0;
+ struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+
+ if ((di->dqb_valid & QIF_BLIMITS &&
+ (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
+ di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
+ (di->dqb_valid & QIF_ILIMITS &&
+ (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
+ di->dqb_isoftlimit > dqi->dqi_maxilimit)))
+ return -ERANGE;
spin_lock(&dq_data_lock);
if (di->dqb_valid & QIF_SPACE) {
@@ -1744,7 +1820,7 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
clear_bit(DQ_BLKS_B, &dquot->dq_flags);
}
else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */
- dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+ dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
}
if (check_ilim) {
if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
@@ -1752,7 +1828,7 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
clear_bit(DQ_INODES_B, &dquot->dq_flags);
}
else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */
- dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+ dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
}
if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
clear_bit(DQ_FAKE_B, &dquot->dq_flags);
@@ -1760,21 +1836,24 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
set_bit(DQ_FAKE_B, &dquot->dq_flags);
spin_unlock(&dq_data_lock);
mark_dquot_dirty(dquot);
+
+ return 0;
}
int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
{
struct dquot *dquot;
+ int rc;
mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
if (!(dquot = dqget(sb, id, type))) {
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
return -ESRCH;
}
- do_set_dqblk(dquot, di);
+ rc = do_set_dqblk(dquot, di);
dqput(dquot);
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
- return 0;
+ return rc;
}
/* Generic routine for getting common part of quota file information */
diff --git a/fs/exec.c b/fs/exec.c
index 54a0a557b678..b152029f18f6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
{
char * name;
int i, ch, retval;
- struct files_struct *files;
char tcomm[sizeof(current->comm)];
/*
@@ -965,26 +964,15 @@ int flush_old_exec(struct linux_binprm * bprm)
goto out;
/*
- * Make sure we have private file handles. Ask the
- * fork helper to do the work for us and the exit
- * helper to do the cleanup of the old one.
- */
- files = current->files; /* refcounted so safe to hold */
- retval = unshare_files();
- if (retval)
- goto out;
- /*
* Release all of the old mmap stuff
*/
retval = exec_mmap(bprm->mm);
if (retval)
- goto mmap_failed;
+ goto out;
bprm->mm = NULL; /* We're using it now */
/* This is the point of no return */
- put_files_struct(files);
-
current->sas_ss_sp = current->sas_ss_size = 0;
if (current->euid == current->uid && current->egid == current->gid)
@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)
return 0;
-mmap_failed:
- reset_files_struct(current, files);
out:
return retval;
}
@@ -1283,12 +1269,17 @@ int do_execve(char * filename,
struct linux_binprm *bprm;
struct file *file;
unsigned long env_p;
+ struct files_struct *displaced;
int retval;
+ retval = unshare_files(&displaced);
+ if (retval)
+ goto out_ret;
+
retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm)
- goto out_ret;
+ goto out_files;
file = open_exec(filename);
retval = PTR_ERR(file);
@@ -1343,6 +1334,8 @@ int do_execve(char * filename,
security_bprm_free(bprm);
acct_update_integrals(current);
kfree(bprm);
+ if (displaced)
+ put_files_struct(displaced);
return retval;
}
@@ -1363,6 +1356,9 @@ out_file:
out_kfree:
kfree(bprm);
+out_files:
+ if (displaced)
+ reset_files_struct(displaced);
out_ret:
return retval;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index e7b2bafa1dd9..10bb02c3f25c 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -106,7 +106,7 @@ static int ext2_valid_block_bitmap(struct super_block *sb,
return 1;
err_out:
- ext2_error(sb, __FUNCTION__,
+ ext2_error(sb, __func__,
"Invalid block bitmap - "
"block_group = %d, block = %lu",
block_group, bitmap_blk);
@@ -132,7 +132,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) {
- ext2_error(sb, __FUNCTION__,
+ ext2_error(sb, __func__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
@@ -143,17 +143,18 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
if (bh_submit_read(bh) < 0) {
brelse(bh);
- ext2_error(sb, __FUNCTION__,
+ ext2_error(sb, __func__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
return NULL;
}
- if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) {
- brelse(bh);
- return NULL;
- }
+ ext2_valid_block_bitmap(sb, desc, block_group, bh);
+ /*
+ * file system mounted not to panic on error, continue with corrupt
+ * bitmap
+ */
return bh;
}
@@ -245,11 +246,10 @@ restart:
prev = rsv;
}
printk("Window map complete.\n");
- if (bad)
- BUG();
+ BUG_ON(bad);
}
#define rsv_window_dump(root, verbose) \
- __rsv_window_dump((root), (verbose), __FUNCTION__)
+ __rsv_window_dump((root), (verbose), __func__)
#else
#define rsv_window_dump(root, verbose) do {} while (0)
#endif
@@ -548,7 +548,7 @@ do_more:
for (i = 0, group_freed = 0; i < count; i++) {
if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
bit + i, bitmap_bh->b_data)) {
- ext2_error(sb, __FUNCTION__,
+ ext2_error(sb, __func__,
"bit already cleared for block %lu", block + i);
} else {
group_freed++;
@@ -1381,7 +1381,12 @@ allocated:
"Allocating block in system zone - "
"blocks from "E2FSBLK", length %lu",
ret_block, num);
- goto out;
+ /*
+ * ext2_try_to_allocate marked the blocks we allocated as in
+ * use. So we may want to selectively mark some of the blocks
+ * as free
+ */
+ goto retry_alloc;
}
performed_allocation = 1;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 8dededd80fe2..a78c6b4af060 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -41,8 +41,8 @@ static inline __le16 ext2_rec_len_to_disk(unsigned len)
{
if (len == (1 << 16))
return cpu_to_le16(EXT2_MAX_REC_LEN);
- else if (len > (1 << 16))
- BUG();
+ else
+ BUG_ON(len > (1 << 16));
return cpu_to_le16(len);
}
@@ -295,11 +295,11 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
struct page *page = ext2_get_page(inode, n);
if (IS_ERR(page)) {
- ext2_error(sb, __FUNCTION__,
+ ext2_error(sb, __func__,
"bad page in #%lu",
inode->i_ino);
filp->f_pos += PAGE_CACHE_SIZE - offset;
- return -EIO;
+ return PTR_ERR(page);
}
kaddr = page_address(page);
if (unlikely(need_revalidate)) {
@@ -314,7 +314,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1);
for ( ;(char*)de <= limit; de = ext2_next_entry(de)) {
if (de->rec_len == 0) {
- ext2_error(sb, __FUNCTION__,
+ ext2_error(sb, __func__,
"zero-length directory entry");
ext2_put_page(page);
return -EIO;
@@ -381,7 +381,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
kaddr += ext2_last_byte(dir, n) - reclen;
while ((char *) de <= kaddr) {
if (de->rec_len == 0) {
- ext2_error(dir->i_sb, __FUNCTION__,
+ ext2_error(dir->i_sb, __func__,
"zero-length directory entry");
ext2_put_page(page);
goto out;
@@ -396,7 +396,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
n = 0;
/* next page is past the blocks we've got */
if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) {
- ext2_error(dir->i_sb, __FUNCTION__,
+ ext2_error(dir->i_sb, __func__,
"dir %lu size %lld exceeds block count %llu",
dir->i_ino, dir->i_size,
(unsigned long long)dir->i_blocks);
@@ -506,7 +506,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
goto got_it;
}
if (de->rec_len == 0) {
- ext2_error(dir->i_sb, __FUNCTION__,
+ ext2_error(dir->i_sb, __func__,
"zero-length directory entry");
err = -EIO;
goto out_unlock;
@@ -578,7 +578,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
while ((char*)de < (char*)dir) {
if (de->rec_len == 0) {
- ext2_error(inode->i_sb, __FUNCTION__,
+ ext2_error(inode->i_sb, __func__,
"zero-length directory entry");
err = -EIO;
goto out;
@@ -670,7 +670,7 @@ int ext2_empty_dir (struct inode * inode)
while ((char *)de <= kaddr) {
if (de->rec_len == 0) {
- ext2_error(inode->i_sb, __FUNCTION__,
+ ext2_error(inode->i_sb, __func__,
"zero-length directory entry");
printk("kaddr=%p, de=%p\n", kaddr, de);
goto not_empty;
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 08f647d8188d..f59741346760 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -75,11 +75,9 @@ static void ext2_release_inode(struct super_block *sb, int group, int dir)
}
spin_lock(sb_bgl_lock(EXT2_SB(sb), group));
- desc->bg_free_inodes_count =
- cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) + 1);
+ le16_add_cpu(&desc->bg_free_inodes_count, 1);
if (dir)
- desc->bg_used_dirs_count =
- cpu_to_le16(le16_to_cpu(desc->bg_used_dirs_count) - 1);
+ le16_add_cpu(&desc->bg_used_dirs_count, -1);
spin_unlock(sb_bgl_lock(EXT2_SB(sb), group));
if (dir)
percpu_counter_dec(&EXT2_SB(sb)->s_dirs_counter);
@@ -539,13 +537,11 @@ got:
percpu_counter_inc(&sbi->s_dirs_counter);
spin_lock(sb_bgl_lock(sbi, group));
- gdp->bg_free_inodes_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
+ le16_add_cpu(&gdp->bg_free_inodes_count, -1);
if (S_ISDIR(mode)) {
if (sbi->s_debts[group] < 255)
sbi->s_debts[group]++;
- gdp->bg_used_dirs_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
+ le16_add_cpu(&gdp->bg_used_dirs_count, 1);
} else {
if (sbi->s_debts[group])
sbi->s_debts[group]--;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index b8a2990bab83..384fc0d1dd74 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -254,13 +254,13 @@ no_block:
* Caller must make sure that @ind is valid and will stay that way.
*/
-static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
+static ext2_fsblk_t ext2_find_near(struct inode *inode, Indirect *ind)
{
struct ext2_inode_info *ei = EXT2_I(inode);
__le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;
__le32 *p;
- unsigned long bg_start;
- unsigned long colour;
+ ext2_fsblk_t bg_start;
+ ext2_fsblk_t colour;
/* Try to find previous block */
for (p = ind->p - 1; p >= start; p--)
@@ -275,8 +275,7 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
* It is going to be refered from inode itself? OK, just put it into
* the same cylinder group then.
*/
- bg_start = (ei->i_block_group * EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
- le32_to_cpu(EXT2_SB(inode->i_sb)->s_es->s_first_data_block);
+ bg_start = ext2_group_first_block_no(inode->i_sb, ei->i_block_group);
colour = (current->pid % 16) *
(EXT2_BLOCKS_PER_GROUP(inode->i_sb) / 16);
return bg_start + colour;
@@ -291,8 +290,8 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
* Returns preferred place for a block (the goal).
*/
-static inline int ext2_find_goal(struct inode *inode, long block,
- Indirect *partial)
+static inline ext2_fsblk_t ext2_find_goal(struct inode *inode, long block,
+ Indirect *partial)
{
struct ext2_block_alloc_info *block_i;
@@ -796,7 +795,7 @@ const struct address_space_operations ext2_aops = {
const struct address_space_operations ext2_aops_xip = {
.bmap = ext2_bmap,
- .get_xip_page = ext2_get_xip_page,
+ .get_xip_mem = ext2_get_xip_mem,
};
const struct address_space_operations ext2_nobh_aops = {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 088b011bb97e..ef50cbc792db 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -51,8 +51,7 @@ void ext2_error (struct super_block * sb, const char * function,
if (!(sb->s_flags & MS_RDONLY)) {
sbi->s_mount_state |= EXT2_ERROR_FS;
- es->s_state =
- cpu_to_le16(le16_to_cpu(es->s_state) | EXT2_ERROR_FS);
+ es->s_state |= cpu_to_le16(EXT2_ERROR_FS);
ext2_sync_super(sb, es);
}
@@ -90,7 +89,7 @@ void ext2_update_dynamic_rev(struct super_block *sb)
if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
return;
- ext2_warning(sb, __FUNCTION__,
+ ext2_warning(sb, __func__,
"updating to rev %d because of new feature flag, "
"running e2fsck is recommended",
EXT2_DYNAMIC_REV);
@@ -604,7 +603,7 @@ static int ext2_setup_super (struct super_block * sb,
"running e2fsck is recommended\n");
if (!le16_to_cpu(es->s_max_mnt_count))
es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
- es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+ le16_add_cpu(&es->s_mnt_count, 1);
ext2_write_super(sb);
if (test_opt (sb, DEBUG))
printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
@@ -622,13 +621,13 @@ static int ext2_check_descriptors(struct super_block *sb)
{
int i;
struct ext2_sb_info *sbi = EXT2_SB(sb);
- unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
- unsigned long last_block;
ext2_debug ("Checking group descriptors");
for (i = 0; i < sbi->s_groups_count; i++) {
struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL);
+ ext2_fsblk_t first_block = ext2_group_first_block_no(sb, i);
+ ext2_fsblk_t last_block;
if (i == sbi->s_groups_count - 1)
last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
@@ -664,7 +663,6 @@ static int ext2_check_descriptors(struct super_block *sb)
i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
return 0;
}
- first_block += EXT2_BLOCKS_PER_GROUP(sb);
}
return 1;
}
@@ -721,10 +719,9 @@ static unsigned long descriptor_loc(struct super_block *sb,
int nr)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
- unsigned long bg, first_data_block, first_meta_bg;
+ unsigned long bg, first_meta_bg;
int has_super = 0;
- first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) ||
@@ -733,7 +730,8 @@ static unsigned long descriptor_loc(struct super_block *sb,
bg = sbi->s_desc_per_block * nr;
if (ext2_bg_has_super(sb, bg))
has_super = 1;
- return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
+
+ return ext2_group_first_block_no(sb, bg) + has_super;
}
static int ext2_fill_super(struct super_block *sb, void *data, int silent)
@@ -1062,7 +1060,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount3;
}
if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
- ext2_warning(sb, __FUNCTION__,
+ ext2_warning(sb, __func__,
"mounting ext3 filesystem as ext2");
ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
return 0;
@@ -1126,10 +1124,9 @@ void ext2_write_super (struct super_block * sb)
if (!(sb->s_flags & MS_RDONLY)) {
es = EXT2_SB(sb)->s_es;
- if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) {
+ if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) {
ext2_debug ("setting valid to 0\n");
- es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) &
- ~EXT2_VALID_FS);
+ es->s_state &= cpu_to_le16(~EXT2_VALID_FS);
es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb));
es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb));
es->s_mtime = cpu_to_le32(get_seconds());
@@ -1180,7 +1177,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
(old_mount_opt & EXT2_MOUNT_XIP)) &&
invalidate_inodes(sb))
- ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
+ ext2_warning(sb, __func__, "busy inodes while remounting "\
"xip remain in cache (no functional problem)");
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0;
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index a99d46f3b26e..987a5261cc2e 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -646,8 +646,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
unlock_buffer(new_bh);
goto cleanup;
}
- HDR(new_bh)->h_refcount = cpu_to_le32(1 +
- le32_to_cpu(HDR(new_bh)->h_refcount));
+ le32_add_cpu(&HDR(new_bh)->h_refcount, 1);
ea_bdebug(new_bh, "refcount now=%d",
le32_to_cpu(HDR(new_bh)->h_refcount));
}
@@ -660,10 +659,8 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
ext2_xattr_cache_insert(new_bh);
} else {
/* We need to allocate a new block */
- int goal = le32_to_cpu(EXT2_SB(sb)->s_es->
- s_first_data_block) +
- EXT2_I(inode)->i_block_group *
- EXT2_BLOCKS_PER_GROUP(sb);
+ ext2_fsblk_t goal = ext2_group_first_block_no(sb,
+ EXT2_I(inode)->i_block_group);
int block = ext2_new_block(inode, goal, &error);
if (error)
goto cleanup;
@@ -731,8 +728,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
bforget(old_bh);
} else {
/* Decrement the refcount only. */
- HDR(old_bh)->h_refcount = cpu_to_le32(
- le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
+ le32_add_cpu(&HDR(old_bh)->h_refcount, -1);
if (ce)
mb_cache_entry_release(ce);
DQUOT_FREE_BLOCK(inode, 1);
@@ -789,8 +785,7 @@ ext2_xattr_delete_inode(struct inode *inode)
bforget(bh);
unlock_buffer(bh);
} else {
- HDR(bh)->h_refcount = cpu_to_le32(
- le32_to_cpu(HDR(bh)->h_refcount) - 1);
+ le32_add_cpu(&HDR(bh)->h_refcount, -1);
if (ce)
mb_cache_entry_release(ce);
ea_bdebug(bh, "refcount now=%d",
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
index ca7f00312388..4fb94c20041b 100644
--- a/fs/ext2/xip.c
+++ b/fs/ext2/xip.c
@@ -15,24 +15,28 @@
#include "xip.h"
static inline int
-__inode_direct_access(struct inode *inode, sector_t sector,
- unsigned long *data)
+__inode_direct_access(struct inode *inode, sector_t block,
+ void **kaddr, unsigned long *pfn)
{
- BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
- return inode->i_sb->s_bdev->bd_disk->fops
- ->direct_access(inode->i_sb->s_bdev,sector,data);
+ struct block_device *bdev = inode->i_sb->s_bdev;
+ struct block_device_operations *ops = bdev->bd_disk->fops;
+ sector_t sector;
+
+ sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
+
+ BUG_ON(!ops->direct_access);
+ return ops->direct_access(bdev, sector, kaddr, pfn);
}
static inline int
-__ext2_get_sector(struct inode *inode, sector_t offset, int create,
+__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
sector_t *result)
{
struct buffer_head tmp;
int rc;
memset(&tmp, 0, sizeof(struct buffer_head));
- rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &tmp,
- create);
+ rc = ext2_get_block(inode, pgoff, &tmp, create);
*result = tmp.b_blocknr;
/* did we get a sparse block (hole in the file)? */
@@ -45,15 +49,15 @@ __ext2_get_sector(struct inode *inode, sector_t offset, int create,
}
int
-ext2_clear_xip_target(struct inode *inode, int block)
+ext2_clear_xip_target(struct inode *inode, sector_t block)
{
- sector_t sector = block * (PAGE_SIZE/512);
- unsigned long data;
+ void *kaddr;
+ unsigned long pfn;
int rc;
- rc = __inode_direct_access(inode, sector, &data);
+ rc = __inode_direct_access(inode, block, &kaddr, &pfn);
if (!rc)
- clear_page((void*)data);
+ clear_page(kaddr);
return rc;
}
@@ -64,30 +68,23 @@ void ext2_xip_verify_sb(struct super_block *sb)
if ((sbi->s_mount_opt & EXT2_MOUNT_XIP) &&
!sb->s_bdev->bd_disk->fops->direct_access) {
sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
- ext2_warning(sb, __FUNCTION__,
+ ext2_warning(sb, __func__,
"ignoring xip option - not supported by bdev");
}
}
-struct page *
-ext2_get_xip_page(struct address_space *mapping, sector_t offset,
- int create)
+int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create,
+ void **kmem, unsigned long *pfn)
{
int rc;
- unsigned long data;
- sector_t sector;
+ sector_t block;
/* first, retrieve the sector number */
- rc = __ext2_get_sector(mapping->host, offset, create, &sector);
+ rc = __ext2_get_block(mapping->host, pgoff, create, &block);
if (rc)
- goto error;
+ return rc;
/* retrieve address of the target data */
- rc = __inode_direct_access
- (mapping->host, sector * (PAGE_SIZE/512), &data);
- if (!rc)
- return virt_to_page(data);
-
- error:
- return ERR_PTR(rc);
+ rc = __inode_direct_access(mapping->host, block, kmem, pfn);
+ return rc;
}
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h
index aa85331d6c56..18b34d2f31b3 100644
--- a/fs/ext2/xip.h
+++ b/fs/ext2/xip.h
@@ -7,19 +7,20 @@
#ifdef CONFIG_EXT2_FS_XIP
extern void ext2_xip_verify_sb (struct super_block *);
-extern int ext2_clear_xip_target (struct inode *, int);
+extern int ext2_clear_xip_target (struct inode *, sector_t);
static inline int ext2_use_xip (struct super_block *sb)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
}
-struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
-#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+int ext2_get_xip_mem(struct address_space *, pgoff_t, int,
+ void **, unsigned long *);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_mem)
#else
#define mapping_is_xip(map) 0
#define ext2_xip_verify_sb(sb) do { } while (0)
#define ext2_use_xip(sb) 0
#define ext2_clear_xip_target(inode, chain) 0
-#define ext2_get_xip_page NULL
+#define ext2_get_xip_mem NULL
#endif
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index da0cb2c0e437..92fd0338a6eb 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -117,7 +117,7 @@ static int ext3_valid_block_bitmap(struct super_block *sb,
return 1;
err_out:
- ext3_error(sb, __FUNCTION__,
+ ext3_error(sb, __func__,
"Invalid block bitmap - "
"block_group = %d, block = %lu",
block_group, bitmap_blk);
@@ -147,7 +147,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) {
- ext3_error(sb, __FUNCTION__,
+ ext3_error(sb, __func__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
@@ -158,16 +158,17 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
if (bh_submit_read(bh) < 0) {
brelse(bh);
- ext3_error(sb, __FUNCTION__,
+ ext3_error(sb, __func__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
return NULL;
}
- if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) {
- brelse(bh);
- return NULL;
- }
+ ext3_valid_block_bitmap(sb, desc, block_group, bh);
+ /*
+ * file system mounted not to panic on error, continue with corrupt
+ * bitmap
+ */
return bh;
}
/*
@@ -232,11 +233,10 @@ restart:
prev = rsv;
}
printk("Window map complete.\n");
- if (bad)
- BUG();
+ BUG_ON(bad);
}
#define rsv_window_dump(root, verbose) \
- __rsv_window_dump((root), (verbose), __FUNCTION__)
+ __rsv_window_dump((root), (verbose), __func__)
#else
#define rsv_window_dump(root, verbose) do {} while (0)
#endif
@@ -618,7 +618,7 @@ do_more:
if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
bit + i, bitmap_bh->b_data)) {
jbd_unlock_bh_state(bitmap_bh);
- ext3_error(sb, __FUNCTION__,
+ ext3_error(sb, __func__,
"bit already cleared for block "E3FSBLK,
block + i);
jbd_lock_bh_state(bitmap_bh);
@@ -1642,7 +1642,11 @@ allocated:
"Allocating block in system zone - "
"blocks from "E3FSBLK", length %lu",
ret_block, num);
- goto out;
+ /*
+ * claim_block() marked the blocks we allocated as in use. So we
+ * may want to selectively mark some of the blocks as free.
+ */
+ goto retry_alloc;
}
performed_allocation = 1;
@@ -1668,7 +1672,7 @@ allocated:
if (ext3_test_bit(grp_alloc_blk+i,
bh2jh(bitmap_bh)->b_committed_data)) {
printk("%s: block was unexpectedly set in "
- "b_committed_data\n", __FUNCTION__);
+ "b_committed_data\n", __func__);
}
}
}
diff --git a/fs/ext3/ext3_jbd.c b/fs/ext3/ext3_jbd.c
index e1f91fd26a93..d401f148d74d 100644
--- a/fs/ext3/ext3_jbd.c
+++ b/fs/ext3/ext3_jbd.c
@@ -9,7 +9,7 @@ int __ext3_journal_get_undo_access(const char *where, handle_t *handle,
{
int err = journal_get_undo_access(handle, bh);
if (err)
- ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext3_journal_abort_handle(where, __func__, bh, handle,err);
return err;
}
@@ -18,7 +18,7 @@ int __ext3_journal_get_write_access(const char *where, handle_t *handle,
{
int err = journal_get_write_access(handle, bh);
if (err)
- ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext3_journal_abort_handle(where, __func__, bh, handle,err);
return err;
}
@@ -27,7 +27,7 @@ int __ext3_journal_forget(const char *where, handle_t *handle,
{
int err = journal_forget(handle, bh);
if (err)
- ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext3_journal_abort_handle(where, __func__, bh, handle,err);
return err;
}
@@ -36,7 +36,7 @@ int __ext3_journal_revoke(const char *where, handle_t *handle,
{
int err = journal_revoke(handle, blocknr, bh);
if (err)
- ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext3_journal_abort_handle(where, __func__, bh, handle,err);
return err;
}
@@ -45,7 +45,7 @@ int __ext3_journal_get_create_access(const char *where,
{
int err = journal_get_create_access(handle, bh);
if (err)
- ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext3_journal_abort_handle(where, __func__, bh, handle,err);
return err;
}
@@ -54,6 +54,6 @@ int __ext3_journal_dirty_metadata(const char *where,
{
int err = journal_dirty_metadata(handle, bh);
if (err)
- ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext3_journal_abort_handle(where, __func__, bh, handle,err);
return err;
}
diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c
index a588e23841d4..d33634119e17 100644
--- a/fs/ext3/fsync.c
+++ b/fs/ext3/fsync.c
@@ -72,6 +72,9 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync)
goto out;
}
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ goto out;
+
/*
* The VFS has written the file data. If the inode is unaltered
* then we need not start a commit.
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 96dd5573e49b..77126821b2e9 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -644,7 +644,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
/* Error cases - e2fsck has already cleaned up for us */
if (ino > max_ino) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"bad orphan ino %lu! e2fsck was run?", ino);
goto error;
}
@@ -653,7 +653,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb);
bitmap_bh = read_inode_bitmap(sb, block_group);
if (!bitmap_bh) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"inode bitmap error for orphan %lu", ino);
goto error;
}
@@ -678,7 +678,7 @@ iget_failed:
err = PTR_ERR(inode);
inode = NULL;
bad_orphan:
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"bad orphan inode %lu! e2fsck was run?", ino);
printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
bit, (unsigned long long)bitmap_bh->b_blocknr,
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index c683609b0e3a..cc47b76091bf 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -95,7 +95,7 @@ int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
BUFFER_TRACE(bh, "call ext3_journal_revoke");
err = ext3_journal_revoke(handle, blocknr, bh);
if (err)
- ext3_abort(inode->i_sb, __FUNCTION__,
+ ext3_abort(inode->i_sb, __func__,
"error %d when attempting revoke", err);
BUFFER_TRACE(bh, "exit");
return err;
@@ -1190,7 +1190,7 @@ int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
{
int err = journal_dirty_data(handle, bh);
if (err)
- ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__,
+ ext3_journal_abort_handle(__func__, __func__,
bh, handle, err);
return err;
}
@@ -2454,11 +2454,10 @@ out_stop:
static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
unsigned long ino, struct ext3_iloc *iloc)
{
- unsigned long desc, group_desc, block_group;
+ unsigned long block_group;
unsigned long offset;
ext3_fsblk_t block;
- struct buffer_head *bh;
- struct ext3_group_desc * gdp;
+ struct ext3_group_desc *gdp;
if (!ext3_valid_inum(sb, ino)) {
/*
@@ -2470,27 +2469,15 @@ static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
}
block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
- if (block_group >= EXT3_SB(sb)->s_groups_count) {
- ext3_error(sb,"ext3_get_inode_block","group >= groups count");
- return 0;
- }
- smp_rmb();
- group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb);
- desc = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1);
- bh = EXT3_SB(sb)->s_group_desc[group_desc];
- if (!bh) {
- ext3_error (sb, "ext3_get_inode_block",
- "Descriptor not loaded");
+ gdp = ext3_get_group_desc(sb, block_group, NULL);
+ if (!gdp)
return 0;
- }
-
- gdp = (struct ext3_group_desc *)bh->b_data;
/*
* Figure out the offset within the block group inode table
*/
offset = ((ino - 1) % EXT3_INODES_PER_GROUP(sb)) *
EXT3_INODE_SIZE(sb);
- block = le32_to_cpu(gdp[desc].bg_inode_table) +
+ block = le32_to_cpu(gdp->bg_inode_table) +
(offset >> EXT3_BLOCK_SIZE_BITS(sb));
iloc->block_group = block_group;
@@ -3214,7 +3201,7 @@ void ext3_dirty_inode(struct inode *inode)
current_handle->h_transaction != handle->h_transaction) {
/* This task has a transaction open against a different fs */
printk(KERN_EMERG "%s: transactions do not match!\n",
- __FUNCTION__);
+ __func__);
} else {
jbd_debug(5, "marking dirty. outer handle=%p\n",
current_handle);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index dec3e0d88ab1..0b8cf80154f1 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -57,10 +57,15 @@ static struct buffer_head *ext3_append(handle_t *handle,
*block = inode->i_size >> inode->i_sb->s_blocksize_bits;
- if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
+ bh = ext3_bread(handle, inode, *block, 1, err);
+ if (bh) {
inode->i_size += inode->i_sb->s_blocksize;
EXT3_I(inode)->i_disksize = inode->i_size;
- ext3_journal_get_write_access(handle,bh);
+ *err = ext3_journal_get_write_access(handle, bh);
+ if (*err) {
+ brelse(bh);
+ bh = NULL;
+ }
}
return bh;
}
@@ -356,7 +361,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
if (root->info.hash_version != DX_HASH_TEA &&
root->info.hash_version != DX_HASH_HALF_MD4 &&
root->info.hash_version != DX_HASH_LEGACY) {
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"Unrecognised inode hash code %d",
root->info.hash_version);
brelse(bh);
@@ -370,7 +375,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
hash = hinfo->hash;
if (root->info.unused_flags & 1) {
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"Unimplemented inode hash flags: %#06x",
root->info.unused_flags);
brelse(bh);
@@ -379,7 +384,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
}
if ((indirect = root->info.indirect_levels) > 1) {
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"Unimplemented inode hash depth: %#06x",
root->info.indirect_levels);
brelse(bh);
@@ -392,7 +397,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
if (dx_get_limit(entries) != dx_root_limit(dir,
root->info.info_length)) {
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"dx entry: limit != root limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
@@ -404,7 +409,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
{
count = dx_get_count(entries);
if (!count || count > dx_get_limit(entries)) {
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"dx entry: no count or count > limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
@@ -449,7 +454,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
goto fail2;
at = entries = ((struct dx_node *) bh->b_data)->entries;
if (dx_get_limit(entries) != dx_node_limit (dir)) {
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"dx entry: limit != node limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
@@ -465,7 +470,7 @@ fail2:
}
fail:
if (*err == ERR_BAD_DX_DIR)
- ext3_warning(dir->i_sb, __FUNCTION__,
+ ext3_warning(dir->i_sb, __func__,
"Corrupt dir inode %ld, running e2fsck is "
"recommended.", dir->i_ino);
return NULL;
@@ -913,7 +918,7 @@ restart:
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
/* read error, skip block & hope for the best */
- ext3_error(sb, __FUNCTION__, "reading directory #%lu "
+ ext3_error(sb, __func__, "reading directory #%lu "
"offset %lu", dir->i_ino, block);
brelse(bh);
goto next;
@@ -1005,7 +1010,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
retval = ext3_htree_next_block(dir, hash, frame,
frames, NULL);
if (retval < 0) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"error reading index page in directory #%lu",
dir->i_ino);
*err = retval;
@@ -1530,7 +1535,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
if (levels && (dx_get_count(frames->entries) ==
dx_get_limit(frames->entries))) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Directory index full!");
err = -ENOSPC;
goto cleanup;
@@ -1832,11 +1837,11 @@ static int empty_dir (struct inode * inode)
if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) ||
!(bh = ext3_bread (NULL, inode, 0, 0, &err))) {
if (err)
- ext3_error(inode->i_sb, __FUNCTION__,
+ ext3_error(inode->i_sb, __func__,
"error %d reading directory #%lu offset 0",
err, inode->i_ino);
else
- ext3_warning(inode->i_sb, __FUNCTION__,
+ ext3_warning(inode->i_sb, __func__,
"bad directory (dir #%lu) - no data block",
inode->i_ino);
return 1;
@@ -1865,7 +1870,7 @@ static int empty_dir (struct inode * inode)
offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err);
if (!bh) {
if (err)
- ext3_error(sb, __FUNCTION__,
+ ext3_error(sb, __func__,
"error %d reading directory"
" #%lu offset %lu",
err, inode->i_ino, offset);
@@ -2318,6 +2323,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
EXT3_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
new_dir->i_version++;
+ new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME_SEC;
+ ext3_mark_inode_dirty(handle, new_dir);
BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata");
ext3_journal_dirty_metadata(handle, new_bh);
brelse(new_bh);
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 0e97b6e07cb0..28cfd0b40527 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -48,60 +48,60 @@ static int verify_group_input(struct super_block *sb,
free_blocks_count, input->reserved_blocks);
if (group != sbi->s_groups_count)
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Cannot add at group %u (only %lu groups)",
input->group, sbi->s_groups_count);
else if ((start - le32_to_cpu(es->s_first_data_block)) %
EXT3_BLOCKS_PER_GROUP(sb))
- ext3_warning(sb, __FUNCTION__, "Last group not full");
+ ext3_warning(sb, __func__, "Last group not full");
else if (input->reserved_blocks > input->blocks_count / 5)
- ext3_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",
+ ext3_warning(sb, __func__, "Reserved blocks too high (%u)",
input->reserved_blocks);
else if (free_blocks_count < 0)
- ext3_warning(sb, __FUNCTION__, "Bad blocks count %u",
+ ext3_warning(sb, __func__, "Bad blocks count %u",
input->blocks_count);
else if (!(bh = sb_bread(sb, end - 1)))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Cannot read last block ("E3FSBLK")",
end - 1);
else if (outside(input->block_bitmap, start, end))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Block bitmap not in group (block %u)",
input->block_bitmap);
else if (outside(input->inode_bitmap, start, end))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Inode bitmap not in group (block %u)",
input->inode_bitmap);
else if (outside(input->inode_table, start, end) ||
outside(itend - 1, start, end))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Inode table not in group (blocks %u-"E3FSBLK")",
input->inode_table, itend - 1);
else if (input->inode_bitmap == input->block_bitmap)
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Block bitmap same as inode bitmap (%u)",
input->block_bitmap);
else if (inside(input->block_bitmap, input->inode_table, itend))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Block bitmap (%u) in inode table (%u-"E3FSBLK")",
input->block_bitmap, input->inode_table, itend-1);
else if (inside(input->inode_bitmap, input->inode_table, itend))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Inode bitmap (%u) in inode table (%u-"E3FSBLK")",
input->inode_bitmap, input->inode_table, itend-1);
else if (inside(input->block_bitmap, start, metaend))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Block bitmap (%u) in GDT table"
" ("E3FSBLK"-"E3FSBLK")",
input->block_bitmap, start, metaend - 1);
else if (inside(input->inode_bitmap, start, metaend))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Inode bitmap (%u) in GDT table"
" ("E3FSBLK"-"E3FSBLK")",
input->inode_bitmap, start, metaend - 1);
else if (inside(input->inode_table, start, metaend) ||
inside(itend - 1, start, metaend))
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Inode table (%u-"E3FSBLK") overlaps"
"GDT table ("E3FSBLK"-"E3FSBLK")",
input->inode_table, itend - 1, start, metaend - 1);
@@ -386,7 +386,7 @@ static int verify_reserved_gdb(struct super_block *sb,
while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"reserved GDT "E3FSBLK
" missing grp %d ("E3FSBLK")",
blk, grp,
@@ -440,7 +440,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
*/
if (EXT3_SB(sb)->s_sbh->b_blocknr !=
le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"won't resize using backup superblock at %llu",
(unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr);
return -EPERM;
@@ -464,7 +464,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
data = (__le32 *)dind->b_data;
if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"new group %u GDT block "E3FSBLK" not reserved",
input->group, gdblock);
err = -EINVAL;
@@ -488,7 +488,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
GFP_NOFS);
if (!n_group_desc) {
err = -ENOMEM;
- ext3_warning (sb, __FUNCTION__,
+ ext3_warning (sb, __func__,
"not enough memory for %lu groups", gdb_num + 1);
goto exit_inode;
}
@@ -586,7 +586,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
/* Get each reserved primary GDT block and verify it holds backups */
for (res = 0; res < reserved_gdb; res++, blk++) {
if (le32_to_cpu(*data) != blk) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"reserved block "E3FSBLK
" not at offset %ld",
blk,
@@ -730,7 +730,7 @@ static void update_backups(struct super_block *sb,
*/
exit_err:
if (err) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"can't update backup for group %d (err %d), "
"forcing fsck on next reboot", group, err);
sbi->s_mount_state &= ~EXT3_VALID_FS;
@@ -770,33 +770,33 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb,
EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Can't resize non-sparse filesystem further");
return -EPERM;
}
if (le32_to_cpu(es->s_blocks_count) + input->blocks_count <
le32_to_cpu(es->s_blocks_count)) {
- ext3_warning(sb, __FUNCTION__, "blocks_count overflow\n");
+ ext3_warning(sb, __func__, "blocks_count overflow\n");
return -EINVAL;
}
if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) <
le32_to_cpu(es->s_inodes_count)) {
- ext3_warning(sb, __FUNCTION__, "inodes_count overflow\n");
+ ext3_warning(sb, __func__, "inodes_count overflow\n");
return -EINVAL;
}
if (reserved_gdb || gdb_off == 0) {
if (!EXT3_HAS_COMPAT_FEATURE(sb,
EXT3_FEATURE_COMPAT_RESIZE_INODE)){
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"No reserved GDT blocks, can't resize");
return -EPERM;
}
inode = ext3_iget(sb, EXT3_RESIZE_INO);
if (IS_ERR(inode)) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"Error opening resize inode");
return PTR_ERR(inode);
}
@@ -825,7 +825,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
lock_super(sb);
if (input->group != sbi->s_groups_count) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"multiple resizers run on filesystem!");
err = -EBUSY;
goto exit_journal;
@@ -988,13 +988,13 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
" too large to resize to %lu blocks safely\n",
sb->s_id, n_blocks_count);
if (sizeof(sector_t) < 8)
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"CONFIG_LBD not enabled\n");
return -EINVAL;
}
if (n_blocks_count < o_blocks_count) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"can't shrink FS - resize aborted");
return -EBUSY;
}
@@ -1004,7 +1004,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
EXT3_BLOCKS_PER_GROUP(sb);
if (last == 0) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"need to use ext2online to resize further");
return -EPERM;
}
@@ -1012,7 +1012,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
add = EXT3_BLOCKS_PER_GROUP(sb) - last;
if (o_blocks_count + add < o_blocks_count) {
- ext3_warning(sb, __FUNCTION__, "blocks_count overflow");
+ ext3_warning(sb, __func__, "blocks_count overflow");
return -EINVAL;
}
@@ -1020,7 +1020,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
add = n_blocks_count - o_blocks_count;
if (o_blocks_count + add < n_blocks_count)
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"will only finish group ("E3FSBLK
" blocks, %u new)",
o_blocks_count + add, add);
@@ -1028,7 +1028,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
/* See if the device is actually as big as what was requested */
bh = sb_bread(sb, o_blocks_count + add -1);
if (!bh) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"can't read last block, resize aborted");
return -ENOSPC;
}
@@ -1040,22 +1040,23 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
handle = ext3_journal_start_sb(sb, 3);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
- ext3_warning(sb, __FUNCTION__, "error %d on journal start",err);
+ ext3_warning(sb, __func__, "error %d on journal start",err);
goto exit_put;
}
lock_super(sb);
if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"multiple resizers run on filesystem!");
unlock_super(sb);
+ ext3_journal_stop(handle);
err = -EBUSY;
goto exit_put;
}
if ((err = ext3_journal_get_write_access(handle,
EXT3_SB(sb)->s_sbh))) {
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"error %d on journal write access", err);
unlock_super(sb);
ext3_journal_stop(handle);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ad5360664082..fe3119a71ada 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -84,7 +84,7 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
* take the FS itself readonly cleanly. */
journal = EXT3_SB(sb)->s_journal;
if (is_journal_aborted(journal)) {
- ext3_abort(sb, __FUNCTION__,
+ ext3_abort(sb, __func__,
"Detected aborted journal");
return ERR_PTR(-EROFS);
}
@@ -304,7 +304,7 @@ void ext3_update_dynamic_rev(struct super_block *sb)
if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV)
return;
- ext3_warning(sb, __FUNCTION__,
+ ext3_warning(sb, __func__,
"updating to rev %d because of new feature flag, "
"running e2fsck is recommended",
EXT3_DYNAMIC_REV);
@@ -685,7 +685,8 @@ static int ext3_acquire_dquot(struct dquot *dquot);
static int ext3_release_dquot(struct dquot *dquot);
static int ext3_mark_dquot_dirty(struct dquot *dquot);
static int ext3_write_info(struct super_block *sb, int type);
-static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path);
+static int ext3_quota_on(struct super_block *sb, int type, int format_id,
+ char *path, int remount);
static int ext3_quota_on_mount(struct super_block *sb, int type);
static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
@@ -1096,6 +1097,9 @@ clear_qf_name:
case Opt_quota:
case Opt_usrquota:
case Opt_grpquota:
+ printk(KERN_ERR
+ "EXT3-fs: quota options not supported.\n");
+ break;
case Opt_usrjquota:
case Opt_grpjquota:
case Opt_offusrjquota:
@@ -1103,7 +1107,7 @@ clear_qf_name:
case Opt_jqfmt_vfsold:
case Opt_jqfmt_vfsv0:
printk(KERN_ERR
- "EXT3-fs: journalled quota options not "
+ "EXT3-fs: journaled quota options not "
"supported.\n");
break;
case Opt_noquota:
@@ -1218,7 +1222,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
inconsistencies, to force a fsck at reboot. But for
a plain journaled filesystem we can keep it set as
valid forever! :) */
- es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS);
+ es->s_state &= cpu_to_le16(~EXT3_VALID_FS);
#endif
if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT);
@@ -1253,14 +1257,14 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
static int ext3_check_descriptors(struct super_block *sb)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
- ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
- ext3_fsblk_t last_block;
int i;
ext3_debug ("Checking group descriptors");
for (i = 0; i < sbi->s_groups_count; i++) {
struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL);
+ ext3_fsblk_t first_block = ext3_group_first_block_no(sb, i);
+ ext3_fsblk_t last_block;
if (i == sbi->s_groups_count - 1)
last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
@@ -1299,7 +1303,6 @@ static int ext3_check_descriptors(struct super_block *sb)
le32_to_cpu(gdp->bg_inode_table));
return 0;
}
- first_block += EXT3_BLOCKS_PER_GROUP(sb);
}
sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb));
@@ -1387,7 +1390,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
if (inode->i_nlink) {
printk(KERN_DEBUG
"%s: truncating inode %lu to %Ld bytes\n",
- __FUNCTION__, inode->i_ino, inode->i_size);
+ __func__, inode->i_ino, inode->i_size);
jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
inode->i_ino, inode->i_size);
ext3_truncate(inode);
@@ -1395,7 +1398,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
} else {
printk(KERN_DEBUG
"%s: deleting unreferenced inode %lu\n",
- __FUNCTION__, inode->i_ino);
+ __func__, inode->i_ino);
jbd_debug(2, "deleting unreferenced inode %lu\n",
inode->i_ino);
nr_orphans++;
@@ -1415,7 +1418,7 @@ static void ext3_orphan_cleanup (struct super_block * sb,
/* Turn quotas off */
for (i = 0; i < MAXQUOTAS; i++) {
if (sb_dqopt(sb)->files[i])
- vfs_quota_off(sb, i);
+ vfs_quota_off(sb, i, 0);
}
#endif
sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -2298,9 +2301,9 @@ static void ext3_clear_journal_err(struct super_block * sb,
char nbuf[16];
errstr = ext3_decode_error(sb, j_errno, nbuf);
- ext3_warning(sb, __FUNCTION__, "Filesystem error recorded "
+ ext3_warning(sb, __func__, "Filesystem error recorded "
"from previous mount: %s", errstr);
- ext3_warning(sb, __FUNCTION__, "Marking fs in need of "
+ ext3_warning(sb, __func__, "Marking fs in need of "
"filesystem check.");
EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
@@ -2427,7 +2430,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
}
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
- ext3_abort(sb, __FUNCTION__, "Abort forced by user");
+ ext3_abort(sb, __func__, "Abort forced by user");
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
@@ -2639,8 +2642,14 @@ static int ext3_dquot_drop(struct inode *inode)
/* We may delete quota structure so we need to reserve enough blocks */
handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb));
- if (IS_ERR(handle))
+ if (IS_ERR(handle)) {
+ /*
+ * We call dquot_drop() anyway to at least release references
+ * to quota structures so that umount does not hang.
+ */
+ dquot_drop(inode);
return PTR_ERR(handle);
+ }
ret = dquot_drop(inode);
err = ext3_journal_stop(handle);
if (!ret)
@@ -2743,17 +2752,17 @@ static int ext3_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int ext3_quota_on(struct super_block *sb, int type, int format_id,
- char *path)
+ char *path, int remount)
{
int err;
struct nameidata nd;
if (!test_opt(sb, QUOTA))
return -EINVAL;
- /* Not journalling quota? */
- if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] &&
- !EXT3_SB(sb)->s_qf_names[GRPQUOTA])
- return vfs_quota_on(sb, type, format_id, path);
+ /* Not journalling quota or remount? */
+ if ((!EXT3_SB(sb)->s_qf_names[USRQUOTA] &&
+ !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) || remount)
+ return vfs_quota_on(sb, type, format_id, path, remount);
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
if (err)
return err;
@@ -2762,13 +2771,13 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
path_put(&nd.path);
return -EXDEV;
}
- /* Quotafile not of fs root? */
+ /* Quotafile not in fs root? */
if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
printk(KERN_WARNING
"EXT3-fs: Quota file not on filesystem root. "
"Journalled quota will not work.\n");
path_put(&nd.path);
- return vfs_quota_on(sb, type, format_id, path);
+ return vfs_quota_on(sb, type, format_id, path, remount);
}
/* Read data from quotafile - avoid pagecache and such because we cannot afford
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index 42856541e9a5..d4a4f0e9ff69 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -99,6 +99,8 @@ static struct buffer_head *ext3_xattr_cache_find(struct inode *,
struct mb_cache_entry **);
static void ext3_xattr_rehash(struct ext3_xattr_header *,
struct ext3_xattr_entry *);
+static int ext3_xattr_list(struct inode *inode, char *buffer,
+ size_t buffer_size);
static struct mb_cache *ext3_xattr_cache;
@@ -232,7 +234,7 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext3_xattr_check_block(bh)) {
-bad_block: ext3_error(inode->i_sb, __FUNCTION__,
+bad_block: ext3_error(inode->i_sb, __func__,
"inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
@@ -374,7 +376,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext3_xattr_check_block(bh)) {
- ext3_error(inode->i_sb, __FUNCTION__,
+ ext3_error(inode->i_sb, __func__,
"inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
@@ -427,7 +429,7 @@ cleanup:
* Returns a negative error number on failure, or the number of bytes
* used / required on success.
*/
-int
+static int
ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{
int i_error, b_error;
@@ -649,7 +651,7 @@ ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i,
atomic_read(&(bs->bh->b_count)),
le32_to_cpu(BHDR(bs->bh)->h_refcount));
if (ext3_xattr_check_block(bs->bh)) {
- ext3_error(sb, __FUNCTION__,
+ ext3_error(sb, __func__,
"inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
@@ -797,10 +799,8 @@ inserted:
get_bh(new_bh);
} else {
/* We need to allocate a new block */
- ext3_fsblk_t goal = le32_to_cpu(
- EXT3_SB(sb)->s_es->s_first_data_block) +
- (ext3_fsblk_t)EXT3_I(inode)->i_block_group *
- EXT3_BLOCKS_PER_GROUP(sb);
+ ext3_fsblk_t goal = ext3_group_first_block_no(sb,
+ EXT3_I(inode)->i_block_group);
ext3_fsblk_t block = ext3_new_block(handle, inode,
goal, &error);
if (error)
@@ -852,7 +852,7 @@ cleanup_dquot:
goto cleanup;
bad_block:
- ext3_error(inode->i_sb, __FUNCTION__,
+ ext3_error(inode->i_sb, __func__,
"inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
@@ -1081,14 +1081,14 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
goto cleanup;
bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
if (!bh) {
- ext3_error(inode->i_sb, __FUNCTION__,
+ ext3_error(inode->i_sb, __func__,
"inode %lu: block "E3FSBLK" read error", inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
}
if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1)) {
- ext3_error(inode->i_sb, __FUNCTION__,
+ ext3_error(inode->i_sb, __func__,
"inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
@@ -1215,7 +1215,7 @@ again:
}
bh = sb_bread(inode->i_sb, ce->e_block);
if (!bh) {
- ext3_error(inode->i_sb, __FUNCTION__,
+ ext3_error(inode->i_sb, __func__,
"inode %lu: block %lu read error",
inode->i_ino, (unsigned long) ce->e_block);
} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h
index 6b1ae1c6182c..148a4dfc82ab 100644
--- a/fs/ext3/xattr.h
+++ b/fs/ext3/xattr.h
@@ -67,7 +67,6 @@ extern struct xattr_handler ext3_xattr_security_handler;
extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t);
-extern int ext3_xattr_list(struct inode *, char *, size_t);
extern int ext3_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
@@ -89,12 +88,6 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name,
}
static inline int
-ext3_xattr_list(struct inode *inode, void *buffer, size_t size)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int
ext3_xattr_set(struct inode *inode, int name_index, const char *name,
const void *value, size_t size, int flags)
{
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 13383ba18f1d..c81a8e759bad 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -813,7 +813,8 @@ static int ext4_acquire_dquot(struct dquot *dquot);
static int ext4_release_dquot(struct dquot *dquot);
static int ext4_mark_dquot_dirty(struct dquot *dquot);
static int ext4_write_info(struct super_block *sb, int type);
-static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path);
+static int ext4_quota_on(struct super_block *sb, int type, int format_id,
+ char *path, int remount);
static int ext4_quota_on_mount(struct super_block *sb, int type);
static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
@@ -1632,7 +1633,7 @@ static void ext4_orphan_cleanup (struct super_block * sb,
/* Turn quotas off */
for (i = 0; i < MAXQUOTAS; i++) {
if (sb_dqopt(sb)->files[i])
- vfs_quota_off(sb, i);
+ vfs_quota_off(sb, i, 0);
}
#endif
sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -3143,7 +3144,7 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
- char *path)
+ char *path, int remount)
{
int err;
struct nameidata nd;
@@ -3151,9 +3152,9 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
if (!test_opt(sb, QUOTA))
return -EINVAL;
/* Not journalling quota? */
- if (!EXT4_SB(sb)->s_qf_names[USRQUOTA] &&
- !EXT4_SB(sb)->s_qf_names[GRPQUOTA])
- return vfs_quota_on(sb, type, format_id, path);
+ if ((!EXT4_SB(sb)->s_qf_names[USRQUOTA] &&
+ !EXT4_SB(sb)->s_qf_names[GRPQUOTA]) || remount)
+ return vfs_quota_on(sb, type, format_id, path, remount);
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
if (err)
return err;
@@ -3168,7 +3169,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
"EXT4-fs: Quota file not on filesystem root. "
"Journalled quota will not work.\n");
path_put(&nd.path);
- return vfs_quota_on(sb, type, format_id, path);
+ return vfs_quota_on(sb, type, format_id, path, remount);
}
/* Read data from quotafile - avoid pagecache and such because we cannot afford
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 72cbcd61bd95..486725ee99ae 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -124,8 +124,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos,
* but ignore that right now.
* Ahem... Stack smashing in ring 0 isn't fun. Fixed.
*/
-static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
- struct nls_table *nls)
+static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len,
+ int uni_xlate, struct nls_table *nls)
{
wchar_t *ip, ec;
unsigned char *op, nc;
@@ -135,10 +135,11 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
ip = uni;
op = ascii;
- while (*ip) {
+ while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) {
ec = *ip++;
if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
op += charlen;
+ len -= charlen;
} else {
if (uni_xlate == 1) {
*op = ':';
@@ -149,16 +150,19 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
ec >>= 4;
}
op += 5;
+ len -= 5;
} else {
*op++ = '?';
+ len--;
}
}
- /* We have some slack there, so it's OK */
- if (op>ascii+256) {
- op = ascii + 256;
- break;
- }
}
+
+ if (unlikely(*ip)) {
+ printk(KERN_WARNING "FAT: filename was truncated while "
+ "converting.");
+ }
+
*op = 0;
return (op - ascii);
}
@@ -243,7 +247,7 @@ static int fat_parse_long(struct inode *dir, loff_t *pos,
unsigned char id, slot, slots, alias_checksum;
if (!*unicode) {
- *unicode = (wchar_t *)__get_free_page(GFP_KERNEL);
+ *unicode = __getname();
if (!*unicode) {
brelse(*bh);
return -ENOMEM;
@@ -311,9 +315,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
struct nls_table *nls_io = sbi->nls_io;
struct nls_table *nls_disk = sbi->nls_disk;
wchar_t bufuname[14];
- unsigned char xlate_len, nr_slots;
+ unsigned char nr_slots;
+ int xlate_len;
wchar_t *unicode = NULL;
- unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */
+ unsigned char work[MSDOS_NAME];
+ unsigned char *bufname = NULL;
int uni_xlate = sbi->options.unicode_xlate;
int utf8 = sbi->options.utf8;
int anycase = (sbi->options.name_check != 's');
@@ -321,6 +327,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
loff_t cpos = 0;
int chl, i, j, last_u, err;
+ bufname = __getname();
+ if (!bufname)
+ return -ENOMEM;
+
err = -ENOENT;
while(1) {
if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
@@ -386,8 +396,8 @@ parse_record:
bufuname[last_u] = 0x0000;
xlate_len = utf8
- ?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
- :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, bufuname, PATH_MAX)
+ :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io);
if (xlate_len == name_len)
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
(anycase && !nls_strnicmp(nls_io, name, bufname,
@@ -396,8 +406,8 @@ parse_record:
if (nr_slots) {
xlate_len = utf8
- ?utf8_wcstombs(bufname, unicode, sizeof(bufname))
- :uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
+ ?utf8_wcstombs(bufname, unicode, PATH_MAX)
+ :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io);
if (xlate_len != name_len)
continue;
if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
@@ -416,8 +426,10 @@ Found:
sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
err = 0;
EODir:
+ if (bufname)
+ __putname(bufname);
if (unicode)
- free_page((unsigned long)unicode);
+ __putname(unicode);
return err;
}
@@ -598,7 +610,7 @@ parse_record:
if (isvfat) {
bufuname[j] = 0x0000;
i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
- : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
+ : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io);
}
fill_name = bufname;
@@ -607,10 +619,10 @@ parse_record:
/* convert the unicode long name. 261 is maximum size
* of unicode buffer. (13 * slots + nul) */
void *longname = unicode + 261;
- int buf_size = PAGE_SIZE - (261 * sizeof(unicode[0]));
+ int buf_size = PATH_MAX - (261 * sizeof(unicode[0]));
int long_len = utf8
? utf8_wcstombs(longname, unicode, buf_size)
- : uni16_to_x8(longname, unicode, uni_xlate, nls_io);
+ : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io);
if (!both) {
fill_name = longname;
@@ -640,7 +652,7 @@ EODir:
FillFailed:
brelse(bh);
if (unicode)
- free_page((unsigned long)unicode);
+ __putname(unicode);
out:
unlock_kernel();
return ret;
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 5fb366992b73..13ab763cc510 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -450,7 +450,8 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */
lock_fat(sbi);
- if (sbi->free_clusters != -1 && sbi->free_clusters < nr_cluster) {
+ if (sbi->free_clusters != -1 && sbi->free_clus_valid &&
+ sbi->free_clusters < nr_cluster) {
unlock_fat(sbi);
return -ENOSPC;
}
@@ -504,6 +505,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
/* Couldn't allocate the free entries */
sbi->free_clusters = 0;
+ sbi->free_clus_valid = 1;
sb->s_dirt = 1;
err = -ENOSPC;
@@ -583,8 +585,6 @@ error:
brelse(bhs[i]);
unlock_fat(sbi);
- fat_clusters_flush(sb);
-
return err;
}
@@ -615,7 +615,7 @@ int fat_count_free_clusters(struct super_block *sb)
int err = 0, free;
lock_fat(sbi);
- if (sbi->free_clusters != -1)
+ if (sbi->free_clusters != -1 && sbi->free_clus_valid)
goto out;
reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits;
@@ -643,6 +643,7 @@ int fat_count_free_clusters(struct super_block *sb)
} while (fat_ent_next(sbi, &fatent));
}
sbi->free_clusters = free;
+ sbi->free_clus_valid = 1;
sb->s_dirt = 1;
fatent_brelse(&fatent);
out:
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 2a3bed967041..d604bb132422 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -157,104 +157,6 @@ out:
return err;
}
-static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
-{
- mode_t req = mode & ~S_IFMT;
-
- /*
- * Of the r and x bits, all (subject to umask) must be present. Of the
- * w bits, either all (subject to umask) or none must be present.
- */
-
- if (S_ISREG(mode)) {
- req &= ~sbi->options.fs_fmask;
-
- if ((req & (S_IRUGO | S_IXUGO)) !=
- ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
- return -EPERM;
-
- if ((req & S_IWUGO) != 0 &&
- (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
- return -EPERM;
- } else if (S_ISDIR(mode)) {
- req &= ~sbi->options.fs_dmask;
-
- if ((req & (S_IRUGO | S_IXUGO)) !=
- ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
- return -EPERM;
-
- if ((req & S_IWUGO) != 0 &&
- (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
- return -EPERM;
- } else {
- return -EPERM;
- }
-
- return 0;
-}
-
-int fat_notify_change(struct dentry *dentry, struct iattr *attr)
-{
- struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
- struct inode *inode = dentry->d_inode;
- int mask, error = 0;
-
- lock_kernel();
-
- /*
- * Expand the file. Since inode_setattr() updates ->i_size
- * before calling the ->truncate(), but FAT needs to fill the
- * hole before it.
- */
- if (attr->ia_valid & ATTR_SIZE) {
- if (attr->ia_size > inode->i_size) {
- error = fat_cont_expand(inode, attr->ia_size);
- if (error || attr->ia_valid == ATTR_SIZE)
- goto out;
- attr->ia_valid &= ~ATTR_SIZE;
- }
- }
-
- error = inode_change_ok(inode, attr);
- if (error) {
- if (sbi->options.quiet)
- error = 0;
- goto out;
- }
- if (((attr->ia_valid & ATTR_UID) &&
- (attr->ia_uid != sbi->options.fs_uid)) ||
- ((attr->ia_valid & ATTR_GID) &&
- (attr->ia_gid != sbi->options.fs_gid)))
- error = -EPERM;
-
- if (error) {
- if (sbi->options.quiet)
- error = 0;
- goto out;
- }
-
- if (attr->ia_valid & ATTR_MODE) {
- error = check_mode(sbi, attr->ia_mode);
- if (error != 0 && !sbi->options.quiet)
- goto out;
- }
-
- error = inode_setattr(inode, attr);
- if (error)
- goto out;
-
- if (S_ISDIR(inode->i_mode))
- mask = sbi->options.fs_dmask;
- else
- mask = sbi->options.fs_fmask;
- inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
-out:
- unlock_kernel();
- return error;
-}
-
-EXPORT_SYMBOL_GPL(fat_notify_change);
-
/* Free all clusters after the skip'th cluster. */
static int fat_free(struct inode *inode, int skip)
{
@@ -355,8 +257,112 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
}
EXPORT_SYMBOL_GPL(fat_getattr);
+static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode,
+ mode_t mode)
+{
+ mode_t mask, req = mode & ~S_IFMT;
+
+ if (S_ISREG(mode))
+ mask = sbi->options.fs_fmask;
+ else
+ mask = sbi->options.fs_dmask;
+
+ /*
+ * Of the r and x bits, all (subject to umask) must be present. Of the
+ * w bits, either all (subject to umask) or none must be present.
+ */
+ req &= ~mask;
+ if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
+ return -EPERM;
+ if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask)))
+ return -EPERM;
+
+ return 0;
+}
+
+static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
+{
+ mode_t allow_utime = sbi->options.allow_utime;
+
+ if (current->fsuid != inode->i_uid) {
+ if (in_group_p(inode->i_gid))
+ allow_utime >>= 3;
+ if (allow_utime & MAY_WRITE)
+ return 1;
+ }
+
+ /* use a default check */
+ return 0;
+}
+
+int fat_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
+ struct inode *inode = dentry->d_inode;
+ int mask, error = 0;
+ unsigned int ia_valid;
+
+ lock_kernel();
+
+ /*
+ * Expand the file. Since inode_setattr() updates ->i_size
+ * before calling the ->truncate(), but FAT needs to fill the
+ * hole before it.
+ */
+ if (attr->ia_valid & ATTR_SIZE) {
+ if (attr->ia_size > inode->i_size) {
+ error = fat_cont_expand(inode, attr->ia_size);
+ if (error || attr->ia_valid == ATTR_SIZE)
+ goto out;
+ attr->ia_valid &= ~ATTR_SIZE;
+ }
+ }
+
+ /* Check for setting the inode time. */
+ ia_valid = attr->ia_valid;
+ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
+ if (fat_allow_set_time(sbi, inode))
+ attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET);
+ }
+
+ error = inode_change_ok(inode, attr);
+ attr->ia_valid = ia_valid;
+ if (error) {
+ if (sbi->options.quiet)
+ error = 0;
+ goto out;
+ }
+ if (((attr->ia_valid & ATTR_UID) &&
+ (attr->ia_uid != sbi->options.fs_uid)) ||
+ ((attr->ia_valid & ATTR_GID) &&
+ (attr->ia_gid != sbi->options.fs_gid)) ||
+ ((attr->ia_valid & ATTR_MODE) &&
+ fat_check_mode(sbi, inode, attr->ia_mode) < 0))
+ error = -EPERM;
+
+ if (error) {
+ if (sbi->options.quiet)
+ error = 0;
+ goto out;
+ }
+
+ error = inode_setattr(inode, attr);
+ if (error)
+ goto out;
+
+ if (S_ISDIR(inode->i_mode))
+ mask = sbi->options.fs_dmask;
+ else
+ mask = sbi->options.fs_fmask;
+ inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
+out:
+ unlock_kernel();
+ return error;
+}
+EXPORT_SYMBOL_GPL(fat_setattr);
+
const struct inode_operations fat_file_inode_operations = {
.truncate = fat_truncate,
- .setattr = fat_notify_change,
+ .setattr = fat_setattr,
.getattr = fat_getattr,
};
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 53f3cf62b7c1..5f522a55b596 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -433,11 +433,8 @@ EXPORT_SYMBOL_GPL(fat_build_inode);
static void fat_delete_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
-
- if (!is_bad_inode(inode)) {
- inode->i_size = 0;
- fat_truncate(inode);
- }
+ inode->i_size = 0;
+ fat_truncate(inode);
clear_inode(inode);
}
@@ -445,8 +442,6 @@ static void fat_clear_inode(struct inode *inode)
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
- if (is_bad_inode(inode))
- return;
lock_kernel();
spin_lock(&sbi->inode_hash_lock);
fat_cache_inval_inode(inode);
@@ -542,7 +537,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
/* If the count of free cluster is still unknown, counts it here. */
- if (sbi->free_clusters == -1) {
+ if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
int err = fat_count_free_clusters(dentry->d_sb);
if (err)
return err;
@@ -790,6 +785,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
seq_printf(m, ",gid=%u", opts->fs_gid);
seq_printf(m, ",fmask=%04o", opts->fs_fmask);
seq_printf(m, ",dmask=%04o", opts->fs_dmask);
+ if (opts->allow_utime)
+ seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
if (sbi->nls_disk)
seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
if (isvfat) {
@@ -845,9 +842,9 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
enum {
Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
- Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase,
- Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
- Opt_dots, Opt_nodots,
+ Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage,
+ Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug,
+ Opt_immutable, Opt_dots, Opt_nodots,
Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
@@ -866,6 +863,7 @@ static match_table_t fat_tokens = {
{Opt_umask, "umask=%o"},
{Opt_dmask, "dmask=%o"},
{Opt_fmask, "fmask=%o"},
+ {Opt_allow_utime, "allow_utime=%o"},
{Opt_codepage, "codepage=%u"},
{Opt_usefree, "usefree"},
{Opt_nocase, "nocase"},
@@ -937,6 +935,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
opts->fs_uid = current->uid;
opts->fs_gid = current->gid;
opts->fs_fmask = opts->fs_dmask = current->fs->umask;
+ opts->allow_utime = -1;
opts->codepage = fat_default_codepage;
opts->iocharset = fat_default_iocharset;
if (is_vfat)
@@ -1024,6 +1023,11 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
return 0;
opts->fs_fmask = option;
break;
+ case Opt_allow_utime:
+ if (match_octal(&args[0], &option))
+ return 0;
+ opts->allow_utime = option & (S_IWGRP | S_IWOTH);
+ break;
case Opt_codepage:
if (match_int(&args[0], &option))
return 0;
@@ -1106,6 +1110,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
" for FAT filesystems, filesystem will be case sensitive!\n");
}
+ /* If user doesn't specify allow_utime, it's initialized from dmask. */
+ if (opts->allow_utime == (unsigned short)-1)
+ opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
if (opts->unicode_xlate)
opts->utf8 = 0;
@@ -1208,7 +1215,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
*/
media = b->media;
- if (!FAT_VALID_MEDIA(media)) {
+ if (!fat_valid_media(media)) {
if (!silent)
printk(KERN_ERR "FAT: invalid media value (0x%02x)\n",
media);
@@ -1219,7 +1226,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
if (!is_power_of_2(logical_sector_size)
|| (logical_sector_size < 512)
- || (PAGE_CACHE_SIZE < logical_sector_size)) {
+ || (logical_sector_size > 4096)) {
if (!silent)
printk(KERN_ERR "FAT: bogus logical sector size %u\n",
logical_sector_size);
@@ -1267,6 +1274,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
sbi->fat_length = le16_to_cpu(b->fat_length);
sbi->root_cluster = 0;
sbi->free_clusters = -1; /* Don't know yet */
+ sbi->free_clus_valid = 0;
sbi->prev_free = FAT_START_ENT;
if (!sbi->fat_length && b->fat32_length) {
@@ -1302,8 +1310,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
sbi->fsinfo_sector);
} else {
if (sbi->options.usefree)
- sbi->free_clusters =
- le32_to_cpu(fsinfo->free_clusters);
+ sbi->free_clus_valid = 1;
+ sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index e632da761fc1..3f3ac630ccde 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd)
* file_lock held for write.
*/
-static int locate_fd(struct files_struct *files,
- struct file *file, unsigned int orig_start)
+static int locate_fd(unsigned int orig_start, int cloexec)
{
+ struct files_struct *files = current->files;
unsigned int newfd;
unsigned int start;
int error;
struct fdtable *fdt;
+ spin_lock(&files->file_lock);
+
error = -EINVAL;
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
goto out;
@@ -97,42 +99,28 @@ repeat:
if (error)
goto repeat;
- /*
- * We reacquired files_lock, so we are safe as long as
- * we reacquire the fdtable pointer and use it while holding
- * the lock, no one can free it during that time.
- */
if (start <= files->next_fd)
files->next_fd = newfd + 1;
+ FD_SET(newfd, fdt->open_fds);
+ if (cloexec)
+ FD_SET(newfd, fdt->close_on_exec);
+ else
+ FD_CLR(newfd, fdt->close_on_exec);
error = newfd;
-
+
out:
+ spin_unlock(&files->file_lock);
return error;
}
static int dupfd(struct file *file, unsigned int start, int cloexec)
{
- struct files_struct * files = current->files;
- struct fdtable *fdt;
- int fd;
-
- spin_lock(&files->file_lock);
- fd = locate_fd(files, file, start);
- if (fd >= 0) {
- /* locate_fd() may have expanded fdtable, load the ptr */
- fdt = files_fdtable(files);
- FD_SET(fd, fdt->open_fds);
- if (cloexec)
- FD_SET(fd, fdt->close_on_exec);
- else
- FD_CLR(fd, fdt->close_on_exec);
- spin_unlock(&files->file_lock);
+ int fd = locate_fd(start, cloexec);
+ if (fd >= 0)
fd_install(fd, file);
- } else {
- spin_unlock(&files->file_lock);
+ else
fput(file);
- }
return fd;
}
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 033f7bdd47e8..4df34da2284a 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -242,10 +242,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
return inode;
}
-static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
+static void fuse_umount_begin(struct super_block *sb)
{
- if (flags & MNT_FORCE)
- fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
+ fuse_abort_conn(get_fuse_conn_super(sb));
}
static void fuse_send_destroy(struct fuse_conn *fc)
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 90a04a6e3789..f55394e57cb2 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -438,7 +438,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
int error;
/*
- * Due to the order of unstuffing files and ->nopage(), we can be
+ * Due to the order of unstuffing files and ->fault(), we can be
* asked for a zero page in the case of a stuffed file being extended,
* so we need to supply one here. It doesn't happen often.
*/
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 6846785fe904..9783723e8ffe 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -504,7 +504,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
INIT_LIST_HEAD(&inode->i_mapping->private_list);
info = HUGETLBFS_I(inode);
- mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL);
+ mpol_shared_policy_init(&info->policy, NULL);
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index a38c7186c570..cd931ef1f000 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -407,22 +407,6 @@ void journal_commit_transaction(journal_t *journal)
jbd_debug (3, "JBD: commit phase 2\n");
/*
- * First, drop modified flag: all accesses to the buffers
- * will be tracked for a new trasaction only -bzzz
- */
- spin_lock(&journal->j_list_lock);
- if (commit_transaction->t_buffers) {
- new_jh = jh = commit_transaction->t_buffers->b_tnext;
- do {
- J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
- new_jh->b_modified == 0);
- new_jh->b_modified = 0;
- new_jh = new_jh->b_tnext;
- } while (new_jh != jh);
- }
- spin_unlock(&journal->j_list_lock);
-
- /*
* Now start flushing things to disk, in the order they appear
* on the transaction lists. Data blocks go first.
*/
@@ -488,6 +472,9 @@ void journal_commit_transaction(journal_t *journal)
*/
commit_transaction->t_state = T_COMMIT;
+ J_ASSERT(commit_transaction->t_nr_buffers <=
+ commit_transaction->t_outstanding_credits);
+
descriptor = NULL;
bufs = 0;
while (commit_transaction->t_buffers) {
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 0e081d5f32e8..b99c3b3654c4 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -534,7 +534,7 @@ int log_wait_commit(journal_t *journal, tid_t tid)
if (!tid_geq(journal->j_commit_request, tid)) {
printk(KERN_EMERG
"%s: error: j_commit_request=%d, tid=%d\n",
- __FUNCTION__, journal->j_commit_request, tid);
+ __func__, journal->j_commit_request, tid);
}
spin_unlock(&journal->j_state_lock);
#endif
@@ -599,7 +599,7 @@ int journal_bmap(journal_t *journal, unsigned long blocknr,
printk(KERN_ALERT "%s: journal block not found "
"at offset %lu on %s\n",
- __FUNCTION__,
+ __func__,
blocknr,
bdevname(journal->j_dev, b));
err = -EIO;
@@ -728,7 +728,7 @@ journal_t * journal_init_dev(struct block_device *bdev,
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
if (!journal->j_wbuf) {
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
- __FUNCTION__);
+ __func__);
kfree(journal);
journal = NULL;
goto out;
@@ -782,7 +782,7 @@ journal_t * journal_init_inode (struct inode *inode)
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
if (!journal->j_wbuf) {
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
- __FUNCTION__);
+ __func__);
kfree(journal);
return NULL;
}
@@ -791,7 +791,7 @@ journal_t * journal_init_inode (struct inode *inode)
/* If that failed, give up */
if (err) {
printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
- __FUNCTION__);
+ __func__);
kfree(journal);
return NULL;
}
@@ -877,7 +877,7 @@ int journal_create(journal_t *journal)
*/
printk(KERN_EMERG
"%s: creation of journal on external device!\n",
- __FUNCTION__);
+ __func__);
BUG();
}
@@ -1657,7 +1657,7 @@ static struct journal_head *journal_alloc_journal_head(void)
jbd_debug(1, "out of memory for journal_head\n");
if (time_after(jiffies, last_warning + 5*HZ)) {
printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
- __FUNCTION__);
+ __func__);
last_warning = jiffies;
}
while (ret == NULL) {
@@ -1794,13 +1794,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
if (jh->b_frozen_data) {
printk(KERN_WARNING "%s: freeing "
"b_frozen_data\n",
- __FUNCTION__);
+ __func__);
jbd_free(jh->b_frozen_data, bh->b_size);
}
if (jh->b_committed_data) {
printk(KERN_WARNING "%s: freeing "
"b_committed_data\n",
- __FUNCTION__);
+ __func__);
jbd_free(jh->b_committed_data, bh->b_size);
}
bh->b_private = NULL;
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index d5f8eee7c88c..1bb43e987f4b 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -138,7 +138,7 @@ repeat:
oom:
if (!journal_oom_retry)
return -ENOMEM;
- jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__);
+ jbd_debug(1, "ENOMEM in %s, retrying\n", __func__);
yield();
goto repeat;
}
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 2c9e8f5d13aa..67ff2024c23c 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -609,6 +609,12 @@ repeat:
goto done;
/*
+ * this is the first time this transaction is touching this buffer,
+ * reset the modified flag
+ */
+ jh->b_modified = 0;
+
+ /*
* If there is already a copy-out version of this buffer, then we don't
* need to make another one
*/
@@ -681,7 +687,7 @@ repeat:
if (!frozen_buffer) {
printk(KERN_EMERG
"%s: OOM for frozen_buffer\n",
- __FUNCTION__);
+ __func__);
JBUFFER_TRACE(jh, "oom!");
error = -ENOMEM;
jbd_lock_bh_state(bh);
@@ -820,9 +826,16 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
if (jh->b_transaction == NULL) {
jh->b_transaction = transaction;
+
+ /* first access by this transaction */
+ jh->b_modified = 0;
+
JBUFFER_TRACE(jh, "file as BJ_Reserved");
__journal_file_buffer(jh, transaction, BJ_Reserved);
} else if (jh->b_transaction == journal->j_committing_transaction) {
+ /* first access by this transaction */
+ jh->b_modified = 0;
+
JBUFFER_TRACE(jh, "set next transaction");
jh->b_next_transaction = transaction;
}
@@ -891,7 +904,7 @@ repeat:
committed_data = jbd_alloc(jh2bh(jh)->b_size, GFP_NOFS);
if (!committed_data) {
printk(KERN_EMERG "%s: No memory for committed data\n",
- __FUNCTION__);
+ __func__);
err = -ENOMEM;
goto out;
}
@@ -1222,6 +1235,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
struct journal_head *jh;
int drop_reserve = 0;
int err = 0;
+ int was_modified = 0;
BUFFER_TRACE(bh, "entry");
@@ -1240,6 +1254,9 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
goto not_jbd;
}
+ /* keep track of wether or not this transaction modified us */
+ was_modified = jh->b_modified;
+
/*
* The buffer's going from the transaction, we must drop
* all references -bzzz
@@ -1257,7 +1274,12 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
- drop_reserve = 1;
+ /*
+ * we only want to drop a reference if this transaction
+ * modified the buffer
+ */
+ if (was_modified)
+ drop_reserve = 1;
/*
* We are no longer going to journal this buffer.
@@ -1297,7 +1319,13 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
if (jh->b_next_transaction) {
J_ASSERT(jh->b_next_transaction == transaction);
jh->b_next_transaction = NULL;
- drop_reserve = 1;
+
+ /*
+ * only drop a reference if this transaction modified
+ * the buffer
+ */
+ if (was_modified)
+ drop_reserve = 1;
}
}
@@ -2069,7 +2097,7 @@ void __journal_refile_buffer(struct journal_head *jh)
jh->b_transaction = jh->b_next_transaction;
jh->b_next_transaction = NULL;
__journal_file_buffer(jh, jh->b_transaction,
- was_dirty ? BJ_Metadata : BJ_Reserved);
+ jh->b_modified ? BJ_Metadata : BJ_Reserved);
J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
if (was_dirty)
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking
index d14d5a4dc5ac..3ea36554107f 100644
--- a/fs/jffs2/README.Locking
+++ b/fs/jffs2/README.Locking
@@ -14,7 +14,7 @@ be fairly close.
alloc_sem
---------
-The alloc_sem is a per-filesystem semaphore, used primarily to ensure
+The alloc_sem is a per-filesystem mutex, used primarily to ensure
contiguous allocation of space on the medium. It is automatically
obtained during space allocations (jffs2_reserve_space()) and freed
upon write completion (jffs2_complete_reservation()). Note that
@@ -41,10 +41,10 @@ if the wbuf is currently holding any data is permitted, though.
Ordering constraints: See f->sem.
- File Semaphore f->sem
+ File Mutex f->sem
---------------------
-This is the JFFS2-internal equivalent of the inode semaphore i->i_sem.
+This is the JFFS2-internal equivalent of the inode mutex i->i_sem.
It protects the contents of the jffs2_inode_info private inode data,
including the linked list of node fragments (but see the notes below on
erase_completion_lock), etc.
@@ -60,14 +60,14 @@ lead to deadlock, unless we played games with unlocking the i_sem
before calling the space allocation functions.
Instead of playing such games, we just have an extra internal
-semaphore, which is obtained by the garbage collection code and also
+mutex, which is obtained by the garbage collection code and also
by the normal file system code _after_ allocation of space.
Ordering constraints:
1. Never attempt to allocate space or lock alloc_sem with
any f->sem held.
- 2. Never attempt to lock two file semaphores in one thread.
+ 2. Never attempt to lock two file mutexes in one thread.
No ordering rules have been made for doing so.
@@ -86,8 +86,8 @@ a simple spin_lock() rather than spin_lock_bh().
Note that the per-inode list of physical nodes (f->nodes) is a special
case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in
-the list are protected by the file semaphore f->sem. But the erase
-code may remove _obsolete_ nodes from the list while holding only the
+the list are protected by the file mutex f->sem. But the erase code
+may remove _obsolete_ nodes from the list while holding only the
erase_completion_lock. So you can walk the list only while holding the
erase_completion_lock, and can drop the lock temporarily mid-walk as
long as the pointer you're holding is to a _valid_ node, not an
@@ -124,10 +124,10 @@ Ordering constraints:
erase_free_sem
--------------
-This semaphore is only used by the erase code which frees obsolete
-node references and the jffs2_garbage_collect_deletion_dirent()
-function. The latter function on NAND flash must read _obsolete_ nodes
-to determine whether the 'deletion dirent' under consideration can be
+This mutex is only used by the erase code which frees obsolete node
+references and the jffs2_garbage_collect_deletion_dirent() function.
+The latter function on NAND flash must read _obsolete_ nodes to
+determine whether the 'deletion dirent' under consideration can be
discarded or whether it is still required to show that an inode has
been unlinked. Because reading from the flash may sleep, the
erase_completion_lock cannot be held, so an alternative, more
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 722a6b682951..d58f845ccb85 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -345,6 +345,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
INIT_LIST_HEAD(&c->dirty_list);
INIT_LIST_HEAD(&c->erasable_list);
INIT_LIST_HEAD(&c->erasing_list);
+ INIT_LIST_HEAD(&c->erase_checking_list);
INIT_LIST_HEAD(&c->erase_pending_list);
INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
INIT_LIST_HEAD(&c->erase_complete_list);
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
index 3a32c64ed497..5544d31c066b 100644
--- a/fs/jffs2/debug.c
+++ b/fs/jffs2/debug.c
@@ -62,9 +62,9 @@ __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
void
__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
{
- down(&f->sem);
+ mutex_lock(&f->sem);
__jffs2_dbg_fragtree_paranoia_check_nolock(f);
- up(&f->sem);
+ mutex_unlock(&f->sem);
}
void
@@ -153,6 +153,139 @@ __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
kfree(buf);
}
+void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
+{
+ struct jffs2_eraseblock *jeb;
+ uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
+ erasing = 0, bad = 0, unchecked = 0;
+ int nr_counted = 0;
+ int dump = 0;
+
+ if (c->gcblock) {
+ nr_counted++;
+ free += c->gcblock->free_size;
+ dirty += c->gcblock->dirty_size;
+ used += c->gcblock->used_size;
+ wasted += c->gcblock->wasted_size;
+ unchecked += c->gcblock->unchecked_size;
+ }
+ if (c->nextblock) {
+ nr_counted++;
+ free += c->nextblock->free_size;
+ dirty += c->nextblock->dirty_size;
+ used += c->nextblock->used_size;
+ wasted += c->nextblock->wasted_size;
+ unchecked += c->nextblock->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->clean_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->very_dirty_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->dirty_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->erasable_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->erase_pending_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->free_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+ list_for_each_entry(jeb, &c->bad_used_list, list) {
+ nr_counted++;
+ free += jeb->free_size;
+ dirty += jeb->dirty_size;
+ used += jeb->used_size;
+ wasted += jeb->wasted_size;
+ unchecked += jeb->unchecked_size;
+ }
+
+ list_for_each_entry(jeb, &c->erasing_list, list) {
+ nr_counted++;
+ erasing += c->sector_size;
+ }
+ list_for_each_entry(jeb, &c->erase_checking_list, list) {
+ nr_counted++;
+ erasing += c->sector_size;
+ }
+ list_for_each_entry(jeb, &c->erase_complete_list, list) {
+ nr_counted++;
+ erasing += c->sector_size;
+ }
+ list_for_each_entry(jeb, &c->bad_list, list) {
+ nr_counted++;
+ bad += c->sector_size;
+ }
+
+#define check(sz) \
+ if (sz != c->sz##_size) { \
+ printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \
+ sz, c->sz##_size); \
+ dump = 1; \
+ }
+ check(free);
+ check(dirty);
+ check(used);
+ check(wasted);
+ check(unchecked);
+ check(bad);
+ check(erasing);
+#undef check
+
+ if (nr_counted != c->nr_blocks) {
+ printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
+ __func__, nr_counted, c->nr_blocks);
+ dump = 1;
+ }
+
+ if (dump) {
+ __jffs2_dbg_dump_block_lists_nolock(c);
+ BUG();
+ }
+}
+
/*
* Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
*/
@@ -229,6 +362,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
}
#endif
+ if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
+ __jffs2_dbg_superblock_counts(c);
+
return;
error:
@@ -268,7 +404,10 @@ __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
printk(JFFS2_DBG);
for (ref = jeb->first_node; ; ref = ref_next(ref)) {
- printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
+ printk("%#08x", ref_offset(ref));
+#ifdef TEST_TOTLEN
+ printk("(%x)", ref->__totlen);
+#endif
if (ref_next(ref))
printk("->");
else
@@ -447,6 +586,21 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
}
}
}
+ if (list_empty(&c->erase_checking_list)) {
+ printk(JFFS2_DBG "erase_checking_list: empty\n");
+ } else {
+ struct list_head *this;
+
+ list_for_each(this, &c->erase_checking_list) {
+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+ if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+ printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+ jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+ jeb->unchecked_size, jeb->free_size);
+ }
+ }
+ }
if (list_empty(&c->erase_pending_list)) {
printk(JFFS2_DBG "erase_pending_list: empty\n");
@@ -532,9 +686,9 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
void
__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
{
- down(&f->sem);
+ mutex_lock(&f->sem);
jffs2_dbg_dump_fragtree_nolock(f);
- up(&f->sem);
+ mutex_unlock(&f->sem);
}
void
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 4130adabd76e..9645275023e6 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -38,6 +38,7 @@
#if CONFIG_JFFS2_FS_DEBUG > 1
#define JFFS2_DBG_FRAGTREE2_MESSAGES
+#define JFFS2_DBG_READINODE2_MESSAGES
#define JFFS2_DBG_MEMALLOC_MESSAGES
#endif
@@ -115,6 +116,11 @@
#else
#define dbg_readinode(fmt, ...)
#endif
+#ifdef JFFS2_DBG_READINODE2_MESSAGES
+#define dbg_readinode2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_readinode2(fmt, ...)
+#endif
/* Fragtree build debugging messages */
#ifdef JFFS2_DBG_FRAGTREE_MESSAGES
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index f948f7e6ec82..c63e7a96af0d 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -86,7 +86,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
dir_f = JFFS2_INODE_INFO(dir_i);
c = JFFS2_SB_INFO(dir_i->i_sb);
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
@@ -99,7 +99,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
}
if (fd)
ino = fd->ino;
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
if (ino) {
inode = jffs2_iget(dir_i->i_sb, ino);
if (IS_ERR(inode)) {
@@ -146,7 +146,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
curofs=1;
- down(&f->sem);
+ mutex_lock(&f->sem);
for (fd = f->dents; fd; fd = fd->next) {
curofs++;
@@ -166,7 +166,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
offset++;
}
- up(&f->sem);
+ mutex_unlock(&f->sem);
out:
filp->f_pos = offset;
return 0;
@@ -275,9 +275,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
if (!ret) {
- down(&f->sem);
+ mutex_lock(&f->sem);
old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
- up(&f->sem);
+ mutex_unlock(&f->sem);
d_instantiate(dentry, old_dentry->d_inode);
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
atomic_inc(&old_dentry->d_inode->i_count);
@@ -351,7 +351,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
if (IS_ERR(fn)) {
/* Eeek. Wave bye bye */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
return PTR_ERR(fn);
@@ -361,7 +361,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f->target = kmalloc(targetlen + 1, GFP_KERNEL);
if (!f->target) {
printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
return -ENOMEM;
@@ -374,7 +374,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
obsoleted by the first data write
*/
f->metadata = fn;
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
@@ -406,7 +406,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
}
dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -429,7 +429,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
as if it were the final unlink() */
jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
jffs2_clear_inode(inode);
return PTR_ERR(fd);
}
@@ -442,7 +442,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
jffs2_complete_reservation(c);
d_instantiate(dentry, inode);
@@ -507,7 +507,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
if (IS_ERR(fn)) {
/* Eeek. Wave bye bye */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
return PTR_ERR(fn);
@@ -516,7 +516,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
obsoleted by the first data write
*/
f->metadata = fn;
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
@@ -548,7 +548,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
}
dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -571,7 +571,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
as if it were the final unlink() */
jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
jffs2_clear_inode(inode);
return PTR_ERR(fd);
}
@@ -585,7 +585,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
jffs2_complete_reservation(c);
d_instantiate(dentry, inode);
@@ -673,7 +673,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
if (IS_ERR(fn)) {
/* Eeek. Wave bye bye */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
jffs2_clear_inode(inode);
return PTR_ERR(fn);
@@ -682,7 +682,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
obsoleted by the first data write
*/
f->metadata = fn;
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
@@ -714,7 +714,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
}
dir_f = JFFS2_INODE_INFO(dir_i);
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -740,7 +740,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
as if it were the final unlink() */
jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
jffs2_clear_inode(inode);
return PTR_ERR(fd);
}
@@ -753,7 +753,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
jffs2_complete_reservation(c);
d_instantiate(dentry, inode);
@@ -780,14 +780,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
if (S_ISDIR(new_dentry->d_inode->i_mode)) {
struct jffs2_full_dirent *fd;
- down(&victim_f->sem);
+ mutex_lock(&victim_f->sem);
for (fd = victim_f->dents; fd; fd = fd->next) {
if (fd->ino) {
- up(&victim_f->sem);
+ mutex_unlock(&victim_f->sem);
return -ENOTEMPTY;
}
}
- up(&victim_f->sem);
+ mutex_unlock(&victim_f->sem);
}
}
@@ -816,9 +816,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
/* Don't oops if the victim was a dirent pointing to an
inode which didn't exist. */
if (victim_f->inocache) {
- down(&victim_f->sem);
+ mutex_lock(&victim_f->sem);
victim_f->inocache->nlink--;
- up(&victim_f->sem);
+ mutex_unlock(&victim_f->sem);
}
}
@@ -836,11 +836,11 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
if (ret) {
/* Oh shit. We really ought to make a single node which can do both atomically */
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
- down(&f->sem);
+ mutex_lock(&f->sem);
inc_nlink(old_dentry->d_inode);
if (f->inocache)
f->inocache->nlink++;
- up(&f->sem);
+ mutex_unlock(&f->sem);
printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
/* Might as well let the VFS know */
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index a1db9180633f..25a640e566d3 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -50,14 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
if (!instr) {
printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
c->erasing_size -= c->sector_size;
c->dirty_size += c->sector_size;
jeb->dirty_size = c->sector_size;
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
return;
}
@@ -84,14 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
if (ret == -ENOMEM || ret == -EAGAIN) {
/* Erase failed immediately. Refile it on the list */
D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
c->erasing_size -= c->sector_size;
c->dirty_size += c->sector_size;
jeb->dirty_size = c->sector_size;
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
return;
}
@@ -107,7 +107,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
{
struct jffs2_eraseblock *jeb;
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
@@ -116,9 +116,9 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
if (!list_empty(&c->erase_complete_list)) {
jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
- list_del(&jeb->list);
+ list_move(&jeb->list, &c->erase_checking_list);
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
jffs2_mark_erased_block(c, jeb);
if (!--count) {
@@ -139,7 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
jffs2_free_jeb_node_refs(c, jeb);
list_add(&jeb->list, &c->erasing_list);
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
jffs2_erase_block(c, jeb);
@@ -149,12 +149,12 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
/* Be nice */
yield();
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
}
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
done:
D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
}
@@ -162,11 +162,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move_tail(&jeb->list, &c->erase_complete_list);
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
/* Ensure that kupdated calls us again to mark them clean */
jffs2_erase_pending_trigger(c);
}
@@ -180,26 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
failed too many times. */
if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
/* We'd like to give this block another try. */
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
c->erasing_size -= c->sector_size;
c->dirty_size += c->sector_size;
jeb->dirty_size = c->sector_size;
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
return;
}
}
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
c->erasing_size -= c->sector_size;
c->bad_size += c->sector_size;
list_move(&jeb->list, &c->bad_list);
c->nr_erasing_blocks--;
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
wake_up(&c->erase_wait);
}
@@ -350,9 +350,11 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
break;
} while(--retlen);
c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
- if (retlen)
+ if (retlen) {
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
*wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
+ return -EIO;
+ }
return 0;
}
do_flash_read:
@@ -373,10 +375,12 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
if (ret) {
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
+ ret = -EIO;
goto fail;
}
if (retlen != readlen) {
printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
+ ret = -EIO;
goto fail;
}
for (i=0; i<readlen; i += sizeof(unsigned long)) {
@@ -385,6 +389,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (*datum + 1) {
*bad_offset += i;
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset);
+ ret = -EIO;
goto fail;
}
}
@@ -419,9 +424,6 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
if (jffs2_write_nand_cleanmarker(c, jeb))
goto filebad;
}
-
- /* Everything else got zeroed before the erase */
- jeb->free_size = c->sector_size;
} else {
struct kvec vecs[1];
@@ -449,48 +451,50 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
goto filebad;
}
-
- /* Everything else got zeroed before the erase */
- jeb->free_size = c->sector_size;
- /* FIXME Special case for cleanmarker in empty block */
- jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
}
+ /* Everything else got zeroed before the erase */
+ jeb->free_size = c->sector_size;
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
+
c->erasing_size -= c->sector_size;
- c->free_size += jeb->free_size;
- c->used_size += jeb->used_size;
+ c->free_size += c->sector_size;
- jffs2_dbg_acct_sanity_check_nolock(c,jeb);
- jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
+ /* Account for cleanmarker now, if it's in-band */
+ if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c))
+ jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
- list_add_tail(&jeb->list, &c->free_list);
+ list_move_tail(&jeb->list, &c->free_list);
c->nr_erasing_blocks--;
c->nr_free_blocks++;
+
+ jffs2_dbg_acct_sanity_check_nolock(c, jeb);
+ jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
+
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
wake_up(&c->erase_wait);
return;
filebad:
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
/* Stick it on a list (any list) so erase_failed can take it
right off again. Silly, but shouldn't happen often. */
- list_add(&jeb->list, &c->erasing_list);
+ list_move(&jeb->list, &c->erasing_list);
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
jffs2_erase_failed(c, jeb, bad_offset);
return;
refile:
/* Stick it back on the list from whence it came and come back later */
jffs2_erase_pending_trigger(c);
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
- list_add(&jeb->list, &c->erase_complete_list);
+ list_move(&jeb->list, &c->erase_complete_list);
spin_unlock(&c->erase_completion_lock);
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
return;
}
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index dcc2734e0b5d..5e920343b2c5 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -115,9 +115,9 @@ static int jffs2_readpage (struct file *filp, struct page *pg)
struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
int ret;
- down(&f->sem);
+ mutex_lock(&f->sem);
ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
- up(&f->sem);
+ mutex_unlock(&f->sem);
return ret;
}
@@ -154,7 +154,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
if (ret)
goto out_page;
- down(&f->sem);
+ mutex_lock(&f->sem);
memset(&ri, 0, sizeof(ri));
ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -181,7 +181,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
if (IS_ERR(fn)) {
ret = PTR_ERR(fn);
jffs2_complete_reservation(c);
- up(&f->sem);
+ mutex_unlock(&f->sem);
goto out_page;
}
ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -195,12 +195,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
jffs2_mark_node_obsolete(c, fn->raw);
jffs2_free_full_dnode(fn);
jffs2_complete_reservation(c);
- up(&f->sem);
+ mutex_unlock(&f->sem);
goto out_page;
}
jffs2_complete_reservation(c);
inode->i_size = pageofs;
- up(&f->sem);
+ mutex_unlock(&f->sem);
}
/*
@@ -209,9 +209,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
* case of a short-copy.
*/
if (!PageUptodate(pg)) {
- down(&f->sem);
+ mutex_lock(&f->sem);
ret = jffs2_do_readpage_nolock(inode, pg);
- up(&f->sem);
+ mutex_unlock(&f->sem);
if (ret)
goto out_page;
}
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index e26ea78c7892..3eb1c84b0a33 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -36,6 +36,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
unsigned int ivalid;
uint32_t alloclen;
int ret;
+ int alloc_type = ALLOC_NORMAL;
D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
@@ -50,20 +51,20 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
mdata = (char *)&dev;
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
} else if (S_ISLNK(inode->i_mode)) {
- down(&f->sem);
+ mutex_lock(&f->sem);
mdatalen = f->metadata->size;
mdata = kmalloc(f->metadata->size, GFP_USER);
if (!mdata) {
- up(&f->sem);
+ mutex_unlock(&f->sem);
return -ENOMEM;
}
ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
if (ret) {
- up(&f->sem);
+ mutex_unlock(&f->sem);
kfree(mdata);
return ret;
}
- up(&f->sem);
+ mutex_unlock(&f->sem);
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
}
@@ -82,7 +83,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
kfree(mdata);
return ret;
}
- down(&f->sem);
+ mutex_lock(&f->sem);
ivalid = iattr->ia_valid;
ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -115,6 +116,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
ri->compr = JFFS2_COMPR_ZERO;
ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
ri->offset = cpu_to_je32(inode->i_size);
+ } else if (ivalid & ATTR_SIZE && !iattr->ia_size) {
+ /* For truncate-to-zero, treat it as deletion because
+ it'll always be obsoleting all previous nodes */
+ alloc_type = ALLOC_DELETION;
}
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
if (mdatalen)
@@ -122,14 +127,14 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
else
ri->data_crc = cpu_to_je32(0);
- new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, ALLOC_NORMAL);
+ new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type);
if (S_ISLNK(inode->i_mode))
kfree(mdata);
if (IS_ERR(new_metadata)) {
jffs2_complete_reservation(c);
jffs2_free_raw_inode(ri);
- up(&f->sem);
+ mutex_unlock(&f->sem);
return PTR_ERR(new_metadata);
}
/* It worked. Update the inode */
@@ -149,6 +154,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
jffs2_add_full_dnode_to_inode(c, f, new_metadata);
inode->i_size = iattr->ia_size;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
f->metadata = NULL;
} else {
f->metadata = new_metadata;
@@ -159,7 +165,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
}
jffs2_free_raw_inode(ri);
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
/* We have to do the vmtruncate() without f->sem held, since
@@ -167,8 +173,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
We are protected from a simultaneous write() extending i_size
back past iattr->ia_size, because do_truncate() holds the
generic inode semaphore. */
- if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
- vmtruncate(inode, iattr->ia_size);
+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
+ vmtruncate(inode, iattr->ia_size);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+ }
return 0;
}
@@ -248,12 +256,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
c = JFFS2_SB_INFO(inode->i_sb);
jffs2_init_inode_info(f);
- down(&f->sem);
+ mutex_lock(&f->sem);
ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
if (ret) {
- up(&f->sem);
+ mutex_unlock(&f->sem);
iget_failed(inode);
return ERR_PTR(ret);
}
@@ -330,7 +338,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino);
}
- up(&f->sem);
+ mutex_unlock(&f->sem);
D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
unlock_new_inode(inode);
@@ -339,7 +347,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
error_io:
ret = -EIO;
error:
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
iget_failed(inode);
return ERR_PTR(ret);
@@ -380,9 +388,9 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
Flush the writebuffer, if neccecary, else we loose it */
if (!(sb->s_flags & MS_RDONLY)) {
jffs2_stop_garbage_collect_thread(c);
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
jffs2_flush_wbuf_pad(c);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
}
if (!(*flags & MS_RDONLY))
@@ -429,7 +437,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
f = JFFS2_INODE_INFO(inode);
jffs2_init_inode_info(f);
- down(&f->sem);
+ mutex_lock(&f->sem);
memset(ri, 0, sizeof(*ri));
/* Set OS-specific defaults for new inodes */
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 32ff0373aa04..bad005664e30 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -126,7 +126,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
int ret = 0, inum, nlink;
int xattr = 0;
- if (down_interruptible(&c->alloc_sem))
+ if (mutex_lock_interruptible(&c->alloc_sem))
return -EINTR;
for (;;) {
@@ -143,7 +143,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
c->unchecked_size);
jffs2_dbg_dump_block_lists_nolock(c);
spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return -ENOSPC;
}
@@ -190,7 +190,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
made no progress in this case, but that should be OK */
c->checked_ino--;
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
return 0;
@@ -210,7 +210,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino);
jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return ret;
}
@@ -221,9 +221,15 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
jeb = jffs2_find_gc_block(c);
if (!jeb) {
- D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
+ /* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */
+ if (!list_empty(&c->erase_pending_list)) {
+ spin_unlock(&c->erase_completion_lock);
+ mutex_unlock(&c->alloc_sem);
+ return -EAGAIN;
+ }
+ D1(printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return -EIO;
}
@@ -232,7 +238,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
if (!jeb->used_size) {
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
goto eraseit;
}
@@ -248,7 +254,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
jeb->gc_node = raw;
spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
BUG();
}
}
@@ -266,7 +272,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
/* Just mark it obsolete */
jffs2_mark_node_obsolete(c, raw);
}
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
goto eraseit_lock;
}
@@ -334,7 +340,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
*/
printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
ic->ino, ic->state);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
spin_unlock(&c->inocache_lock);
BUG();
@@ -345,7 +351,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
the alloc_sem() (for marking nodes invalid) so we must
drop the alloc_sem before sleeping. */
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
ic->ino, ic->state));
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
@@ -416,7 +422,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
ret = -ENOSPC;
}
release_sem:
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
eraseit_lock:
/* If we've finished this block, start it erasing */
@@ -445,7 +451,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era
uint32_t start = 0, end = 0, nrfrags = 0;
int ret = 0;
- down(&f->sem);
+ mutex_lock(&f->sem);
/* Now we have the lock for this inode. Check that it's still the one at the head
of the list. */
@@ -525,7 +531,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era
}
}
upnout:
- up(&f->sem);
+ mutex_unlock(&f->sem);
return ret;
}
@@ -846,7 +852,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
/* Prevent the erase code from nicking the obsolete node refs while
we're looking at them. I really don't like this extra lock but
can't see any alternative. Suggestions on a postcard to... */
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
@@ -899,7 +905,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
/* OK. The name really does match. There really is still an older node on
the flash which our deletion dirent obsoletes. So we have to write out
a new deletion dirent to replace it */
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
@@ -908,7 +914,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
return jffs2_garbage_collect_dirent(c, jeb, f, fd);
}
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
kfree(rd);
}
@@ -1081,7 +1087,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
return 0;
}
-static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb,
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
uint32_t start, uint32_t end)
{
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c
index f4d525b0ea53..e2177210f621 100644
--- a/fs/jffs2/ioctl.c
+++ b/fs/jffs2/ioctl.c
@@ -10,6 +10,7 @@
*/
#include <linux/fs.h>
+#include "nodelist.h"
int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h
index a841f4973a74..31559f45fdde 100644
--- a/fs/jffs2/jffs2_fs_i.h
+++ b/fs/jffs2/jffs2_fs_i.h
@@ -15,7 +15,7 @@
#include <linux/version.h>
#include <linux/rbtree.h>
#include <linux/posix_acl.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
struct jffs2_inode_info {
/* We need an internal mutex similar to inode->i_mutex.
@@ -24,7 +24,7 @@ struct jffs2_inode_info {
before letting GC proceed. Or we'd have to put ugliness
into the GC code so it didn't attempt to obtain the i_mutex
for the inode(s) which are already locked */
- struct semaphore sem;
+ struct mutex sem;
/* The highest (datanode) version number used for this ino */
uint32_t highest_version;
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 18fca2b9e531..85ef6dbb1be7 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -16,7 +16,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/list.h>
@@ -44,7 +44,7 @@ struct jffs2_sb_info {
struct completion gc_thread_start; /* GC thread start completion */
struct completion gc_thread_exit; /* GC thread exit completion port */
- struct semaphore alloc_sem; /* Used to protect all the following
+ struct mutex alloc_sem; /* Used to protect all the following
fields, and also to protect against
out-of-order writing of nodes. And GC. */
uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER
@@ -87,6 +87,7 @@ struct jffs2_sb_info {
struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */
struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */
struct list_head erasing_list; /* Blocks which are currently erasing */
+ struct list_head erase_checking_list; /* Blocks which are being checked and marked */
struct list_head erase_pending_list; /* Blocks which need erasing now */
struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */
struct list_head free_list; /* Blocks which are free and ready to be used */
@@ -104,7 +105,7 @@ struct jffs2_sb_info {
/* Sem to allow jffs2_garbage_collect_deletion_dirent to
drop the erase_completion_lock while it's holding a pointer
to an obsoleted node. I don't like this. Alternatives welcomed. */
- struct semaphore erase_free_sem;
+ struct mutex erase_free_sem;
uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index ec1aae9e695e..8219df6eb6d8 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -87,7 +87,7 @@ struct jffs2_raw_node_ref
xattr_ref or xattr_datum instead. The common part of those structures
has NULL in the first word. See jffs2_raw_ref_to_ic() below */
uint32_t flash_offset;
-#define TEST_TOTLEN
+#undef TEST_TOTLEN
#ifdef TEST_TOTLEN
uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
#endif
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index a0313fa8748e..9df8f3ef20df 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -48,7 +48,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
minsize = PAD(minsize);
D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
@@ -57,7 +57,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
/* this needs a little more thought (true <tglx> :)) */
while(ret == -EAGAIN) {
while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
- int ret;
uint32_t dirty, avail;
/* calculate real dirty size
@@ -82,7 +81,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
dirty, c->unchecked_size, c->sector_size));
spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return -ENOSPC;
}
@@ -105,11 +104,11 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
avail, blocksneeded * c->sector_size));
spin_unlock(&c->erase_completion_lock);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return -ENOSPC;
}
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
@@ -117,7 +116,10 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
spin_unlock(&c->erase_completion_lock);
ret = jffs2_garbage_collect_pass(c);
- if (ret)
+
+ if (ret == -EAGAIN)
+ jffs2_erase_pending_blocks(c, 1);
+ else if (ret)
return ret;
cond_resched();
@@ -125,7 +127,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
if (signal_pending(current))
return -EINTR;
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
spin_lock(&c->erase_completion_lock);
}
@@ -138,7 +140,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
if (!ret)
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
if (ret)
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return ret;
}
@@ -463,7 +465,7 @@ void jffs2_complete_reservation(struct jffs2_sb_info *c)
{
D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n"));
jffs2_garbage_collect_trigger(c);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
}
static inline int on_list(struct list_head *obj, struct list_head *head)
@@ -512,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
any jffs2_raw_node_refs. So we don't need to stop erases from
happening, or protect against people holding an obsolete
jffs2_raw_node_ref without the erase_completion_lock. */
- down(&c->erase_free_sem);
+ mutex_lock(&c->erase_free_sem);
}
spin_lock(&c->erase_completion_lock);
@@ -715,7 +717,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
}
out_erase_sem:
- up(&c->erase_free_sem);
+ mutex_unlock(&c->erase_free_sem);
}
int jffs2_thread_should_wake(struct jffs2_sb_info *c)
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index e512a93d6249..4cb4d76de07f 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -825,8 +825,9 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
else // normal case...
tn->fn->size = je32_to_cpu(rd->dsize);
- dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",
- ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);
+ dbg_readinode2("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",
+ ref_offset(ref), je32_to_cpu(rd->version),
+ je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);
ret = jffs2_add_tn_to_tree(c, rii, tn);
@@ -836,13 +837,13 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
jffs2_free_tmp_dnode_info(tn);
return ret;
}
-#ifdef JFFS2_DBG_READINODE_MESSAGES
- dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version));
+#ifdef JFFS2_DBG_READINODE2_MESSAGES
+ dbg_readinode2("After adding ver %d:\n", je32_to_cpu(rd->version));
tn = tn_first(&rii->tn_root);
while (tn) {
- dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n",
- tn, tn->version, tn->fn->ofs,
- tn->fn->ofs+tn->fn->size, tn->overlapped);
+ dbg_readinode2("%p: v %d r 0x%x-0x%x ov %d\n",
+ tn, tn->version, tn->fn->ofs,
+ tn->fn->ofs+tn->fn->size, tn->overlapped);
tn = tn_next(tn);
}
#endif
@@ -1193,7 +1194,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",
ret, retlen, sizeof(*latest_node));
/* FIXME: If this fails, there seems to be a memory leak. Find it. */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return ret?ret:-EIO;
}
@@ -1202,7 +1203,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
if (crc != je32_to_cpu(latest_node->node_crc)) {
JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",
f->inocache->ino, ref_offset(rii.latest_ref));
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
@@ -1242,7 +1243,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
if (!f->target) {
JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -ENOMEM;
}
@@ -1255,7 +1256,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
ret = -EIO;
kfree(f->target);
f->target = NULL;
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -ret;
}
@@ -1273,14 +1274,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
if (f->metadata) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
if (!frag_first(&f->fragtree)) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
@@ -1289,7 +1290,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -EIO;
}
@@ -1379,12 +1380,13 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
if (!f)
return -ENOMEM;
- init_MUTEX_LOCKED(&f->sem);
+ mutex_init(&f->sem);
+ mutex_lock(&f->sem);
f->inocache = ic;
ret = jffs2_do_read_inode_internal(c, f, &n);
if (!ret) {
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
}
kfree (f);
@@ -1398,7 +1400,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
jffs2_clear_acl(f);
jffs2_xattr_delete_inode(c, f->inocache);
- down(&f->sem);
+ mutex_lock(&f->sem);
deleted = f->inocache && !f->inocache->nlink;
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
@@ -1430,5 +1432,5 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
jffs2_del_ino_cache(c, f->inocache);
}
- up(&f->sem);
+ mutex_unlock(&f->sem);
}
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 4677355996cc..f3353df178e7 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -47,7 +47,7 @@ static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo)
{
struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
- init_MUTEX(&ei->sem);
+ mutex_init(&ei->sem);
inode_init_once(&ei->vfs_inode);
}
@@ -55,9 +55,9 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
jffs2_flush_wbuf_pad(c);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return 0;
}
@@ -95,8 +95,8 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
/* Initialize JFFS2 superblock locks, the further initialization will
* be done later */
- init_MUTEX(&c->alloc_sem);
- init_MUTEX(&c->erase_free_sem);
+ mutex_init(&c->alloc_sem);
+ mutex_init(&c->erase_free_sem);
init_waitqueue_head(&c->erase_wait);
init_waitqueue_head(&c->inocache_wq);
spin_lock_init(&c->erase_completion_lock);
@@ -125,9 +125,9 @@ static void jffs2_put_super (struct super_block *sb)
D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
jffs2_flush_wbuf_pad(c);
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
jffs2_sum_exit(c);
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index d1d4f27464ba..8de52b607678 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -578,8 +578,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
if (!jffs2_is_writebuffered(c))
return 0;
- if (!down_trylock(&c->alloc_sem)) {
- up(&c->alloc_sem);
+ if (mutex_trylock(&c->alloc_sem)) {
+ mutex_unlock(&c->alloc_sem);
printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
BUG();
}
@@ -702,10 +702,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
if (!c->wbuf)
return 0;
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
if (!jffs2_wbuf_pending_for_ino(c, ino)) {
D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return 0;
}
@@ -725,14 +725,14 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
} else while (old_wbuf_len &&
old_wbuf_ofs == c->wbuf_ofs) {
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
ret = jffs2_garbage_collect_pass(c);
if (ret) {
/* GC failed. Flush it with padding instead */
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
down_write(&c->wbuf_sem);
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
/* retry flushing wbuf in case jffs2_wbuf_recover
@@ -742,12 +742,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
up_write(&c->wbuf_sem);
break;
}
- down(&c->alloc_sem);
+ mutex_lock(&c->alloc_sem);
}
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
- up(&c->alloc_sem);
+ mutex_unlock(&c->alloc_sem);
return ret;
}
@@ -1236,12 +1236,24 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
if (!c->wbuf)
return -ENOMEM;
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf_verify) {
+ kfree(c->oobbuf);
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+#endif
+
printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
return 0;
}
void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ kfree(c->wbuf_verify);
+#endif
kfree(c->wbuf);
}
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 776f13cbf2b5..665fce9797d3 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -137,12 +137,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
JFFS2_SUMMARY_INODE_SIZE);
} else {
/* Locking pain */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy,
alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
- down(&f->sem);
+ mutex_lock(&f->sem);
}
if (!ret) {
@@ -285,12 +285,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
JFFS2_SUMMARY_DIRENT_SIZE(namelen));
} else {
/* Locking pain */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy,
alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
- down(&f->sem);
+ mutex_lock(&f->sem);
}
if (!ret) {
@@ -353,7 +353,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
break;
}
- down(&f->sem);
+ mutex_lock(&f->sem);
datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
@@ -381,7 +381,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
if (IS_ERR(fn)) {
ret = PTR_ERR(fn);
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
if (!retried) {
/* Write error to be retried */
@@ -403,11 +403,11 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
jffs2_mark_node_obsolete(c, fn->raw);
jffs2_free_full_dnode(fn);
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
break;
}
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
if (!datalen) {
printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
@@ -439,7 +439,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
JFFS2_SUMMARY_INODE_SIZE);
D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
if (ret) {
- up(&f->sem);
+ mutex_unlock(&f->sem);
return ret;
}
@@ -454,7 +454,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
if (IS_ERR(fn)) {
D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
/* Eeek. Wave bye bye */
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
return PTR_ERR(fn);
}
@@ -463,7 +463,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
*/
f->metadata = fn;
- up(&f->sem);
+ mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode);
@@ -489,7 +489,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
return -ENOMEM;
}
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -513,7 +513,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
/* dirent failed to write. Delete the inode normally
as if it were the final unlink() */
jffs2_complete_reservation(c);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
return PTR_ERR(fd);
}
@@ -522,7 +522,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
jffs2_complete_reservation(c);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
return 0;
}
@@ -551,7 +551,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
return ret;
}
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
/* Build a deletion node */
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -574,21 +574,21 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
if (IS_ERR(fd)) {
jffs2_complete_reservation(c);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
return PTR_ERR(fd);
}
/* File it. This will mark the old one obsolete. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
} else {
- struct jffs2_full_dirent *fd = dir_f->dents;
uint32_t nhash = full_name_hash(name, namelen);
+ fd = dir_f->dents;
/* We don't actually want to reserve any space, but we do
want to be holding the alloc_sem when we write to flash */
- down(&c->alloc_sem);
- down(&dir_f->sem);
+ mutex_lock(&c->alloc_sem);
+ mutex_lock(&dir_f->sem);
for (fd = dir_f->dents; fd; fd = fd->next) {
if (fd->nhash == nhash &&
@@ -607,7 +607,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
break;
}
}
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
}
/* dead_f is NULL if this was a rename not a real unlink */
@@ -615,7 +615,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
pointing to an inode which didn't exist. */
if (dead_f && dead_f->inocache) {
- down(&dead_f->sem);
+ mutex_lock(&dead_f->sem);
if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
while (dead_f->dents) {
@@ -639,7 +639,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
dead_f->inocache->nlink--;
/* NB: Caller must set inode nlink if appropriate */
- up(&dead_f->sem);
+ mutex_unlock(&dead_f->sem);
}
jffs2_complete_reservation(c);
@@ -666,7 +666,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
return ret;
}
- down(&dir_f->sem);
+ mutex_lock(&dir_f->sem);
/* Build a deletion node */
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -691,7 +691,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
if (IS_ERR(fd)) {
jffs2_complete_reservation(c);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
return PTR_ERR(fd);
}
@@ -699,7 +699,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
jffs2_complete_reservation(c);
- up(&dir_f->sem);
+ mutex_unlock(&dir_f->sem);
return 0;
}
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 1f122c1940af..4d81553d2948 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -632,7 +632,7 @@ nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
block->b_flags |= B_TIMED_OUT;
if (conf) {
if (block->b_fl)
- locks_copy_lock(block->b_fl, conf);
+ __locks_copy_lock(block->b_fl, conf);
}
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index dbbefbcd6712..d1c48b539df8 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -18,6 +18,8 @@
#include <linux/lockd/lockd.h>
#include <linux/lockd/share.h>
#include <linux/lockd/sm_inter.h>
+#include <linux/module.h>
+#include <linux/mount.h>
#define NLMDBG_FACILITY NLMDBG_SVCSUBS
@@ -194,6 +196,12 @@ again:
return 0;
}
+static int
+nlmsvc_always_match(void *dummy1, struct nlm_host *dummy2)
+{
+ return 1;
+}
+
/*
* Inspect a single file
*/
@@ -230,7 +238,8 @@ nlm_file_inuse(struct nlm_file *file)
* Loop over all files in the file table.
*/
static int
-nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
+nlm_traverse_files(void *data, nlm_host_match_fn_t match,
+ int (*is_failover_file)(void *data, struct nlm_file *file))
{
struct hlist_node *pos, *next;
struct nlm_file *file;
@@ -239,12 +248,14 @@ nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
mutex_lock(&nlm_file_mutex);
for (i = 0; i < FILE_NRHASH; i++) {
hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
+ if (is_failover_file && !is_failover_file(data, file))
+ continue;
file->f_count++;
mutex_unlock(&nlm_file_mutex);
/* Traverse locks, blocks and shares of this file
* and update file->f_locks count */
- if (nlm_inspect_file(host, file, match))
+ if (nlm_inspect_file(data, file, match))
ret = 1;
mutex_lock(&nlm_file_mutex);
@@ -303,21 +314,27 @@ nlm_release_file(struct nlm_file *file)
* Used by nlmsvc_invalidate_all
*/
static int
-nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
+nlmsvc_mark_host(void *data, struct nlm_host *dummy)
{
+ struct nlm_host *host = data;
+
host->h_inuse = 1;
return 0;
}
static int
-nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
+nlmsvc_same_host(void *data, struct nlm_host *other)
{
+ struct nlm_host *host = data;
+
return host == other;
}
static int
-nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
+nlmsvc_is_client(void *data, struct nlm_host *dummy)
{
+ struct nlm_host *host = data;
+
if (host->h_server) {
/* we are destroying locks even though the client
* hasn't asked us too, so don't unmonitor the
@@ -337,7 +354,7 @@ void
nlmsvc_mark_resources(void)
{
dprintk("lockd: nlmsvc_mark_resources\n");
- nlm_traverse_files(NULL, nlmsvc_mark_host);
+ nlm_traverse_files(NULL, nlmsvc_mark_host, NULL);
}
/*
@@ -348,7 +365,7 @@ nlmsvc_free_host_resources(struct nlm_host *host)
{
dprintk("lockd: nlmsvc_free_host_resources\n");
- if (nlm_traverse_files(host, nlmsvc_same_host)) {
+ if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) {
printk(KERN_WARNING
"lockd: couldn't remove all locks held by %s\n",
host->h_name);
@@ -368,5 +385,41 @@ nlmsvc_invalidate_all(void)
* turn, which is about as inefficient as it gets.
* Now we just do it once in nlm_traverse_files.
*/
- nlm_traverse_files(NULL, nlmsvc_is_client);
+ nlm_traverse_files(NULL, nlmsvc_is_client, NULL);
+}
+
+static int
+nlmsvc_match_sb(void *datap, struct nlm_file *file)
+{
+ struct super_block *sb = datap;
+
+ return sb == file->f_file->f_path.mnt->mnt_sb;
+}
+
+int
+nlmsvc_unlock_all_by_sb(struct super_block *sb)
+{
+ int ret;
+
+ ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb);
+ return ret ? -EIO : 0;
+}
+EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
+
+static int
+nlmsvc_match_ip(void *datap, struct nlm_host *host)
+{
+ __be32 *server_addr = datap;
+
+ return host->h_saddr.sin_addr.s_addr == *server_addr;
+}
+
+int
+nlmsvc_unlock_all_by_ip(__be32 server_addr)
+{
+ int ret;
+ ret = nlm_traverse_files(&server_addr, nlmsvc_match_ip, NULL);
+ return ret ? -EIO : 0;
+
}
+EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip);
diff --git a/fs/locks.c b/fs/locks.c
index 592faadbcec1..44d9a6a7ec50 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -224,7 +224,7 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
/*
* Initialize a new lock from an existing file_lock structure.
*/
-static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
+void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
{
new->fl_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid;
@@ -236,6 +236,7 @@ static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
new->fl_ops = NULL;
new->fl_lmops = NULL;
}
+EXPORT_SYMBOL(__locks_copy_lock);
void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
@@ -833,7 +834,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (!posix_locks_conflict(request, fl))
continue;
if (conflock)
- locks_copy_lock(conflock, fl);
+ __locks_copy_lock(conflock, fl);
error = -EAGAIN;
if (!(request->fl_flags & FL_SLEEP))
goto out;
@@ -1367,18 +1368,20 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
lease = *flp;
- error = -EAGAIN;
- if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
- goto out;
- if ((arg == F_WRLCK)
- && ((atomic_read(&dentry->d_count) > 1)
- || (atomic_read(&inode->i_count) > 1)))
- goto out;
+ if (arg != F_UNLCK) {
+ error = -ENOMEM;
+ new_fl = locks_alloc_lock();
+ if (new_fl == NULL)
+ goto out;
- error = -ENOMEM;
- new_fl = locks_alloc_lock();
- if (new_fl == NULL)
- goto out;
+ error = -EAGAIN;
+ if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
+ goto out;
+ if ((arg == F_WRLCK)
+ && ((atomic_read(&dentry->d_count) > 1)
+ || (atomic_read(&inode->i_count) > 1)))
+ goto out;
+ }
/*
* At this point, we know that if there is an exclusive
@@ -1404,6 +1407,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
rdlease_count++;
}
+ error = -EAGAIN;
if ((arg == F_RDLCK && (wrlease_count > 0)) ||
(arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
goto out;
@@ -1490,8 +1494,7 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
struct file_lock fl, *flp = &fl;
- struct dentry *dentry = filp->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int error;
locks_init_lock(&fl);
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 30f7d0ae2215..2d4358c59f68 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -653,7 +653,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
.mkdir = msdos_mkdir,
.rmdir = msdos_rmdir,
.rename = msdos_rename,
- .setattr = fat_notify_change,
+ .setattr = fat_setattr,
.getattr = fat_getattr,
};
diff --git a/fs/namespace.c b/fs/namespace.c
index 0505fb61aa74..fe376805cf5f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -14,7 +14,6 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/quotaops.h>
#include <linux/acct.h>
#include <linux/capability.h>
#include <linux/cpumask.h>
@@ -1061,10 +1060,11 @@ static int do_umount(struct vfsmount *mnt, int flags)
* about for the moment.
*/
- lock_kernel();
- if (sb->s_op->umount_begin)
- sb->s_op->umount_begin(mnt, flags);
- unlock_kernel();
+ if (flags & MNT_FORCE && sb->s_op->umount_begin) {
+ lock_kernel();
+ sb->s_op->umount_begin(sb);
+ unlock_kernel();
+ }
/*
* No sense to grab the lock for this test, but test itself looks
@@ -1083,7 +1083,6 @@ static int do_umount(struct vfsmount *mnt, int flags)
down_write(&sb->s_umount);
if (!(sb->s_flags & MS_RDONLY)) {
lock_kernel();
- DQUOT_OFF(sb);
retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
unlock_kernel();
}
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index fbbb9f7afa1a..2e5ab1204dec 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -107,12 +107,6 @@ static const struct super_operations ncp_sops =
.show_options = ncp_show_options,
};
-extern struct dentry_operations ncp_root_dentry_operations;
-#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
-extern const struct address_space_operations ncp_symlink_aops;
-extern int ncp_symlink(struct inode*, struct dentry*, const char*);
-#endif
-
/*
* Fill in the ncpfs-specific information in the inode.
*/
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index ad8f167e54bc..3a97c95e1ca2 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -389,11 +389,11 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
struct dentry* dentry = inode->i_sb->s_root;
if (dentry) {
- struct inode* inode = dentry->d_inode;
+ struct inode* s_inode = dentry->d_inode;
- if (inode) {
- sr.volNumber = NCP_FINFO(inode)->volNumber;
- sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
+ if (s_inode) {
+ sr.volNumber = NCP_FINFO(s_inode)->volNumber;
+ sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum;
sr.namespace = server->name_space[sr.volNumber];
} else
DPRINTK("ncpfs: s_root->d_inode==NULL\n");
@@ -439,12 +439,12 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
dentry = inode->i_sb->s_root;
server->root_setuped = 1;
if (dentry) {
- struct inode* inode = dentry->d_inode;
+ struct inode* s_inode = dentry->d_inode;
if (inode) {
- NCP_FINFO(inode)->volNumber = vnum;
- NCP_FINFO(inode)->dirEntNum = de;
- NCP_FINFO(inode)->DosDirNum = dosde;
+ NCP_FINFO(s_inode)->volNumber = vnum;
+ NCP_FINFO(s_inode)->dirEntNum = de;
+ NCP_FINFO(s_inode)->DosDirNum = dosde;
} else
DPRINTK("ncpfs: s_root->d_inode==NULL\n");
} else
@@ -519,7 +519,6 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
}
{
struct ncp_lock_ioctl rqdata;
- int result;
if (copy_from_user(&rqdata, argp, sizeof(rqdata)))
return -EFAULT;
diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c
index 749a18d33599..7c0b5c21e6cf 100644
--- a/fs/ncpfs/ncpsign_kernel.c
+++ b/fs/ncpfs/ncpsign_kernel.c
@@ -55,7 +55,7 @@ static void nwsign(char *r_data1, char *r_data2, char *outdata) {
unsigned int w0,w1,w2,w3;
static int rbit[4]={0, 2, 1, 3};
#ifdef __i386__
- unsigned int *data2=(int *)r_data2;
+ unsigned int *data2=(unsigned int *)r_data2;
#else
unsigned int data2[16];
for (i=0;i<16;i++)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 20a1cb1810fe..fa220dc74609 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -198,7 +198,7 @@ static match_table_t nfs_secflavor_tokens = {
};
-static void nfs_umount_begin(struct vfsmount *, int);
+static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct dentry *, struct kstatfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *);
static int nfs_show_stats(struct seq_file *, struct vfsmount *);
@@ -647,13 +647,11 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
* Begin unmount by attempting to remove all automounted mountpoints we added
* in response to xdev traversals and referrals
*/
-static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+static void nfs_umount_begin(struct super_block *sb)
{
- struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb);
+ struct nfs_server *server = NFS_SB(sb);
struct rpc_clnt *rpc;
- if (!(flags & MNT_FORCE))
- return;
/* -EIO all pending I/O */
rpc = server->client_acl;
if (!IS_ERR(rpc))
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 55dfdd71f1b0..8799b8708188 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2712,9 +2712,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* Note: locks.c uses the BKL to protect the inode's lock list.
*/
- /* XXX?: Just to divert the locks_release_private at the start of
- * locks_copy_lock: */
- locks_init_lock(&conflock);
err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
switch (-err) {
case 0: /* success! */
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 1ba7ad981935..c513bbdf2d36 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -376,20 +376,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
goto xdr_error;
}
}
- if (bmval[1] & FATTR4_WORD1_TIME_METADATA) {
- /* We require the high 32 bits of 'seconds' to be 0, and we ignore
- all 32 bits of 'nseconds'. */
- READ_BUF(12);
- len += 12;
- READ32(dummy32);
- if (dummy32)
- return nfserr_inval;
- READ32(iattr->ia_ctime.tv_sec);
- READ32(iattr->ia_ctime.tv_nsec);
- if (iattr->ia_ctime.tv_nsec >= (u32)1000000000)
- return nfserr_inval;
- iattr->ia_valid |= ATTR_CTIME;
- }
if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
READ_BUF(4);
len += 4;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 613bcb8171a5..42f3820ee8f5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -22,6 +22,7 @@
#include <linux/seq_file.h>
#include <linux/pagemap.h>
#include <linux/init.h>
+#include <linux/inet.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/ctype.h>
@@ -35,6 +36,7 @@
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr.h>
#include <linux/nfsd/syscall.h>
+#include <linux/lockd/lockd.h>
#include <asm/uaccess.h>
#include <net/ipv6.h>
@@ -53,6 +55,8 @@ enum {
NFSD_Getfs,
NFSD_List,
NFSD_Fh,
+ NFSD_FO_UnlockIP,
+ NFSD_FO_UnlockFS,
NFSD_Threads,
NFSD_Pool_Threads,
NFSD_Versions,
@@ -89,6 +93,9 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
#endif
+static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size);
+static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size);
+
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Svc] = write_svc,
[NFSD_Add] = write_add,
@@ -98,6 +105,8 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Getfd] = write_getfd,
[NFSD_Getfs] = write_getfs,
[NFSD_Fh] = write_filehandle,
+ [NFSD_FO_UnlockIP] = failover_unlock_ip,
+ [NFSD_FO_UnlockFS] = failover_unlock_fs,
[NFSD_Threads] = write_threads,
[NFSD_Pool_Threads] = write_pool_threads,
[NFSD_Versions] = write_versions,
@@ -298,6 +307,58 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
return err;
}
+static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
+{
+ __be32 server_ip;
+ char *fo_path, c;
+ int b1, b2, b3, b4;
+
+ /* sanity check */
+ if (size == 0)
+ return -EINVAL;
+
+ if (buf[size-1] != '\n')
+ return -EINVAL;
+
+ fo_path = buf;
+ if (qword_get(&buf, fo_path, size) < 0)
+ return -EINVAL;
+
+ /* get ipv4 address */
+ if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+ return -EINVAL;
+ server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+
+ return nlmsvc_unlock_all_by_ip(server_ip);
+}
+
+static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
+{
+ struct nameidata nd;
+ char *fo_path;
+ int error;
+
+ /* sanity check */
+ if (size == 0)
+ return -EINVAL;
+
+ if (buf[size-1] != '\n')
+ return -EINVAL;
+
+ fo_path = buf;
+ if (qword_get(&buf, fo_path, size) < 0)
+ return -EINVAL;
+
+ error = path_lookup(fo_path, 0, &nd);
+ if (error)
+ return error;
+
+ error = nlmsvc_unlock_all_by_sb(nd.path.mnt->mnt_sb);
+
+ path_put(&nd.path);
+ return error;
+}
+
static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
{
/* request is:
@@ -700,6 +761,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
[NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
+ [NFSD_FO_UnlockIP] = {"unlock_ip",
+ &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_FO_UnlockFS] = {"unlock_filesystem",
+ &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
diff --git a/fs/open.c b/fs/open.c
index b70e7666bb2c..7af1f05d5978 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -837,7 +837,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
if (f->f_flags & O_DIRECT) {
if (!f->f_mapping->a_ops ||
((!f->f_mapping->a_ops->direct_IO) &&
- (!f->f_mapping->a_ops->get_xip_page))) {
+ (!f->f_mapping->a_ops->get_xip_mem))) {
fput(f);
f = ERR_PTR(-EINVAL);
}
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 5567ec0d03a3..796511886f28 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -18,7 +18,7 @@
*
* Re-organised Feb 1998 Russell King
*/
-
+#include <linux/msdos_fs.h>
#include "check.h"
#include "msdos.h"
@@ -419,6 +419,7 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
Sector sect;
unsigned char *data;
struct partition *p;
+ struct fat_boot_sector *fb;
int slot;
data = read_dev_sector(bdev, 0, &sect);
@@ -444,8 +445,21 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
p = (struct partition *) (data + 0x1be);
for (slot = 1; slot <= 4; slot++, p++) {
if (p->boot_ind != 0 && p->boot_ind != 0x80) {
- put_dev_sector(sect);
- return 0;
+ /*
+ * Even without a valid boot inidicator value
+ * its still possible this is valid FAT filesystem
+ * without a partition table.
+ */
+ fb = (struct fat_boot_sector *) data;
+ if (slot == 1 && fb->reserved && fb->fats
+ && fat_valid_media(fb->media)) {
+ printk("\n");
+ put_dev_sector(sect);
+ return 1;
+ } else {
+ put_dev_sector(sect);
+ return 0;
+ }
}
}
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 2d563979cb02..441a32f0e5f2 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -456,6 +456,20 @@ static const struct file_operations proc_slabstats_operations = {
#endif
#endif
+#ifdef CONFIG_MMU
+static int vmalloc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &vmalloc_op);
+}
+
+static const struct file_operations proc_vmalloc_operations = {
+ .open = vmalloc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif
+
static int show_stat(struct seq_file *p, void *v)
{
int i;
@@ -869,6 +883,9 @@ void __init proc_misc_init(void)
create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations);
#endif
#endif
+#ifdef CONFIG_MMU
+ proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
+#endif
create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
create_seq_entry("pagetypeinfo", S_IRUGO, &pagetypeinfo_file_ops);
create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 9dfb5ff24209..7415eeb7cc3a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -338,8 +338,7 @@ const struct file_operations proc_maps_operations = {
#define PSS_SHIFT 12
#ifdef CONFIG_PROC_PAGE_MONITOR
-struct mem_size_stats
-{
+struct mem_size_stats {
struct vm_area_struct *vma;
unsigned long resident;
unsigned long shared_clean;
@@ -347,6 +346,7 @@ struct mem_size_stats
unsigned long private_clean;
unsigned long private_dirty;
unsigned long referenced;
+ unsigned long swap;
u64 pss;
};
@@ -363,6 +363,12 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
for (; addr != end; pte++, addr += PAGE_SIZE) {
ptent = *pte;
+
+ if (is_swap_pte(ptent)) {
+ mss->swap += PAGE_SIZE;
+ continue;
+ }
+
if (!pte_present(ptent))
continue;
@@ -421,7 +427,8 @@ static int show_smap(struct seq_file *m, void *v)
"Shared_Dirty: %8lu kB\n"
"Private_Clean: %8lu kB\n"
"Private_Dirty: %8lu kB\n"
- "Referenced: %8lu kB\n",
+ "Referenced: %8lu kB\n"
+ "Swap: %8lu kB\n",
(vma->vm_end - vma->vm_start) >> 10,
mss.resident >> 10,
(unsigned long)(mss.pss >> (10 + PSS_SHIFT)),
@@ -429,7 +436,8 @@ static int show_smap(struct seq_file *m, void *v)
mss.shared_dirty >> 10,
mss.private_clean >> 10,
mss.private_dirty >> 10,
- mss.referenced >> 10);
+ mss.referenced >> 10,
+ mss.swap >> 10);
return ret;
}
@@ -579,7 +587,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end,
return err;
}
-u64 swap_pte_to_pagemap_entry(pte_t pte)
+static u64 swap_pte_to_pagemap_entry(pte_t pte)
{
swp_entry_t e = pte_to_swp_entry(pte);
return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
diff --git a/fs/quota.c b/fs/quota.c
index 84f28dd72116..db1cc9f3c7aa 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -69,7 +69,6 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid
switch (cmd) {
case Q_GETFMT:
case Q_GETINFO:
- case Q_QUOTAOFF:
case Q_SETINFO:
case Q_SETQUOTA:
case Q_GETQUOTA:
@@ -229,12 +228,12 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void
if (IS_ERR(pathname = getname(addr)))
return PTR_ERR(pathname);
- ret = sb->s_qcop->quota_on(sb, type, id, pathname);
+ ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
putname(pathname);
return ret;
}
case Q_QUOTAOFF:
- return sb->s_qcop->quota_off(sb, type);
+ return sb->s_qcop->quota_off(sb, type, 0);
case Q_GETFMT: {
__u32 fmt;
diff --git a/fs/quota_v1.c b/fs/quota_v1.c
index f3841f233069..a6cf9269105c 100644
--- a/fs/quota_v1.c
+++ b/fs/quota_v1.c
@@ -139,6 +139,9 @@ static int v1_read_file_info(struct super_block *sb, int type)
goto out;
}
ret = 0;
+ /* limits are stored as unsigned 32-bit data */
+ dqopt->info[type].dqi_maxblimit = 0xffffffff;
+ dqopt->info[type].dqi_maxilimit = 0xffffffff;
dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
out:
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
index c519a583e681..23b647f25d08 100644
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -59,6 +59,9 @@ static int v2_read_file_info(struct super_block *sb, int type)
sb->s_id);
return -1;
}
+ /* limits are stored as unsigned 32-bit data */
+ info->dqi_maxblimit = 0xffffffff;
+ info->dqi_maxilimit = 0xffffffff;
info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index f491ceb5af02..4646caa60455 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -479,7 +479,7 @@ static void __discard_prealloc(struct reiserfs_transaction_handle *th,
if (ei->i_prealloc_count < 0)
reiserfs_warning(th->t_super,
"zam-4001:%s: inode has negative prealloc blocks count.",
- __FUNCTION__);
+ __func__);
#endif
while (ei->i_prealloc_count > 0) {
reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
@@ -517,7 +517,7 @@ void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th)
if (!ei->i_prealloc_count) {
reiserfs_warning(th->t_super,
"zam-4001:%s: inode is in prealloc list but has no preallocated blocks.",
- __FUNCTION__);
+ __func__);
}
#endif
__discard_prealloc(th, ei);
@@ -632,7 +632,7 @@ int reiserfs_parse_alloc_options(struct super_block *s, char *options)
}
reiserfs_warning(s, "zam-4001: %s : unknown option - %s",
- __FUNCTION__, this_char);
+ __func__, this_char);
return 1;
}
@@ -1254,7 +1254,7 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
bh = sb_bread(sb, block);
if (bh == NULL)
reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
- "reading failed", __FUNCTION__, block);
+ "reading failed", __func__, block);
else {
if (buffer_locked(bh)) {
PROC_INFO_INC(sb, scan_bitmap.wait);
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index 7ee4208793b6..2f87f5b14630 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -1464,29 +1464,29 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
} else
/* item falls wholly into S_new[i] */
{
- int ret_val;
+ int leaf_mi;
struct item_head *pasted;
#ifdef CONFIG_REISERFS_CHECK
- struct item_head *ih =
+ struct item_head *ih_check =
B_N_PITEM_HEAD(tbS0, item_pos);
- if (!is_direntry_le_ih(ih)
- && (pos_in_item != ih_item_len(ih)
+ if (!is_direntry_le_ih(ih_check)
+ && (pos_in_item != ih_item_len(ih_check)
|| tb->insert_size[0] <= 0))
reiserfs_panic(tb->tb_sb,
"PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
#endif /* CONFIG_REISERFS_CHECK */
- ret_val =
+ leaf_mi =
leaf_move_items(LEAF_FROM_S_TO_SNEW,
tb, snum[i],
sbytes[i],
S_new[i]);
- RFALSE(ret_val,
+ RFALSE(leaf_mi,
"PAP-12240: unexpected value returned by leaf_move_items (%d)",
- ret_val);
+ leaf_mi);
/* paste into item */
bi.tb = tb;
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 74363a7aacbc..830332021ed4 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -12,8 +12,6 @@
#include <linux/smp_lock.h>
#include <linux/compat.h>
-static int reiserfs_unpack(struct inode *inode, struct file *filp);
-
/*
** reiserfs_ioctl - handler for ioctl for inode
** supported commands:
@@ -159,7 +157,7 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
** Function try to convert tail from direct item into indirect.
** It set up nopack attribute in the REISERFS_I(inode)->nopack
*/
-static int reiserfs_unpack(struct inode *inode, struct file *filp)
+int reiserfs_unpack(struct inode *inode, struct file *filp)
{
int retval = 0;
int index;
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 060eb3f598e7..da86042b3e03 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1187,7 +1187,7 @@ static int flush_commit_list(struct super_block *s,
if (retval)
reiserfs_abort(s, retval, "Journal write error in %s",
- __FUNCTION__);
+ __func__);
put_fs_excl();
return retval;
}
@@ -1534,7 +1534,7 @@ static int flush_journal_list(struct super_block *s,
reiserfs_warning(s,
"clm-2082: Unable to flush buffer %llu in %s",
(unsigned long long)saved_bh->
- b_blocknr, __FUNCTION__);
+ b_blocknr, __func__);
}
free_cnode:
last = cn;
@@ -1586,7 +1586,7 @@ static int flush_journal_list(struct super_block *s,
if (err)
reiserfs_abort(s, -EIO,
"Write error while pushing transaction to disk in %s",
- __FUNCTION__);
+ __func__);
flush_older_and_return:
/* before we can update the journal header block, we _must_ flush all
@@ -1616,7 +1616,7 @@ static int flush_journal_list(struct super_block *s,
if (err)
reiserfs_abort(s, -EIO,
"Write error while updating journal header in %s",
- __FUNCTION__);
+ __func__);
}
remove_all_from_journal_list(s, jl, 0);
list_del_init(&jl->j_list);
@@ -4316,5 +4316,5 @@ static void __reiserfs_journal_abort_soft(struct super_block *sb, int errno)
void reiserfs_journal_abort(struct super_block *sb, int errno)
{
- return __reiserfs_journal_abort_soft(sb, errno);
+ __reiserfs_journal_abort_soft(sb, errno);
}
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 8867533cb727..c1add28dd45e 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -301,7 +301,7 @@ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
path_to_entry, de);
if (retval == IO_ERROR) {
reiserfs_warning(dir->i_sb, "zam-7001: io error in %s",
- __FUNCTION__);
+ __func__);
return IO_ERROR;
}
@@ -496,7 +496,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
reiserfs_warning(dir->i_sb,
"zam-7002:%s: \"reiserfs_find_entry\" "
"has returned unexpected value (%d)",
- __FUNCTION__, retval);
+ __func__, retval);
}
return -EEXIST;
@@ -907,7 +907,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
if (inode->i_nlink != 2 && inode->i_nlink != 1)
reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
- "!= 2 (%d)", __FUNCTION__, inode->i_nlink);
+ "!= 2 (%d)", __func__, inode->i_nlink);
clear_nlink(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
@@ -984,7 +984,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
if (!inode->i_nlink) {
reiserfs_warning(inode->i_sb, "%s: deleting nonexistent file "
- "(%s:%lu), %d", __FUNCTION__,
+ "(%s:%lu), %d", __func__,
reiserfs_bdevname(inode->i_sb), inode->i_ino,
inode->i_nlink);
inode->i_nlink = 1;
diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c
index 65feba4deb69..ea0cf8c28a99 100644
--- a/fs/reiserfs/objectid.c
+++ b/fs/reiserfs/objectid.c
@@ -61,7 +61,7 @@ __u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th)
/* comment needed -Hans */
unused_objectid = le32_to_cpu(map[1]);
if (unused_objectid == U32_MAX) {
- reiserfs_warning(s, "%s: no more object ids", __FUNCTION__);
+ reiserfs_warning(s, "%s: no more object ids", __func__);
reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s));
return 0;
}
@@ -114,7 +114,7 @@ void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
if (objectid_to_release == le32_to_cpu(map[i])) {
/* This incrementation unallocates the objectid. */
//map[i]++;
- map[i] = cpu_to_le32(le32_to_cpu(map[i]) + 1);
+ le32_add_cpu(&map[i], 1);
/* Did we unallocate the last member of an odd sequence, and can shrink oids? */
if (map[i] == map[i + 1]) {
@@ -138,8 +138,7 @@ void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
/* size of objectid map is not changed */
if (objectid_to_release + 1 == le32_to_cpu(map[i + 1])) {
//objectid_map[i+1]--;
- map[i + 1] =
- cpu_to_le32(le32_to_cpu(map[i + 1]) - 1);
+ le32_add_cpu(&map[i + 1], -1);
return;
}
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index d2db2417b2bd..abbc64dcc8d4 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -1419,8 +1419,7 @@ int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
inode_generation =
&REISERFS_SB(th->t_super)->s_rs->s_inode_generation;
- *inode_generation =
- cpu_to_le32(le32_to_cpu(*inode_generation) + 1);
+ le32_add_cpu(inode_generation, 1);
}
/* USE_INODE_GENERATION_COUNTER */
#endif
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 393cc22c1717..ed424d708e69 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -304,7 +304,7 @@ static int finish_unfinished(struct super_block *s)
/* Turn quotas off */
for (i = 0; i < MAXQUOTAS; i++) {
if (sb_dqopt(s)->files[i])
- vfs_quota_off_mount(s, i);
+ vfs_quota_off(s, i, 0);
}
if (ms_active_set)
/* Restore the flag back */
@@ -634,7 +634,7 @@ static int reiserfs_acquire_dquot(struct dquot *);
static int reiserfs_release_dquot(struct dquot *);
static int reiserfs_mark_dquot_dirty(struct dquot *);
static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, char *);
+static int reiserfs_quota_on(struct super_block *, int, int, char *, int);
static struct dquot_operations reiserfs_quota_operations = {
.initialize = reiserfs_dquot_initialize,
@@ -1890,8 +1890,14 @@ static int reiserfs_dquot_drop(struct inode *inode)
ret =
journal_begin(&th, inode->i_sb,
2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
- if (ret)
+ if (ret) {
+ /*
+ * We call dquot_drop() anyway to at least release references
+ * to quota structures so that umount does not hang.
+ */
+ dquot_drop(inode);
goto out;
+ }
ret = dquot_drop(inode);
err =
journal_end(&th, inode->i_sb,
@@ -2015,13 +2021,17 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
- char *path)
+ char *path, int remount)
{
int err;
struct nameidata nd;
+ struct inode *inode;
if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
return -EINVAL;
+ /* No more checks needed? Path and format_id are bogus anyway... */
+ if (remount)
+ return vfs_quota_on(sb, type, format_id, path, 1);
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
if (err)
return err;
@@ -2030,18 +2040,24 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
path_put(&nd.path);
return -EXDEV;
}
+ inode = nd.path.dentry->d_inode;
/* We must not pack tails for quota files on reiserfs for quota IO to work */
- if (!(REISERFS_I(nd.path.dentry->d_inode)->i_flags & i_nopack_mask)) {
- reiserfs_warning(sb,
- "reiserfs: Quota file must have tail packing disabled.");
- path_put(&nd.path);
- return -EINVAL;
+ if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
+ err = reiserfs_unpack(inode, NULL);
+ if (err) {
+ reiserfs_warning(sb,
+ "reiserfs: Unpacking tail of quota file failed"
+ " (%d). Cannot turn on quotas.", err);
+ path_put(&nd.path);
+ return -EINVAL;
+ }
+ mark_inode_dirty(inode);
}
/* Not journalling quota? No more tests needed... */
if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] &&
!REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) {
path_put(&nd.path);
- return vfs_quota_on(sb, type, format_id, path);
+ return vfs_quota_on(sb, type, format_id, path, 0);
}
/* Quotafile not of fs root? */
if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
@@ -2049,7 +2065,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
"reiserfs: Quota file not on filesystem root. "
"Journalled quota will not work.");
path_put(&nd.path);
- return vfs_quota_on(sb, type, format_id, path);
+ return vfs_quota_on(sb, type, format_id, path, 0);
}
/* Read data from quotafile - avoid pagecache and such because we cannot afford
diff --git a/fs/super.c b/fs/super.c
index 4798350b2bc9..a5a4aca7e22f 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -179,7 +179,7 @@ void deactivate_super(struct super_block *s)
if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
s->s_count -= S_BIAS-1;
spin_unlock(&sb_lock);
- DQUOT_OFF(s);
+ DQUOT_OFF(s, 0);
down_write(&s->s_umount);
fs->kill_sb(s);
put_filesystem(fs);
@@ -608,6 +608,7 @@ retry:
int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
{
int retval;
+ int remount_rw;
#ifdef CONFIG_BLOCK
if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
@@ -625,8 +626,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
mark_files_ro(sb);
else if (!fs_may_remount_ro(sb))
return -EBUSY;
- DQUOT_OFF(sb);
+ retval = DQUOT_OFF(sb, 1);
+ if (retval < 0 && retval != -ENOSYS)
+ return -EBUSY;
}
+ remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
if (sb->s_op->remount_fs) {
lock_super(sb);
@@ -636,6 +640,8 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
return retval;
}
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+ if (remount_rw)
+ DQUOT_ON_REMOUNT(sb);
return 0;
}
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index ade9a7e6a757..dbdfabbfd609 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -477,11 +477,10 @@ const struct file_operations sysfs_file_operations = {
.poll = sysfs_poll,
};
-
-int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
- int type)
+int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
+ const struct attribute *attr, int type, mode_t amode)
{
- umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
+ umode_t mode = (amode & S_IALLUGO) | S_IFREG;
struct sysfs_addrm_cxt acxt;
struct sysfs_dirent *sd;
int rc;
@@ -502,6 +501,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
}
+int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
+ int type)
+{
+ return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
+}
+
+
/**
* sysfs_create_file - create an attribute file for an object.
* @kobj: object we're creating for.
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 477904915032..eeba38417b1d 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -23,35 +23,50 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
int i;
for (i = 0, attr = grp->attrs; *attr; i++, attr++)
- if (!grp->is_visible ||
- grp->is_visible(kobj, *attr, i))
- sysfs_hash_and_remove(dir_sd, (*attr)->name);
+ sysfs_hash_and_remove(dir_sd, (*attr)->name);
}
static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
- const struct attribute_group *grp)
+ const struct attribute_group *grp, int update)
{
struct attribute *const* attr;
int error = 0, i;
- for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++)
- if (!grp->is_visible ||
- grp->is_visible(kobj, *attr, i))
- error |=
- sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
+ for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
+ mode_t mode = 0;
+
+ /* in update mode, we're changing the permissions or
+ * visibility. Do this by first removing then
+ * re-adding (if required) the file */
+ if (update)
+ sysfs_hash_and_remove(dir_sd, (*attr)->name);
+ if (grp->is_visible) {
+ mode = grp->is_visible(kobj, *attr, i);
+ if (!mode)
+ continue;
+ }
+ error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR,
+ (*attr)->mode | mode);
+ if (unlikely(error))
+ break;
+ }
if (error)
remove_files(dir_sd, kobj, grp);
return error;
}
-int sysfs_create_group(struct kobject * kobj,
- const struct attribute_group * grp)
+static int internal_create_group(struct kobject *kobj, int update,
+ const struct attribute_group *grp)
{
struct sysfs_dirent *sd;
int error;
- BUG_ON(!kobj || !kobj->sd);
+ BUG_ON(!kobj || (!update && !kobj->sd));
+
+ /* Updates may happen before the object has been instantiated */
+ if (unlikely(update && !kobj->sd))
+ return -EINVAL;
if (grp->name) {
error = sysfs_create_subdir(kobj, grp->name, &sd);
@@ -60,7 +75,7 @@ int sysfs_create_group(struct kobject * kobj,
} else
sd = kobj->sd;
sysfs_get(sd);
- error = create_files(sd, kobj, grp);
+ error = create_files(sd, kobj, grp, update);
if (error) {
if (grp->name)
sysfs_remove_subdir(sd);
@@ -69,6 +84,47 @@ int sysfs_create_group(struct kobject * kobj,
return error;
}
+/**
+ * sysfs_create_group - given a directory kobject, create an attribute group
+ * @kobj: The kobject to create the group on
+ * @grp: The attribute group to create
+ *
+ * This function creates a group for the first time. It will explicitly
+ * warn and error if any of the attribute files being created already exist.
+ *
+ * Returns 0 on success or error.
+ */
+int sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return internal_create_group(kobj, 0, grp);
+}
+
+/**
+ * sysfs_update_group - given a directory kobject, create an attribute group
+ * @kobj: The kobject to create the group on
+ * @grp: The attribute group to create
+ *
+ * This function updates an attribute group. Unlike
+ * sysfs_create_group(), it will explicitly not warn or error if any
+ * of the attribute files being created already exist. Furthermore,
+ * if the visibility of the files has changed through the is_visible()
+ * callback, it will update the permissions and add or remove the
+ * relevant files.
+ *
+ * The primary use for this function is to call it after making a change
+ * that affects group visibility.
+ *
+ * Returns 0 on success or error.
+ */
+int sysfs_update_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return internal_create_group(kobj, 1, grp);
+}
+
+
+
void sysfs_remove_group(struct kobject * kobj,
const struct attribute_group * grp)
{
@@ -95,4 +151,5 @@ void sysfs_remove_group(struct kobject * kobj,
EXPORT_SYMBOL_GPL(sysfs_create_group);
+EXPORT_SYMBOL_GPL(sysfs_update_group);
EXPORT_SYMBOL_GPL(sysfs_remove_group);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index ff17f8da9b43..ce4e15f8aaeb 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -154,6 +154,8 @@ extern const struct file_operations sysfs_file_operations;
int sysfs_add_file(struct sysfs_dirent *dir_sd,
const struct attribute *attr, int type);
+int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
+ const struct attribute *attr, int type, mode_t amode);
/*
* bin.c
*/
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index ba5537d4bc15..2b34c8ca6c83 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -890,7 +890,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
kernel_lb_addr eloc;
- uint32_t elen;
+ uint32_t bsize;
block = udf_new_block(inode->i_sb, inode,
iinfo->i_location.partitionReferenceNum,
@@ -903,9 +903,9 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
eloc.logicalBlockNum = block;
eloc.partitionReferenceNum =
iinfo->i_location.partitionReferenceNum;
- elen = inode->i_sb->s_blocksize;
- iinfo->i_lenExtents = elen;
- udf_add_aext(inode, &epos, eloc, elen, 0);
+ bsize = inode->i_sb->s_blocksize;
+ iinfo->i_lenExtents = bsize;
+ udf_add_aext(inode, &epos, eloc, bsize, 0);
brelse(epos.bh);
block = udf_get_pblock(inode->i_sb, block,
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 1e7598fb9787..0d9ada173739 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -277,7 +277,7 @@ static void ufs_change_blocknr(struct inode *inode, sector_t beg,
if (!page)/* it was truncated */
continue;
if (IS_ERR(page)) {/* or EIO */
- ufs_error(inode->i_sb, __FUNCTION__,
+ ufs_error(inode->i_sb, __func__,
"read of page %llu failed\n",
(unsigned long long)index);
continue;
@@ -308,7 +308,7 @@ static void ufs_change_blocknr(struct inode *inode, sector_t beg,
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
- ufs_error(inode->i_sb, __FUNCTION__,
+ ufs_error(inode->i_sb, __func__,
"read of block failed\n");
break;
}
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index ef563fc8d72c..df0bef18742d 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -179,7 +179,7 @@ bad_entry:
goto fail;
Eend:
p = (struct ufs_dir_entry *)(kaddr + offs);
- ufs_error(sb, __FUNCTION__,
+ ufs_error(sb, __func__,
"entry in directory #%lu spans the page boundary"
"offset=%lu",
dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs);
@@ -284,7 +284,7 @@ struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry,
kaddr += ufs_last_byte(dir, n) - reclen;
while ((char *) de <= kaddr) {
if (de->d_reclen == 0) {
- ufs_error(dir->i_sb, __FUNCTION__,
+ ufs_error(dir->i_sb, __func__,
"zero-length directory entry");
ufs_put_page(page);
goto out;
@@ -356,7 +356,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
goto got_it;
}
if (de->d_reclen == 0) {
- ufs_error(dir->i_sb, __FUNCTION__,
+ ufs_error(dir->i_sb, __func__,
"zero-length directory entry");
err = -EIO;
goto out_unlock;
@@ -456,7 +456,7 @@ ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct page *page = ufs_get_page(inode, n);
if (IS_ERR(page)) {
- ufs_error(sb, __FUNCTION__,
+ ufs_error(sb, __func__,
"bad page in #%lu",
inode->i_ino);
filp->f_pos += PAGE_CACHE_SIZE - offset;
@@ -475,7 +475,7 @@ ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);
for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {
if (de->d_reclen == 0) {
- ufs_error(sb, __FUNCTION__,
+ ufs_error(sb, __func__,
"zero-length directory entry");
ufs_put_page(page);
return -EIO;
@@ -536,7 +536,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
while ((char*)de < (char*)dir) {
if (de->d_reclen == 0) {
- ufs_error(inode->i_sb, __FUNCTION__,
+ ufs_error(inode->i_sb, __func__,
"zero-length directory entry");
err = -EIO;
goto out;
@@ -633,7 +633,7 @@ int ufs_empty_dir(struct inode * inode)
while ((char *)de <= kaddr) {
if (de->d_reclen == 0) {
- ufs_error(inode->i_sb, __FUNCTION__,
+ ufs_error(inode->i_sb, __func__,
"zero-length directory entry: "
"kaddr=%p, de=%p\n", kaddr, de);
goto not_empty;
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 5446b888fc8e..39f877898565 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -929,7 +929,7 @@ void ufs_delete_inode (struct inode * inode)
old_i_size = inode->i_size;
inode->i_size = 0;
if (inode->i_blocks && ufs_truncate(inode, old_i_size))
- ufs_warning(inode->i_sb, __FUNCTION__, "ufs_truncate failed\n");
+ ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n");
ufs_free_inode (inode);
unlock_kernel();
return;
diff --git a/fs/ufs/swab.h b/fs/ufs/swab.h
index 1683d2bee614..8d974c4fd18b 100644
--- a/fs/ufs/swab.h
+++ b/fs/ufs/swab.h
@@ -40,25 +40,7 @@ cpu_to_fs64(struct super_block *sbp, u64 n)
return (__force __fs64)cpu_to_be64(n);
}
-static __inline u32
-fs64_add(struct super_block *sbp, u32 *n, int d)
-{
- if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
- return *n = cpu_to_le64(le64_to_cpu(*n)+d);
- else
- return *n = cpu_to_be64(be64_to_cpu(*n)+d);
-}
-
-static __inline u32
-fs64_sub(struct super_block *sbp, u32 *n, int d)
-{
- if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
- return *n = cpu_to_le64(le64_to_cpu(*n)-d);
- else
- return *n = cpu_to_be64(be64_to_cpu(*n)-d);
-}
-
-static __inline u32
+static inline u32
fs32_to_cpu(struct super_block *sbp, __fs32 n)
{
if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
@@ -80,18 +62,18 @@ static inline void
fs32_add(struct super_block *sbp, __fs32 *n, int d)
{
if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
- *(__le32 *)n = cpu_to_le32(le32_to_cpu(*(__le32 *)n)+d);
+ le32_add_cpu((__le32 *)n, d);
else
- *(__be32 *)n = cpu_to_be32(be32_to_cpu(*(__be32 *)n)+d);
+ be32_add_cpu((__be32 *)n, d);
}
static inline void
fs32_sub(struct super_block *sbp, __fs32 *n, int d)
{
if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
- *(__le32 *)n = cpu_to_le32(le32_to_cpu(*(__le32 *)n)-d);
+ le32_add_cpu((__le32 *)n, -d);
else
- *(__be32 *)n = cpu_to_be32(be32_to_cpu(*(__be32 *)n)-d);
+ be32_add_cpu((__be32 *)n, -d);
}
static inline u16
@@ -116,18 +98,18 @@ static inline void
fs16_add(struct super_block *sbp, __fs16 *n, int d)
{
if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
- *(__le16 *)n = cpu_to_le16(le16_to_cpu(*(__le16 *)n)+d);
+ le16_add_cpu((__le16 *)n, d);
else
- *(__be16 *)n = cpu_to_be16(be16_to_cpu(*(__be16 *)n)+d);
+ be16_add_cpu((__be16 *)n, d);
}
static inline void
fs16_sub(struct super_block *sbp, __fs16 *n, int d)
{
if (UFS_SB(sbp)->s_bytesex == BYTESEX_LE)
- *(__le16 *)n = cpu_to_le16(le16_to_cpu(*(__le16 *)n)-d);
+ le16_add_cpu((__le16 *)n, -d);
else
- *(__be16 *)n = cpu_to_be16(be16_to_cpu(*(__be16 *)n)-d);
+ be16_add_cpu((__be16 *)n, -d);
}
#endif /* _UFS_SWAB_H */
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h
index fcb9231bb9ed..244a1aaa940e 100644
--- a/fs/ufs/ufs.h
+++ b/fs/ufs/ufs.h
@@ -66,7 +66,7 @@ struct ufs_inode_info {
#ifdef CONFIG_UFS_DEBUG
# define UFSD(f, a...) { \
printk ("UFSD (%s, %d): %s:", \
- __FILE__, __LINE__, __FUNCTION__); \
+ __FILE__, __LINE__, __func__); \
printk (f, ## a); \
}
#else
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index cd450bea9f1a..5b66162d0747 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -176,15 +176,10 @@ static inline int vfat_is_used_badchars(const wchar_t *s, int len)
for (i = 0; i < len; i++)
if (vfat_bad_char(s[i]))
return -EINVAL;
- return 0;
-}
-static int vfat_valid_longname(const unsigned char *name, unsigned int len)
-{
- if (name[len - 1] == ' ')
+ if (s[i - 1] == ' ') /* last character cannot be space */
return -EINVAL;
- if (len >= 256)
- return -ENAMETOOLONG;
+
return 0;
}
@@ -477,7 +472,7 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
if (utf8) {
int name_len = strlen(name);
- *outlen = utf8_mbstowcs((wchar_t *)outname, name, PAGE_SIZE);
+ *outlen = utf8_mbstowcs((wchar_t *)outname, name, PATH_MAX);
/*
* We stripped '.'s before and set len appropriately,
@@ -485,11 +480,14 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
*/
*outlen -= (name_len - len);
+ if (*outlen > 255)
+ return -ENAMETOOLONG;
+
op = &outname[*outlen * sizeof(wchar_t)];
} else {
if (nls) {
for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260;
+ i < len && *outlen <= 255;
*outlen += 1)
{
if (escape && (*ip == ':')) {
@@ -525,18 +523,20 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
op += 2;
}
}
+ if (i < len)
+ return -ENAMETOOLONG;
} else {
for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260;
+ i < len && *outlen <= 255;
i++, *outlen += 1)
{
*op++ = *ip++;
*op++ = 0;
}
+ if (i < len)
+ return -ENAMETOOLONG;
}
}
- if (*outlen > 260)
- return -ENAMETOOLONG;
*longlen = *outlen;
if (*outlen % 13) {
@@ -565,7 +565,6 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name,
struct fat_mount_options *opts = &sbi->options;
struct msdos_dir_slot *ps;
struct msdos_dir_entry *de;
- unsigned long page;
unsigned char cksum, lcase;
unsigned char msdos_name[MSDOS_NAME];
wchar_t *uname;
@@ -574,15 +573,11 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name,
loff_t offset;
*nr_slots = 0;
- err = vfat_valid_longname(name, len);
- if (err)
- return err;
- page = __get_free_page(GFP_KERNEL);
- if (!page)
+ uname = __getname();
+ if (!uname)
return -ENOMEM;
- uname = (wchar_t *)page;
err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
opts->unicode_xlate, opts->utf8, sbi->nls_io);
if (err)
@@ -634,7 +629,7 @@ shortname:
de->starthi = cpu_to_le16(cluster >> 16);
de->size = 0;
out_free:
- free_page(page);
+ __putname(uname);
return err;
}
@@ -1003,7 +998,7 @@ static const struct inode_operations vfat_dir_inode_operations = {
.mkdir = vfat_mkdir,
.rmdir = vfat_rmdir,
.rename = vfat_rename,
- .setattr = fat_notify_change,
+ .setattr = fat_setattr,
.getattr = fat_getattr,
};
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 422f29c06c77..28fe8bae1037 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20070126
+#define ACPI_CA_VERSION 0x20080321
/*
* OS name, used for the _OS object. The _OS object is essentially obsolete,
@@ -150,6 +150,17 @@
#define ACPI_OBJ_NUM_OPERANDS 8
#define ACPI_OBJ_MAX_OPERAND 7
+/* Number of elements in the Result Stack frame, can be an arbitrary value */
+
+#define ACPI_RESULTS_FRAME_OBJ_NUM 8
+
+/*
+ * Maximal number of elements the Result Stack can contain,
+ * it may be an arbitray value not exceeding the types of
+ * result_size and result_count (now u8).
+ */
+#define ACPI_RESULTS_OBJ_NUM_MAX 255
+
/* Names within the namespace are 4 bytes long */
#define ACPI_NAME_SIZE 4
diff --git a/include/acpi/acdebug.h b/include/acpi/acdebug.h
index d626bb1d2973..c5a1b50d8d94 100644
--- a/include/acpi/acdebug.h
+++ b/include/acpi/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 389d772c7d5b..788f88782012 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,19 +97,23 @@ typedef const struct acpi_dmtable_info {
#define ACPI_DMT_CHKSUM 20
#define ACPI_DMT_SPACEID 21
#define ACPI_DMT_GAS 22
-#define ACPI_DMT_DMAR 23
-#define ACPI_DMT_MADT 24
-#define ACPI_DMT_SRAT 25
-#define ACPI_DMT_EXIT 26
-#define ACPI_DMT_SIG 27
+#define ACPI_DMT_ASF 23
+#define ACPI_DMT_DMAR 24
+#define ACPI_DMT_HEST 25
+#define ACPI_DMT_HESTNTFY 26
+#define ACPI_DMT_HESTNTYP 27
+#define ACPI_DMT_MADT 28
+#define ACPI_DMT_SRAT 29
+#define ACPI_DMT_EXIT 30
+#define ACPI_DMT_SIG 31
typedef
-void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table);
+void (*acpi_dmtable_handler) (struct acpi_table_header * table);
struct acpi_dmtable_data {
char *signature;
struct acpi_dmtable_info *table_info;
- ACPI_TABLE_HANDLER table_handler;
+ acpi_dmtable_handler table_handler;
char *name;
};
@@ -149,6 +153,7 @@ extern struct acpi_dmtable_info acpi_dm_table_info_asf3[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf4[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[];
extern struct acpi_dmtable_info acpi_dm_table_info_boot[];
+extern struct acpi_dmtable_info acpi_dm_table_info_bert[];
extern struct acpi_dmtable_info acpi_dm_table_info_cpep[];
extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[];
extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[];
@@ -158,11 +163,17 @@ extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[];
extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[];
extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[];
extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
+extern struct acpi_dmtable_info acpi_dm_table_info_einj[];
+extern struct acpi_dmtable_info acpi_dm_table_info_einj0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_erst[];
extern struct acpi_dmtable_info acpi_dm_table_info_facs[];
extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[];
extern struct acpi_dmtable_info acpi_dm_table_info_fadt2[];
extern struct acpi_dmtable_info acpi_dm_table_info_gas[];
extern struct acpi_dmtable_info acpi_dm_table_info_header[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hest[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hest9[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hest_notify[];
extern struct acpi_dmtable_info acpi_dm_table_info_hpet[];
extern struct acpi_dmtable_info acpi_dm_table_info_madt[];
extern struct acpi_dmtable_info acpi_dm_table_info_madt0[];
@@ -180,6 +191,7 @@ extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[];
extern struct acpi_dmtable_info acpi_dm_table_info_rsdp1[];
extern struct acpi_dmtable_info acpi_dm_table_info_rsdp2[];
extern struct acpi_dmtable_info acpi_dm_table_info_sbst[];
+extern struct acpi_dmtable_info acpi_dm_table_info_slic[];
extern struct acpi_dmtable_info acpi_dm_table_info_slit[];
extern struct acpi_dmtable_info acpi_dm_table_info_spcr[];
extern struct acpi_dmtable_info acpi_dm_table_info_spmi[];
@@ -194,7 +206,7 @@ extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[];
*/
void acpi_dm_dump_data_table(struct acpi_table_header *table);
-void
+acpi_status
acpi_dm_dump_table(u32 table_length,
u32 table_offset,
void *table,
@@ -213,9 +225,13 @@ void acpi_dm_dump_cpep(struct acpi_table_header *table);
void acpi_dm_dump_dmar(struct acpi_table_header *table);
+void acpi_dm_dump_einj(struct acpi_table_header *table);
+
+void acpi_dm_dump_erst(struct acpi_table_header *table);
+
void acpi_dm_dump_fadt(struct acpi_table_header *table);
-void acpi_dm_dump_srat(struct acpi_table_header *table);
+void acpi_dm_dump_hest(struct acpi_table_header *table);
void acpi_dm_dump_mcfg(struct acpi_table_header *table);
@@ -227,6 +243,8 @@ void acpi_dm_dump_rsdt(struct acpi_table_header *table);
void acpi_dm_dump_slit(struct acpi_table_header *table);
+void acpi_dm_dump_srat(struct acpi_table_header *table);
+
void acpi_dm_dump_xsdt(struct acpi_table_header *table);
/*
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index 7f690bb0f02f..910f018d92c7 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,9 @@
acpi_status
acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc);
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc);
+
acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *rgn_desc);
acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc);
@@ -68,10 +71,18 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
union acpi_parse_object *op);
acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
union acpi_operand_object *obj_desc);
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
acpi_status acpi_ds_initialize_region(acpi_handle obj_handle);
/*
@@ -269,6 +280,8 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state);
void acpi_ds_clear_operands(struct acpi_walk_state *walk_state);
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state);
+
/*
* dswscope - Scope Stack manipulation
*/
@@ -303,7 +316,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
u32 aml_length,
struct acpi_evaluate_info *info, u8 pass_number);
-acpi_status
+void
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
struct acpi_walk_state *walk_state);
@@ -316,21 +329,11 @@ void
acpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
struct acpi_thread_state *thread);
-acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state);
-
-acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state);
-
acpi_status acpi_ds_result_stack_clear(struct acpi_walk_state *walk_state);
struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
*thread);
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_ds_result_remove(union acpi_operand_object **object,
- u32 index, struct acpi_walk_state *walk_state);
-#endif
-
acpi_status
acpi_ds_result_pop(union acpi_operand_object **object,
struct acpi_walk_state *walk_state);
@@ -339,8 +342,4 @@ acpi_status
acpi_ds_result_push(union acpi_operand_object *object,
struct acpi_walk_state *walk_state);
-acpi_status
-acpi_ds_result_pop_from_bottom(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state);
-
#endif /* _ACDISPAT_H_ */
diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h
index d23cdf326808..d5d099bf349c 100644
--- a/include/acpi/acevents.h
+++ b/include/acpi/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index b73f18a48785..1f591171bf31 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 47a1fd8f2d8a..74ad971241db 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -170,10 +170,14 @@ ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
/*
- * Global lock semaphore works in conjunction with the actual HW global lock
+ * Global lock mutex is an actual AML mutex object
+ * Global lock semaphore works in conjunction with the HW global lock
*/
-ACPI_EXTERN acpi_mutex acpi_gbl_global_lock_mutex;
+ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
+ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
+ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
+ACPI_EXTERN u8 acpi_gbl_global_lock_present;
/*
* Spinlocks are used for interfaces that can be possibly called at
@@ -213,27 +217,33 @@ ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify;
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
+ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
+ACPI_EXTERN void *acpi_gbl_table_handler_context;
ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
+/* Owner ID support */
+
+ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
+ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
+ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
+
/* Misc */
ACPI_EXTERN u32 acpi_gbl_original_mode;
ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
ACPI_EXTERN u32 acpi_gbl_ps_find_count;
-ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
-ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
-ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
-ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
-ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
-ACPI_EXTERN u8 acpi_gbl_global_lock_present;
ACPI_EXTERN u8 acpi_gbl_events_initialized;
ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
+#ifndef DEFINE_ACPI_GLOBALS
+
+/* Other miscellaneous */
+
extern u8 acpi_gbl_shutdown;
extern u32 acpi_gbl_startup_flags;
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
@@ -241,6 +251,8 @@ extern const char *acpi_gbl_highest_dstate_names[4];
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
+#endif
+
/* Exception codes */
extern char const *acpi_gbl_exception_names_env[];
@@ -255,8 +267,6 @@ extern char const *acpi_gbl_exception_names_ctrl[];
*
****************************************************************************/
-#define NUM_NS_TYPES ACPI_TYPE_INVALID+1
-
#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
#define NUM_PREDEFINED_NAMES 10
#else
@@ -267,7 +277,7 @@ ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
-extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES];
+extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES];
@@ -275,8 +285,8 @@ extern const struct acpi_predefined_names
ACPI_EXTERN u32 acpi_gbl_current_node_count;
ACPI_EXTERN u32 acpi_gbl_current_node_size;
ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count;
-ACPI_EXTERN acpi_size acpi_gbl_entry_stack_pointer;
-ACPI_EXTERN acpi_size acpi_gbl_lowest_stack_pointer;
+ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer;
+ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer;
ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
#endif
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index 4053df943453..d4fb9bbc903c 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index ce7c9d653910..e249ce5d3300 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -215,8 +215,6 @@ acpi_ex_create_region(u8 * aml_start,
u32 aml_length,
u8 region_space, struct acpi_walk_state *walk_state);
-acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state);
-
acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state);
acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state);
@@ -248,9 +246,16 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
struct acpi_walk_state *walk_state);
acpi_status
+acpi_ex_acquire_mutex_object(u16 timeout,
+ union acpi_operand_object *obj_desc,
+ acpi_thread_id thread_id);
+
+acpi_status
acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc);
+
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread);
void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc);
@@ -455,9 +460,9 @@ void acpi_ex_relinquish_interpreter(void);
void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
-u8 acpi_ex_acquire_global_lock(u32 rule);
+void acpi_ex_acquire_global_lock(u32 rule);
-void acpi_ex_release_global_lock(u8 locked);
+void acpi_ex_release_global_lock(u32 rule);
void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string);
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 202cd4242ba1..c5cdc32ac2f8 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -522,9 +522,8 @@ struct acpi_thread_state {
* AML arguments
*/
struct acpi_result_values {
- ACPI_STATE_COMMON u8 num_results;
- u8 last_insert;
- union acpi_operand_object *obj_desc[ACPI_OBJ_NUM_OPERANDS];
+ ACPI_STATE_COMMON
+ union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM];
};
typedef
@@ -604,6 +603,7 @@ union acpi_parse_value {
union acpi_parse_object *next; /* Next op */\
struct acpi_namespace_node *node; /* For use by interpreter */\
union acpi_parse_value value; /* Value or args associated with the opcode */\
+ u8 arg_list_length; /* Number of elements in the arg list */\
ACPI_DISASM_ONLY_MEMBERS (\
u8 disasm_flags; /* Used during AML disassembly */\
u8 disasm_opcode; /* Subtype used for disassembly */\
@@ -696,6 +696,8 @@ struct acpi_parse_state {
#define ACPI_PARSEOP_NAMED 0x02
#define ACPI_PARSEOP_DEFERRED 0x04
#define ACPI_PARSEOP_BYTELIST 0x08
+#define ACPI_PARSEOP_IN_STACK 0x10
+#define ACPI_PARSEOP_TARGET 0x20
#define ACPI_PARSEOP_IN_CACHE 0x80
/* Parse object disasm_flags */
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 99d171c87c84..fb41a3b802fc 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,30 +61,6 @@
#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
-#ifdef ACPI_NO_INTEGER64_SUPPORT
-/*
- * acpi_integer is 32-bits, no 64-bit support on this platform
- */
-#define ACPI_LODWORD(l) ((u32)(l))
-#define ACPI_HIDWORD(l) ((u32)(0))
-
-#else
-
-/*
- * Full 64-bit address/integer on both 32-bit and 64-bit platforms
- */
-#define ACPI_LODWORD(l) ((u32)(u64)(l))
-#define ACPI_HIDWORD(l) ((u32)(((*(struct uint64_struct *)(void *)(&l))).hi))
-#endif
-
-/*
- * printf() format helpers
- */
-
-/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */
-
-#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i)
-
/*
* Extract data using a pointer. Any more than a byte and we
* get into potential aligment issues -- see the STORE macros below.
@@ -122,6 +98,31 @@
#endif
/*
+ * Full 64-bit integer must be available on both 32-bit and 64-bit platforms
+ */
+struct acpi_integer_overlay {
+ u32 lo_dword;
+ u32 hi_dword;
+};
+
+#define ACPI_LODWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword)
+#define ACPI_HIDWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword)
+
+/*
+ * printf() format helpers
+ */
+
+/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */
+
+#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i)
+
+#if ACPI_MACHINE_WIDTH == 64
+#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i)
+#else
+#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i)
+#endif
+
+/*
* Macros for moving data around to/from buffers that are possibly unaligned.
* If the hardware supports the transfer of unaligned data, just do the store.
* Otherwise, we have to move one byte at a time.
@@ -137,29 +138,29 @@
/* These macros reverse the bytes during the move, converting little-endian to big endian */
- /* Big Endian <== Little Endian */
- /* Hi...Lo Lo...Hi */
+ /* Big Endian <== Little Endian */
+ /* Hi...Lo Lo...Hi */
/* 16-bit source, 16/32/64 destination */
#define ACPI_MOVE_16_TO_16(d,s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\
- (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];}
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];}
#define ACPI_MOVE_16_TO_32(d,s) {(*(u32 *)(void *)(d))=0;\
- ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
- ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
+ ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
#define ACPI_MOVE_16_TO_64(d,s) {(*(u64 *)(void *)(d))=0;\
- ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
- ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
+ ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
/* 32-bit source, 16/32/64 destination */
#define ACPI_MOVE_32_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */
#define ACPI_MOVE_32_TO_32(d,s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\
- (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\
- (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
- (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\
+ (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
#define ACPI_MOVE_32_TO_64(d,s) {(*(u64 *)(void *)(d))=0;\
((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index 34bfae8a05f3..c1343a9265fa 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 5ef38a6c8a61..713b30903fe5 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -113,7 +113,8 @@ acpi_ns_parse_table(acpi_native_uint table_index,
acpi_status
acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index);
+ acpi_native_uint table_index,
+ struct acpi_namespace_node *start_node);
/*
* nsaccess - Top-level namespace access
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index 7e1211a8b8fa..e9657dac69b7 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -155,8 +155,9 @@ struct acpi_object_event {
struct acpi_object_mutex {
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
u16 acquisition_depth; /* Allow multiple Acquires, same thread */
- struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
acpi_mutex os_mutex; /* Actual OS synchronization object */
+ acpi_thread_id thread_id; /* Current owner of the mutex */
+ struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
union acpi_operand_object *prev; /* Link for list of acquired mutexes */
union acpi_operand_object *next; /* Link for list of acquired mutexes */
struct acpi_namespace_node *node; /* Containing namespace node */
diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h
index e6f76a280a94..dfdf63327885 100644
--- a/include/acpi/acopcode.h
+++ b/include/acpi/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -233,7 +233,7 @@
#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING)
#define ARGI_DEBUG_OP ARG_NONE
-#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING)
#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF)
@@ -246,7 +246,7 @@
#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
#define ARGI_IF_OP ARGI_INVALID_OPCODE
-#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE
#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index c090a8b0bc99..e17873defcec 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h
index 85c358e21014..23ee0fbf5619 100644
--- a/include/acpi/acparser.h
+++ b/include/acpi/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -109,6 +109,8 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode);
char *acpi_ps_get_opcode_name(u16 opcode);
+u8 acpi_ps_get_argument_count(u32 op_type);
+
/*
* psparse - top level parsing routines
*/
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index 2e5f00d3ea0d..c515ef6cc89e 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 4839f2af94c3..d4a560d2deb6 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -8,7 +8,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index d970f7f99549..2c3806e6546f 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -119,6 +119,11 @@ acpi_status
acpi_get_table_by_index(acpi_native_uint table_index,
struct acpi_table_header **out_table);
+acpi_status
+acpi_install_table_handler(acpi_tbl_handler handler, void *context);
+
+acpi_status acpi_remove_table_handler(acpi_tbl_handler handler);
+
/*
* Namespace and name interfaces
*/
diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h
index 9486ab266a5e..eef5bd7a59fa 100644
--- a/include/acpi/acresrc.h
+++ b/include/acpi/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,6 +94,7 @@ typedef const struct acpi_rsconvert_info {
#define ACPI_RSC_BITMASK16 18
#define ACPI_RSC_EXIT_NE 19
#define ACPI_RSC_EXIT_LE 20
+#define ACPI_RSC_EXIT_EQ 21
/* Resource Conversion sub-opcodes */
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index 88482655407f..a907c67d651e 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -80,12 +80,15 @@ struct acpi_walk_state {
u16 opcode; /* Current AML opcode */
u8 next_op_info; /* Info about next_op */
u8 num_operands; /* Stack pointer for Operands[] array */
+ u8 operand_index; /* Index into operand stack, to be used by acpi_ds_obj_stack_push */
acpi_owner_id owner_id; /* Owner of objects created during the walk */
u8 last_predicate; /* Result of last predicate */
u8 current_result;
u8 return_used;
u8 scope_depth;
u8 pass_number; /* Parse pass during table load */
+ u8 result_size; /* Total elements for the result stack */
+ u8 result_count; /* Current number of occupied elements of result stack */
u32 aml_offset;
u32 arg_types;
u32 method_breakpoint; /* For single stepping */
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index 2b9f46f9da4d..4b36a55b0b3b 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 955adfb8d64c..1ebbe883f786 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index a1b1b2ee3e51..9af239bd1153 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,20 +58,28 @@
* it more difficult to inadvertently type in the wrong signature.
*/
#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */
+#define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */
#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */
#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */
#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */
#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */
#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */
+#define ACPI_SIG_EINJ "EINJ" /* Error Injection table */
+#define ACPI_SIG_ERST "ERST" /* Error Record Serialization Table */
+#define ACPI_SIG_HEST "HEST" /* Hardware Error Source Table */
#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */
+#define ACPI_SIG_IBFT "IBFT" /* i_sCSI Boot Firmware Table */
#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */
#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */
#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
+#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */
#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */
#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */
#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */
#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */
#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */
+#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */
+#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */
#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */
/*
@@ -86,13 +94,25 @@
* portable, so do not use any other bitfield types.
*/
-/* Common Sub-table header (used in MADT, SRAT, etc.) */
+/* Common Subtable header (used in MADT, SRAT, etc.) */
struct acpi_subtable_header {
u8 type;
u8 length;
};
+/* Common Subtable header for WHEA tables (EINJ, ERST, WDAT) */
+
+struct acpi_whea_header {
+ u8 action;
+ u8 instruction;
+ u8 flags;
+ u8 reserved;
+ struct acpi_generic_address register_region;
+ u64 value; /* Value used with Read/Write register */
+ u64 mask; /* Bitmask required for this register instruction */
+};
+
/*******************************************************************************
*
* ASF - Alert Standard Format table (Signature "ASF!")
@@ -204,6 +224,35 @@ struct acpi_asf_address {
/*******************************************************************************
*
+ * BERT - Boot Error Record Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_bert {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 region_length; /* Length of the boot error region */
+ u64 address; /* Physical addresss of the error region */
+};
+
+/* Boot Error Region */
+
+struct acpi_bert_region {
+ u32 block_status;
+ u32 raw_data_offset;
+ u32 raw_data_length;
+ u32 data_length;
+ u32 error_severity;
+};
+
+/* block_status Flags */
+
+#define ACPI_BERT_UNCORRECTABLE (1)
+#define ACPI_BERT_CORRECTABLE (2)
+#define ACPI_BERT_MULTIPLE_UNCORRECTABLE (4)
+#define ACPI_BERT_MULTIPLE_CORRECTABLE (8)
+
+/*******************************************************************************
+ *
* BOOT - Simple Boot Flag Table
*
******************************************************************************/
@@ -350,6 +399,352 @@ struct acpi_table_ecdt {
/*******************************************************************************
*
+ * EINJ - Error Injection Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_einj {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length;
+ u32 reserved;
+ u32 entries;
+};
+
+/* EINJ Injection Instruction Entries (actions) */
+
+struct acpi_einj_entry {
+ struct acpi_whea_header whea_header; /* Common header for WHEA tables */
+};
+
+/* Values for Action field above */
+
+enum acpi_einj_actions {
+ ACPI_EINJ_BEGIN_OPERATION = 0,
+ ACPI_EINJ_GET_TRIGGER_TABLE = 1,
+ ACPI_EINJ_SET_ERROR_TYPE = 2,
+ ACPI_EINJ_GET_ERROR_TYPE = 3,
+ ACPI_EINJ_END_OPERATION = 4,
+ ACPI_EINJ_EXECUTE_OPERATION = 5,
+ ACPI_EINJ_CHECK_BUSY_STATUS = 6,
+ ACPI_EINJ_GET_COMMAND_STATUS = 7,
+ ACPI_EINJ_ACTION_RESERVED = 8, /* 8 and greater are reserved */
+ ACPI_EINJ_TRIGGER_ERROR = 0xFF /* Except for this value */
+};
+
+/* Values for Instruction field above */
+
+enum acpi_einj_instructions {
+ ACPI_EINJ_READ_REGISTER = 0,
+ ACPI_EINJ_READ_REGISTER_VALUE = 1,
+ ACPI_EINJ_WRITE_REGISTER = 2,
+ ACPI_EINJ_WRITE_REGISTER_VALUE = 3,
+ ACPI_EINJ_NOOP = 4,
+ ACPI_EINJ_INSTRUCTION_RESERVED = 5 /* 5 and greater are reserved */
+};
+
+/* EINJ Trigger Error Action Table */
+
+struct acpi_einj_trigger {
+ u32 header_size;
+ u32 revision;
+ u32 table_size;
+ u32 entry_count;
+};
+
+/*******************************************************************************
+ *
+ * ERST - Error Record Serialization Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_erst {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length;
+ u32 reserved;
+ u32 entries;
+};
+
+/* ERST Serialization Entries (actions) */
+
+struct acpi_erst_entry {
+ struct acpi_whea_header whea_header; /* Common header for WHEA tables */
+};
+
+/* Values for Action field above */
+
+enum acpi_erst_actions {
+ ACPI_ERST_BEGIN_WRITE_OPERATION = 0,
+ ACPI_ERST_BEGIN_READ_OPERATION = 1,
+ ACPI_ERST_BETGIN_CLEAR_OPERATION = 2,
+ ACPI_ERST_END_OPERATION = 3,
+ ACPI_ERST_SET_RECORD_OFFSET = 4,
+ ACPI_ERST_EXECUTE_OPERATION = 5,
+ ACPI_ERST_CHECK_BUSY_STATUS = 6,
+ ACPI_ERST_GET_COMMAND_STATUS = 7,
+ ACPI_ERST_GET_RECORD_IDENTIFIER = 8,
+ ACPI_ERST_SET_RECORD_IDENTIFIER = 9,
+ ACPI_ERST_GET_RECORD_COUNT = 10,
+ ACPI_ERST_BEGIN_DUMMY_WRIITE = 11,
+ ACPI_ERST_NOT_USED = 12,
+ ACPI_ERST_GET_ERROR_RANGE = 13,
+ ACPI_ERST_GET_ERROR_LENGTH = 14,
+ ACPI_ERST_GET_ERROR_ATTRIBUTES = 15,
+ ACPI_ERST_ACTION_RESERVED = 16 /* 16 and greater are reserved */
+};
+
+/* Values for Instruction field above */
+
+enum acpi_erst_instructions {
+ ACPI_ERST_READ_REGISTER = 0,
+ ACPI_ERST_READ_REGISTER_VALUE = 1,
+ ACPI_ERST_WRITE_REGISTER = 2,
+ ACPI_ERST_WRITE_REGISTER_VALUE = 3,
+ ACPI_ERST_NOOP = 4,
+ ACPI_ERST_LOAD_VAR1 = 5,
+ ACPI_ERST_LOAD_VAR2 = 6,
+ ACPI_ERST_STORE_VAR1 = 7,
+ ACPI_ERST_ADD = 8,
+ ACPI_ERST_SUBTRACT = 9,
+ ACPI_ERST_ADD_VALUE = 10,
+ ACPI_ERST_SUBTRACT_VALUE = 11,
+ ACPI_ERST_STALL = 12,
+ ACPI_ERST_STALL_WHILE_TRUE = 13,
+ ACPI_ERST_SKIP_NEXT_IF_TRUE = 14,
+ ACPI_ERST_GOTO = 15,
+ ACPI_ERST_SET_SRC_ADDRESS_BASE = 16,
+ ACPI_ERST_SET_DST_ADDRESS_BASE = 17,
+ ACPI_ERST_MOVE_DATA = 18,
+ ACPI_ERST_INSTRUCTION_RESERVED = 19 /* 19 and greater are reserved */
+};
+
+/*******************************************************************************
+ *
+ * HEST - Hardware Error Source Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_hest {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 error_source_count;
+};
+
+/* HEST subtable header */
+
+struct acpi_hest_header {
+ u16 type;
+};
+
+/* Values for Type field above for subtables */
+
+enum acpi_hest_types {
+ ACPI_HEST_TYPE_XPF_MACHINE_CHECK = 0,
+ ACPI_HEST_TYPE_XPF_CORRECTED_MACHINE_CHECK = 1,
+ ACPI_HEST_TYPE_XPF_UNUSED = 2,
+ ACPI_HEST_TYPE_XPF_NON_MASKABLE_INTERRUPT = 3,
+ ACPI_HEST_TYPE_IPF_CORRECTED_MACHINE_CHECK = 4,
+ ACPI_HEST_TYPE_IPF_CORRECTED_PLATFORM_ERROR = 5,
+ ACPI_HEST_TYPE_AER_ROOT_PORT = 6,
+ ACPI_HEST_TYPE_AER_ENDPOINT = 7,
+ ACPI_HEST_TYPE_AER_BRIDGE = 8,
+ ACPI_HEST_TYPE_GENERIC_HARDWARE_ERROR_SOURCE = 9,
+ ACPI_HEST_TYPE_RESERVED = 10 /* 10 and greater are reserved */
+};
+
+/*
+ * HEST Sub-subtables
+ */
+
+/* XPF Machine Check Error Bank */
+
+struct acpi_hest_xpf_error_bank {
+ u8 bank_number;
+ u8 clear_status_on_init;
+ u8 status_format;
+ u8 config_write_enable;
+ u32 control_register;
+ u64 control_init_data;
+ u32 status_register;
+ u32 address_register;
+ u32 misc_register;
+};
+
+/* Generic Error Status */
+
+struct acpi_hest_generic_status {
+ u32 block_status;
+ u32 raw_data_offset;
+ u32 raw_data_length;
+ u32 data_length;
+ u32 error_severity;
+};
+
+/* Generic Error Data */
+
+struct acpi_hest_generic_data {
+ u8 section_type[16];
+ u32 error_severity;
+ u16 revision;
+ u8 validation_bits;
+ u8 flags;
+ u32 error_data_length;
+ u8 fru_id[16];
+ u8 fru_text[20];
+};
+
+/* Common HEST structure for PCI/AER types below (6,7,8) */
+
+struct acpi_hest_aer_common {
+ u16 source_id;
+ u16 config_write_enable;
+ u8 flags;
+ u8 enabled;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u32 bus;
+ u16 device;
+ u16 function;
+ u16 device_control;
+ u16 reserved;
+ u32 uncorrectable_error_mask;
+ u32 uncorrectable_error_severity;
+ u32 correctable_error_mask;
+ u32 advanced_error_cababilities;
+};
+
+/* Hardware Error Notification */
+
+struct acpi_hest_notify {
+ u8 type;
+ u8 length;
+ u16 config_write_enable;
+ u32 poll_interval;
+ u32 vector;
+ u32 polling_threshold_value;
+ u32 polling_threshold_window;
+ u32 error_threshold_value;
+ u32 error_threshold_window;
+};
+
+/* Values for Notify Type field above */
+
+enum acpi_hest_notify_types {
+ ACPI_HEST_NOTIFY_POLLED = 0,
+ ACPI_HEST_NOTIFY_EXTERNAL = 1,
+ ACPI_HEST_NOTIFY_LOCAL = 2,
+ ACPI_HEST_NOTIFY_SCI = 3,
+ ACPI_HEST_NOTIFY_NMI = 4,
+ ACPI_HEST_NOTIFY_RESERVED = 5 /* 5 and greater are reserved */
+};
+
+/*
+ * HEST subtables
+ *
+ * From WHEA Design Document, 16 May 2007.
+ * Note: There is no subtable type 2 in this version of the document,
+ * and there are two different subtable type 3s.
+ */
+
+ /* 0: XPF Machine Check Exception */
+
+struct acpi_hest_xpf_machine_check {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u16 config_write_enable;
+ u8 flags;
+ u8 reserved1;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u64 global_capability_data;
+ u64 global_control_data;
+ u8 num_hardware_banks;
+ u8 reserved2[7];
+};
+
+/* 1: XPF Corrected Machine Check */
+
+struct acpi_table_hest_xpf_corrected {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u16 config_write_enable;
+ u8 flags;
+ u8 enabled;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ struct acpi_hest_notify notify;
+ u8 num_hardware_banks;
+ u8 reserved[3];
+};
+
+/* 3: XPF Non-Maskable Interrupt */
+
+struct acpi_hest_xpf_nmi {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u32 reserved;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u32 max_raw_data_length;
+};
+
+/* 4: IPF Corrected Machine Check */
+
+struct acpi_hest_ipf_corrected {
+ struct acpi_hest_header header;
+ u8 enabled;
+ u8 reserved;
+};
+
+/* 5: IPF Corrected Platform Error */
+
+struct acpi_hest_ipf_corrected_platform {
+ struct acpi_hest_header header;
+ u8 enabled;
+ u8 reserved;
+};
+
+/* 6: PCI Express Root Port AER */
+
+struct acpi_hest_aer_root {
+ struct acpi_hest_header header;
+ struct acpi_hest_aer_common aer;
+ u32 root_error_command;
+};
+
+/* 7: PCI Express AER (AER Endpoint) */
+
+struct acpi_hest_aer {
+ struct acpi_hest_header header;
+ struct acpi_hest_aer_common aer;
+};
+
+/* 8: PCI Express/PCI-X Bridge AER */
+
+struct acpi_hest_aer_bridge {
+ struct acpi_hest_header header;
+ struct acpi_hest_aer_common aer;
+ u32 secondary_uncorrectable_error_mask;
+ u32 secondary_uncorrectable_error_severity;
+ u32 secondary_advanced_capabilities;
+};
+
+/* 9: Generic Hardware Error Source */
+
+struct acpi_hest_generic {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u16 related_source_id;
+ u8 config_write_enable;
+ u8 enabled;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u32 max_raw_data_length;
+ struct acpi_generic_address error_status_address;
+ struct acpi_hest_notify notify;
+ u32 error_status_block_length;
+};
+
+/*******************************************************************************
+ *
* HPET - High Precision Event Timer table
*
******************************************************************************/
@@ -373,6 +768,96 @@ struct acpi_table_hpet {
/*******************************************************************************
*
+ * IBFT - Boot Firmware Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_ibft {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 reserved[12];
+};
+
+/* IBFT common subtable header */
+
+struct acpi_ibft_header {
+ u8 type;
+ u8 version;
+ u16 length;
+ u8 index;
+ u8 flags;
+};
+
+/* Values for Type field above */
+
+enum acpi_ibft_type {
+ ACPI_IBFT_TYPE_NOT_USED = 0,
+ ACPI_IBFT_TYPE_CONTROL = 1,
+ ACPI_IBFT_TYPE_INITIATOR = 2,
+ ACPI_IBFT_TYPE_NIC = 3,
+ ACPI_IBFT_TYPE_TARGET = 4,
+ ACPI_IBFT_TYPE_EXTENSIONS = 5,
+ ACPI_IBFT_TYPE_RESERVED = 6 /* 6 and greater are reserved */
+};
+
+/* IBFT subtables */
+
+struct acpi_ibft_control {
+ struct acpi_ibft_header header;
+ u16 extensions;
+ u16 initiator_offset;
+ u16 nic0_offset;
+ u16 target0_offset;
+ u16 nic1_offset;
+ u16 target1_offset;
+};
+
+struct acpi_ibft_initiator {
+ struct acpi_ibft_header header;
+ u8 sns_server[16];
+ u8 slp_server[16];
+ u8 primary_server[16];
+ u8 secondary_server[16];
+ u16 name_length;
+ u16 name_offset;
+};
+
+struct acpi_ibft_nic {
+ struct acpi_ibft_header header;
+ u8 ip_address[16];
+ u8 subnet_mask_prefix;
+ u8 origin;
+ u8 gateway[16];
+ u8 primary_dns[16];
+ u8 secondary_dns[16];
+ u8 dhcp[16];
+ u16 vlan;
+ u8 mac_address[6];
+ u16 pci_address;
+ u16 name_length;
+ u16 name_offset;
+};
+
+struct acpi_ibft_target {
+ struct acpi_ibft_header header;
+ u8 target_ip_address[16];
+ u16 target_ip_socket;
+ u8 target_boot_lun[8];
+ u8 chap_type;
+ u8 nic_association;
+ u16 target_name_length;
+ u16 target_name_offset;
+ u16 chap_name_length;
+ u16 chap_name_offset;
+ u16 chap_secret_length;
+ u16 chap_secret_offset;
+ u16 reverse_chap_name_length;
+ u16 reverse_chap_name_offset;
+ u16 reverse_chap_secret_length;
+ u16 reverse_chap_secret_offset;
+};
+
+/*******************************************************************************
+ *
* MADT - Multiple APIC Description Table
*
******************************************************************************/
@@ -697,6 +1182,78 @@ struct acpi_table_tcpa {
/*******************************************************************************
*
+ * UEFI - UEFI Boot optimization Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_uefi {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 identifier[16]; /* UUID identifier */
+ u16 data_offset; /* Offset of remaining data in table */
+ u8 data;
+};
+
+/*******************************************************************************
+ *
+ * WDAT - Watchdog Action Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_wdat {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length; /* Watchdog Header Length */
+ u16 pci_segment; /* PCI Segment number */
+ u8 pci_bus; /* PCI Bus number */
+ u8 pci_device; /* PCI Device number */
+ u8 pci_function; /* PCI Function number */
+ u8 reserved[3];
+ u32 timer_period; /* Period of one timer count (msec) */
+ u32 max_count; /* Maximum counter value supported */
+ u32 min_count; /* Minimum counter value */
+ u8 flags;
+ u8 reserved2[3];
+ u32 entries; /* Number of watchdog entries that follow */
+};
+
+/* WDAT Instruction Entries (actions) */
+
+struct acpi_wdat_entry {
+ struct acpi_whea_header whea_header; /* Common header for WHEA tables */
+};
+
+/* Values for Action field above */
+
+enum acpi_wdat_actions {
+ ACPI_WDAT_RESET = 1,
+ ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4,
+ ACPI_WDAT_GET_COUNTDOWN = 5,
+ ACPI_WDAT_SET_COUNTDOWN = 6,
+ ACPI_WDAT_GET_RUNNING_STATE = 8,
+ ACPI_WDAT_SET_RUNNING_STATE = 9,
+ ACPI_WDAT_GET_STOPPED_STATE = 10,
+ ACPI_WDAT_SET_STOPPED_STATE = 11,
+ ACPI_WDAT_GET_REBOOT = 16,
+ ACPI_WDAT_SET_REBOOT = 17,
+ ACPI_WDAT_GET_SHUTDOWN = 18,
+ ACPI_WDAT_SET_SHUTDOWN = 19,
+ ACPI_WDAT_GET_STATUS = 32,
+ ACPI_WDAT_SET_STATUS = 33,
+ ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */
+};
+
+/* Values for Instruction field above */
+
+enum acpi_wdat_instructions {
+ ACPI_WDAT_READ_VALUE = 0,
+ ACPI_WDAT_READ_COUNTDOWN = 1,
+ ACPI_WDAT_WRITE_VALUE = 2,
+ ACPI_WDAT_WRITE_COUNTDOWN = 3,
+ ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */
+ ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */
+};
+
+/*******************************************************************************
+ *
* WDRT - Watchdog Resource Table
*
******************************************************************************/
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index e73a38939120..dfea2d440488 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -323,27 +323,11 @@ struct uint32_struct {
#define acpi_semaphore void *
/*
- * Acpi integer width. In ACPI version 1, integers are
- * 32 bits. In ACPI version 2, integers are 64 bits.
- * Note that this pertains to the ACPI integer type only, not
- * other integers used in the implementation of the ACPI CA
+ * Acpi integer width. In ACPI version 1, integers are 32 bits. In ACPI
+ * version 2, integers are 64 bits. Note that this pertains to the ACPI integer
+ * type only, not other integers used in the implementation of the ACPI CA
* subsystem.
*/
-#ifdef ACPI_NO_INTEGER64_SUPPORT
-
-/* 32-bit integers only, no 64-bit support */
-
-typedef u32 acpi_integer;
-#define ACPI_INTEGER_MAX ACPI_UINT32_MAX
-#define ACPI_INTEGER_BIT_SIZE 32
-#define ACPI_MAX_DECIMAL_DIGITS 10 /* 2^32 = 4,294,967,296 */
-
-#define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 32-bit divide */
-
-#else
-
-/* 64-bit integers */
-
typedef unsigned long long acpi_integer;
#define ACPI_INTEGER_MAX ACPI_UINT64_MAX
#define ACPI_INTEGER_BIT_SIZE 64
@@ -352,7 +336,6 @@ typedef unsigned long long acpi_integer;
#if ACPI_MACHINE_WIDTH == 64
#define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 64-bit divide */
#endif
-#endif
#define ACPI_MAX64_DECIMAL_DIGITS 20
#define ACPI_MAX32_DECIMAL_DIGITS 10
@@ -419,14 +402,20 @@ typedef unsigned long long acpi_integer;
/*
* Standard notify values
*/
-#define ACPI_NOTIFY_BUS_CHECK (u8) 0
-#define ACPI_NOTIFY_DEVICE_CHECK (u8) 1
-#define ACPI_NOTIFY_DEVICE_WAKE (u8) 2
-#define ACPI_NOTIFY_EJECT_REQUEST (u8) 3
-#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (u8) 4
-#define ACPI_NOTIFY_FREQUENCY_MISMATCH (u8) 5
-#define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6
-#define ACPI_NOTIFY_POWER_FAULT (u8) 7
+#define ACPI_NOTIFY_BUS_CHECK (u8) 0x00
+#define ACPI_NOTIFY_DEVICE_CHECK (u8) 0x01
+#define ACPI_NOTIFY_DEVICE_WAKE (u8) 0x02
+#define ACPI_NOTIFY_EJECT_REQUEST (u8) 0x03
+#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (u8) 0x04
+#define ACPI_NOTIFY_FREQUENCY_MISMATCH (u8) 0x05
+#define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 0x06
+#define ACPI_NOTIFY_POWER_FAULT (u8) 0x07
+#define ACPI_NOTIFY_CAPABILITIES_CHECK (u8) 0x08
+#define ACPI_NOTIFY_DEVICE_PLD_CHECK (u8) 0x09
+#define ACPI_NOTIFY_RESERVED (u8) 0x0A
+#define ACPI_NOTIFY_LOCALITY_UPDATE (u8) 0x0B
+
+#define ACPI_NOTIFY_MAX 0x0B
/*
* Types associated with ACPI names and objects. The first group of
@@ -494,6 +483,8 @@ typedef u32 acpi_object_type;
#define ACPI_TYPE_INVALID 0x1E
#define ACPI_TYPE_NOT_FOUND 0xFF
+#define ACPI_NUM_NS_TYPES (ACPI_TYPE_INVALID + 1)
+
/*
* All I/O
*/
@@ -599,7 +590,7 @@ typedef u32 acpi_event_status;
#define ACPI_SYSTEM_NOTIFY 0x1
#define ACPI_DEVICE_NOTIFY 0x2
-#define ACPI_ALL_NOTIFY 0x3
+#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3
#define ACPI_MAX_SYS_NOTIFY 0x7f
@@ -654,46 +645,51 @@ typedef u8 acpi_adr_space_type;
/*
* External ACPI object definition
*/
+
+/*
+ * Note: Type == ACPI_TYPE_ANY (0) is used to indicate a NULL package element
+ * or an unresolved named reference.
+ */
union acpi_object {
acpi_object_type type; /* See definition of acpi_ns_type for values */
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_INTEGER */
acpi_integer value; /* The actual number */
} integer;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_STRING */
u32 length; /* # of bytes in string, excluding trailing null */
char *pointer; /* points to the string value */
} string;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_BUFFER */
u32 length; /* # of bytes in buffer */
u8 *pointer; /* points to the buffer */
} buffer;
struct {
- acpi_object_type type;
- u32 fill1;
- acpi_handle handle; /* object reference */
- } reference;
-
- struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_PACKAGE */
u32 count; /* # of elements in package */
union acpi_object *elements; /* Pointer to an array of ACPI_OBJECTs */
} package;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_LOCAL_REFERENCE */
+ acpi_object_type actual_type; /* Type associated with the Handle */
+ acpi_handle handle; /* object reference */
+ } reference;
+
+ struct {
+ acpi_object_type type; /* ACPI_TYPE_PROCESSOR */
u32 proc_id;
acpi_io_address pblk_address;
u32 pblk_length;
} processor;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_POWER */
u32 system_level;
u32 resource_order;
} power_resource;
@@ -747,6 +743,12 @@ struct acpi_system_info {
u32 debug_layer;
};
+/* Table Event Types */
+
+#define ACPI_TABLE_EVENT_LOAD 0x0
+#define ACPI_TABLE_EVENT_UNLOAD 0x1
+#define ACPI_NUM_TABLE_EVENTS 2
+
/*
* Types specific to the OS service interfaces
*/
@@ -776,6 +778,11 @@ acpi_status(*acpi_exception_handler) (acpi_status aml_status,
u16 opcode,
u32 aml_offset, void *context);
+/* Table Event handler (Load, load_table etc) and types */
+
+typedef
+acpi_status(*acpi_tbl_handler) (u32 event, void *table, void *context);
+
/* Address Spaces (For Operation Regions) */
typedef
@@ -990,6 +997,7 @@ struct acpi_vendor_uuid {
* Structures used to describe device resources
*/
struct acpi_resource_irq {
+ u8 descriptor_length;
u8 triggering;
u8 polarity;
u8 sharable;
@@ -1006,6 +1014,7 @@ struct acpi_resource_dma {
};
struct acpi_resource_start_dependent {
+ u8 descriptor_length;
u8 compatibility_priority;
u8 performance_robustness;
};
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index a2918547c73f..b42cadf07302 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,6 +116,8 @@ void acpi_ut_init_globals(void);
char *acpi_ut_get_mutex_name(u32 mutex_id);
+const char *acpi_ut_get_notify_name(u32 notify_value);
+
#endif
char *acpi_ut_get_type_name(acpi_object_type type);
diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h
index da53a4ef287a..ff851c5df698 100644
--- a/include/acpi/amlcode.h
+++ b/include/acpi/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h
index f7d541239da4..7b070e42b7c5 100644
--- a/include/acpi/amlresrc.h
+++ b/include/acpi/amlresrc.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index c785485e62a6..fcd2572e428c 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 3bb50494a38a..8996dba90cd9 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 6ed15a0978eb..9af464598682 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
index 9e19a704d484..15f3ae25c511 100644
--- a/include/asm-alpha/bitops.h
+++ b/include/asm-alpha/bitops.h
@@ -388,6 +388,11 @@ static inline int fls64(unsigned long x)
}
#endif
+static inline unsigned long __fls(unsigned long x)
+{
+ return fls64(x) - 1;
+}
+
static inline int fls(int x)
{
return fls64((unsigned int) x);
diff --git a/include/asm-alpha/bug.h b/include/asm-alpha/bug.h
index 39a3e2a5017d..695a5ee4b5d3 100644
--- a/include/asm-alpha/bug.h
+++ b/include/asm-alpha/bug.h
@@ -1,14 +1,24 @@
#ifndef _ALPHA_BUG_H
#define _ALPHA_BUG_H
+#include <linux/linkage.h>
+
#ifdef CONFIG_BUG
#include <asm/pal.h>
/* ??? Would be nice to use .gprel32 here, but we can't be sure that the
function loaded the GP, so this could fail in modules. */
-#define BUG() \
- __asm__ __volatile__("call_pal %0 # bugchk\n\t"".long %1\n\t.8byte %2" \
- : : "i" (PAL_bugchk), "i"(__LINE__), "i"(__FILE__))
+static inline void ATTRIB_NORET __BUG(const char *file, int line)
+{
+ __asm__ __volatile__(
+ "call_pal %0 # bugchk\n\t"
+ ".long %1\n\t.8byte %2"
+ : : "i" (PAL_bugchk), "i"(line), "i"(file));
+ for ( ; ; )
+ ;
+}
+
+#define BUG() __BUG(__FILE__, __LINE__)
#define HAVE_ARCH_BUG
#endif
diff --git a/include/asm-alpha/byteorder.h b/include/asm-alpha/byteorder.h
index 7af2b8d25486..58e958fc7f1b 100644
--- a/include/asm-alpha/byteorder.h
+++ b/include/asm-alpha/byteorder.h
@@ -7,7 +7,7 @@
#ifdef __GNUC__
-static __inline __attribute_const__ __u32 __arch__swab32(__u32 x)
+static inline __attribute_const__ __u32 __arch__swab32(__u32 x)
{
/*
* Unfortunately, we can't use the 6 instruction sequence
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 99037b032357..05ce5fba43e3 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -268,6 +268,7 @@ extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_FOW); }
extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+extern inline int pte_special(pte_t pte) { return 0; }
extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_FOW; return pte; }
extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
@@ -275,6 +276,7 @@ extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~(__ACCESS_BITS); ret
extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_FOW; return pte; }
extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= __DIRTY_BITS; return pte; }
extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= __ACCESS_BITS; return pte; }
+extern inline pte_t pte_mkspecial(pte_t pte) { return pte; }
#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
diff --git a/include/asm-arm/arch-pxa/pxa3xx_nand.h b/include/asm-arm/arch-pxa/pxa3xx_nand.h
new file mode 100644
index 000000000000..81a8937486cb
--- /dev/null
+++ b/include/asm-arm/arch-pxa/pxa3xx_nand.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_ARCH_PXA3XX_NAND_H
+#define __ASM_ARCH_PXA3XX_NAND_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+struct pxa3xx_nand_platform_data {
+
+ /* the data flash bus is shared between the Static Memory
+ * Controller and the Data Flash Controller, the arbiter
+ * controls the ownership of the bus
+ */
+ int enable_arbiter;
+
+ struct mtd_partition *parts;
+ unsigned int nr_parts;
+};
+#endif /* __ASM_ARCH_PXA3XX_NAND_H */
diff --git a/include/asm-arm/arch-sa1100/ide.h b/include/asm-arm/arch-sa1100/ide.h
index 98b10bcf9f1b..b14cbda01dc3 100644
--- a/include/asm-arm/arch-sa1100/ide.h
+++ b/include/asm-arm/arch-sa1100/ide.h
@@ -37,12 +37,12 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
memset(hw, 0, sizeof(*hw));
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hw->io_ports[i] = reg;
+ for (i = 0; i <= 7; i++) {
+ hw->io_ports_array[i] = reg;
reg += regincr;
}
- hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ hw->io_ports.ctl_addr = ctrl_port;
if (irq)
*irq = 0;
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 5e0182485d8c..5571c13c3f3b 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -260,6 +260,7 @@ extern struct page *empty_zero_page;
#define pte_write(pte) (pte_val(pte) & L_PTE_WRITE)
#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY)
#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG)
+#define pte_special(pte) (0)
/*
* The following only works if pte_present() is not true.
@@ -280,6 +281,8 @@ PTE_BIT_FUNC(mkdirty, |= L_PTE_DIRTY);
PTE_BIT_FUNC(mkold, &= ~L_PTE_YOUNG);
PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG);
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
+
/*
* Mark the prot value as uncacheable and unbufferable.
*/
diff --git a/include/asm-arm/plat-s3c/nand.h b/include/asm-arm/plat-s3c/nand.h
index 8816f7f9cee1..ad6bbe90616e 100644
--- a/include/asm-arm/plat-s3c/nand.h
+++ b/include/asm-arm/plat-s3c/nand.h
@@ -22,11 +22,14 @@
*/
struct s3c2410_nand_set {
+ unsigned int disable_ecc : 1;
+
int nr_chips;
int nr_partitions;
char *name;
int *nr_map;
struct mtd_partition *partitions;
+ struct nand_ecclayout *ecc_layout;
};
struct s3c2410_platform_nand {
@@ -36,6 +39,8 @@ struct s3c2410_platform_nand {
int twrph0; /* active time for nWE/nOE */
int twrph1; /* time for release CLE/ALE from nWE/nOE inactive */
+ unsigned int ignore_unset_ecc : 1;
+
int nr_sets;
struct s3c2410_nand_set *sets;
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index 3ae7b548fce7..c0e5e29417df 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -212,6 +212,10 @@ static inline int pte_young(pte_t pte)
{
return pte_val(pte) & _PAGE_ACCESSED;
}
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
/*
* The following only work if pte_present() is not true.
@@ -252,6 +256,10 @@ static inline pte_t pte_mkyoung(pte_t pte)
set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED));
return pte;
}
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return pte;
+}
#define pmd_none(x) (!pmd_val(x))
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
diff --git a/include/asm-cris/arch-v10/ide.h b/include/asm-cris/arch-v10/ide.h
index ea34e0d0a388..5366e6239328 100644
--- a/include/asm-cris/arch-v10/ide.h
+++ b/include/asm-cris/arch-v10/ide.h
@@ -59,22 +59,19 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, u
int i;
/* fill in ports for ATA addresses 0 to 7 */
-
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hw->io_ports[i] = data_port |
+ for (i = 0; i <= 7; i++) {
+ hw->io_ports_array[i] = data_port |
IO_FIELD(R_ATA_CTRL_DATA, addr, i) |
IO_STATE(R_ATA_CTRL_DATA, cs0, active);
}
/* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */
-
- hw->io_ports[IDE_CONTROL_OFFSET] = data_port |
+ hw->io_ports.ctl_addr = data_port |
IO_FIELD(R_ATA_CTRL_DATA, addr, 6) |
IO_STATE(R_ATA_CTRL_DATA, cs1, active);
/* whats this for ? */
-
- hw->io_ports[IDE_IRQ_OFFSET] = 0;
+ hw->io_ports.irq_addr = 0;
}
static inline void ide_init_default_hwifs(void)
diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
index a2607575681b..829e7a7d9fb9 100644
--- a/include/asm-cris/pgtable.h
+++ b/include/asm-cris/pgtable.h
@@ -115,6 +115,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WR
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
static inline pte_t pte_wrprotect(pte_t pte)
{
@@ -162,6 +163,7 @@ static inline pte_t pte_mkyoung(pte_t pte)
}
return pte;
}
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/*
* Conversion functions: convert a page and protection to a page entry,
@@ -229,7 +231,7 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
/* to find an entry in a page-table-directory */
-static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+static inline pgd_t * pgd_offset(const struct mm_struct *mm, unsigned long address)
{
return mm->pgd + pgd_index(address);
}
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 4e219046fe42..83c51aba534b 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -380,6 +380,7 @@ static inline pmd_t *pmd_offset(pud_t *dir, unsigned long address)
static inline int pte_dirty(pte_t pte) { return (pte).pte & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return (pte).pte & _PAGE_ACCESSED; }
static inline int pte_write(pte_t pte) { return !((pte).pte & _PAGE_WP); }
+static inline int pte_special(pte_t pte) { return 0; }
static inline pte_t pte_mkclean(pte_t pte) { (pte).pte &= ~_PAGE_DIRTY; return pte; }
static inline pte_t pte_mkold(pte_t pte) { (pte).pte &= ~_PAGE_ACCESSED; return pte; }
@@ -387,6 +388,7 @@ static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte |= _PAGE_WP; return pte
static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte &= ~_PAGE_WP; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
{
diff --git a/include/asm-generic/bitops/__fls.h b/include/asm-generic/bitops/__fls.h
new file mode 100644
index 000000000000..be24465403d6
--- /dev/null
+++ b/include/asm-generic/bitops/__fls.h
@@ -0,0 +1,43 @@
+#ifndef _ASM_GENERIC_BITOPS___FLS_H_
+#define _ASM_GENERIC_BITOPS___FLS_H_
+
+#include <asm/types.h>
+
+/**
+ * __fls - find last (most-significant) set bit in a long word
+ * @word: the word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __fls(unsigned long word)
+{
+ int num = BITS_PER_LONG - 1;
+
+#if BITS_PER_LONG == 64
+ if (!(word & (~0ul << 32))) {
+ num -= 32;
+ word <<= 32;
+ }
+#endif
+ if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
+ num -= 16;
+ word <<= 16;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
+ num -= 8;
+ word <<= 8;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
+ num -= 4;
+ word <<= 4;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
+ num -= 2;
+ word <<= 2;
+ }
+ if (!(word & (~0ul << (BITS_PER_LONG-1))))
+ num -= 1;
+ return num;
+}
+
+#endif /* _ASM_GENERIC_BITOPS___FLS_H_ */
diff --git a/include/asm-generic/bitops/find.h b/include/asm-generic/bitops/find.h
index 72a51e5a12ef..1914e9742512 100644
--- a/include/asm-generic/bitops/find.h
+++ b/include/asm-generic/bitops/find.h
@@ -1,11 +1,13 @@
#ifndef _ASM_GENERIC_BITOPS_FIND_H_
#define _ASM_GENERIC_BITOPS_FIND_H_
+#ifndef CONFIG_GENERIC_FIND_NEXT_BIT
extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
size, unsigned long offset);
extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
long size, unsigned long offset);
+#endif
#define find_first_bit(addr, size) find_next_bit((addr), (size), 0)
#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
diff --git a/include/asm-generic/bitops/fls64.h b/include/asm-generic/bitops/fls64.h
index 1b6b17ce2428..86d403f8b256 100644
--- a/include/asm-generic/bitops/fls64.h
+++ b/include/asm-generic/bitops/fls64.h
@@ -3,6 +3,18 @@
#include <asm/types.h>
+/**
+ * fls64 - find last set bit in a 64-bit word
+ * @x: the word to search
+ *
+ * This is defined in a similar way as the libc and compiler builtin
+ * ffsll, but returns the position of the most significant set bit.
+ *
+ * fls64(value) returns 0 if value is 0 or the position of the last
+ * set bit if value is nonzero. The last (most significant) bit is
+ * at position 64.
+ */
+#if BITS_PER_LONG == 32
static inline int fls64(__u64 x)
{
__u32 h = x >> 32;
@@ -10,5 +22,15 @@ static inline int fls64(__u64 x)
return fls(h) + 32;
return fls(x);
}
+#elif BITS_PER_LONG == 64
+static inline int fls64(__u64 x)
+{
+ if (x == 0)
+ return 0;
+ return __fls(x) + 1;
+}
+#else
+#error BITS_PER_LONG not 32 or 64
+#endif
#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index f29a502f4a6c..ecf675a59d21 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -16,7 +16,14 @@
#define ARCH_NR_GPIOS 256
#endif
+static inline int gpio_is_valid(int number)
+{
+ /* only some non-negative numbers are valid */
+ return ((unsigned)number) < ARCH_NR_GPIOS;
+}
+
struct seq_file;
+struct module;
/**
* struct gpio_chip - abstract a GPIO controller
@@ -48,6 +55,7 @@ struct seq_file;
*/
struct gpio_chip {
char *label;
+ struct module *owner;
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
@@ -66,6 +74,7 @@ struct gpio_chip {
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
unsigned offset);
+extern int __init __must_check gpiochip_reserve(int start, int ngpio);
/* add/remove chips */
extern int gpiochip_add(struct gpio_chip *chip);
@@ -97,6 +106,12 @@ extern int __gpio_cansleep(unsigned gpio);
#else
+static inline int gpio_is_valid(int number)
+{
+ /* only non-negative numbers are valid */
+ return number >= 0;
+}
+
/* platforms that don't directly support access to GPIOs through I2C, SPI,
* or other blocking infrastructure can use these wrappers.
*/
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
index 67dc84cd1343..76b0cc5637f8 100644
--- a/include/asm-generic/iomap.h
+++ b/include/asm-generic/iomap.h
@@ -60,6 +60,10 @@ extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long cou
extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
extern void ioport_unmap(void __iomem *);
+#ifndef ARCH_HAS_IOREMAP_WC
+#define ioremap_wc ioremap_nocache
+#endif
+
/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
struct pci_dev;
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
index 953d3df9dd22..e2ca80037335 100644
--- a/include/asm-ia64/bitops.h
+++ b/include/asm-ia64/bitops.h
@@ -407,6 +407,22 @@ fls (int t)
return ia64_popcnt(x);
}
+/*
+ * Find the last (most significant) bit set. Undefined for x==0.
+ * Bits are numbered from 0..63 (e.g., __fls(9) == 3).
+ */
+static inline unsigned long
+__fls (unsigned long x)
+{
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x |= x >> 32;
+ return ia64_popcnt(x) - 1;
+}
+
#include <asm-generic/bitops/fls64.h>
/*
diff --git a/include/asm-ia64/gcc_intrin.h b/include/asm-ia64/gcc_intrin.h
index de2ed2cbdd84..2fe292c275fe 100644
--- a/include/asm-ia64/gcc_intrin.h
+++ b/include/asm-ia64/gcc_intrin.h
@@ -21,6 +21,10 @@
#define ia64_invala_fr(regnum) asm volatile ("invala.e f%0" :: "i"(regnum))
+#define ia64_flushrs() asm volatile ("flushrs;;":::"memory")
+
+#define ia64_loadrs() asm volatile ("loadrs;;":::"memory")
+
extern void ia64_bad_param_for_setreg (void);
extern void ia64_bad_param_for_getreg (void);
@@ -517,6 +521,14 @@ do { \
#define ia64_ptrd(addr, size) \
asm volatile ("ptr.d %0,%1" :: "r"(addr), "r"(size) : "memory")
+#define ia64_ttag(addr) \
+({ \
+ __u64 ia64_intri_res; \
+ asm volatile ("ttag %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \
+ ia64_intri_res; \
+})
+
+
/* Values for lfhint in ia64_lfetch and ia64_lfetch_fault */
#define ia64_lfhint_none 0
diff --git a/include/asm-ia64/hugetlb.h b/include/asm-ia64/hugetlb.h
new file mode 100644
index 000000000000..f28a9701f1cf
--- /dev/null
+++ b/include/asm-ia64/hugetlb.h
@@ -0,0 +1,79 @@
+#ifndef _ASM_IA64_HUGETLB_H
+#define _ASM_IA64_HUGETLB_H
+
+#include <asm/page.h>
+
+
+void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
+ unsigned long end, unsigned long floor,
+ unsigned long ceiling);
+
+int prepare_hugepage_range(unsigned long addr, unsigned long len);
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr,
+ unsigned long len)
+{
+ return (REGION_NUMBER(addr) == RGN_HPAGE ||
+ REGION_NUMBER((addr)+(len)-1) == RGN_HPAGE);
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
+{
+}
+
+static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ set_pte_at(mm, addr, ptep, pte);
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+ return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+#endif /* _ASM_IA64_HUGETLB_H */
diff --git a/include/asm-ia64/kvm.h b/include/asm-ia64/kvm.h
index 030d29b4b26b..eb2d3559d089 100644
--- a/include/asm-ia64/kvm.h
+++ b/include/asm-ia64/kvm.h
@@ -1,6 +1,205 @@
-#ifndef __LINUX_KVM_IA64_H
-#define __LINUX_KVM_IA64_H
+#ifndef __ASM_IA64_KVM_H
+#define __ASM_IA64_KVM_H
-/* ia64 does not support KVM */
+/*
+ * asm-ia64/kvm.h: kvm structure definitions for ia64
+ *
+ * Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <asm/types.h>
+#include <asm/fpu.h>
+
+#include <linux/ioctl.h>
+
+/* Architectural interrupt line count. */
+#define KVM_NR_INTERRUPTS 256
+
+#define KVM_IOAPIC_NUM_PINS 24
+
+struct kvm_ioapic_state {
+ __u64 base_address;
+ __u32 ioregsel;
+ __u32 id;
+ __u32 irr;
+ __u32 pad;
+ union {
+ __u64 bits;
+ struct {
+ __u8 vector;
+ __u8 delivery_mode:3;
+ __u8 dest_mode:1;
+ __u8 delivery_status:1;
+ __u8 polarity:1;
+ __u8 remote_irr:1;
+ __u8 trig_mode:1;
+ __u8 mask:1;
+ __u8 reserve:7;
+ __u8 reserved[4];
+ __u8 dest_id;
+ } fields;
+ } redirtbl[KVM_IOAPIC_NUM_PINS];
+};
+
+#define KVM_IRQCHIP_PIC_MASTER 0
+#define KVM_IRQCHIP_PIC_SLAVE 1
+#define KVM_IRQCHIP_IOAPIC 2
+
+#define KVM_CONTEXT_SIZE 8*1024
+
+union context {
+ /* 8K size */
+ char dummy[KVM_CONTEXT_SIZE];
+ struct {
+ unsigned long psr;
+ unsigned long pr;
+ unsigned long caller_unat;
+ unsigned long pad;
+ unsigned long gr[32];
+ unsigned long ar[128];
+ unsigned long br[8];
+ unsigned long cr[128];
+ unsigned long rr[8];
+ unsigned long ibr[8];
+ unsigned long dbr[8];
+ unsigned long pkr[8];
+ struct ia64_fpreg fr[128];
+ };
+};
+
+struct thash_data {
+ union {
+ struct {
+ unsigned long p : 1; /* 0 */
+ unsigned long rv1 : 1; /* 1 */
+ unsigned long ma : 3; /* 2-4 */
+ unsigned long a : 1; /* 5 */
+ unsigned long d : 1; /* 6 */
+ unsigned long pl : 2; /* 7-8 */
+ unsigned long ar : 3; /* 9-11 */
+ unsigned long ppn : 38; /* 12-49 */
+ unsigned long rv2 : 2; /* 50-51 */
+ unsigned long ed : 1; /* 52 */
+ unsigned long ig1 : 11; /* 53-63 */
+ };
+ struct {
+ unsigned long __rv1 : 53; /* 0-52 */
+ unsigned long contiguous : 1; /*53 */
+ unsigned long tc : 1; /* 54 TR or TC */
+ unsigned long cl : 1;
+ /* 55 I side or D side cache line */
+ unsigned long len : 4; /* 56-59 */
+ unsigned long io : 1; /* 60 entry is for io or not */
+ unsigned long nomap : 1;
+ /* 61 entry cann't be inserted into machine TLB.*/
+ unsigned long checked : 1;
+ /* 62 for VTLB/VHPT sanity check */
+ unsigned long invalid : 1;
+ /* 63 invalid entry */
+ };
+ unsigned long page_flags;
+ }; /* same for VHPT and TLB */
+
+ union {
+ struct {
+ unsigned long rv3 : 2;
+ unsigned long ps : 6;
+ unsigned long key : 24;
+ unsigned long rv4 : 32;
+ };
+ unsigned long itir;
+ };
+ union {
+ struct {
+ unsigned long ig2 : 12;
+ unsigned long vpn : 49;
+ unsigned long vrn : 3;
+ };
+ unsigned long ifa;
+ unsigned long vadr;
+ struct {
+ unsigned long tag : 63;
+ unsigned long ti : 1;
+ };
+ unsigned long etag;
+ };
+ union {
+ struct thash_data *next;
+ unsigned long rid;
+ unsigned long gpaddr;
+ };
+};
+
+#define NITRS 8
+#define NDTRS 8
+
+struct saved_vpd {
+ unsigned long vhpi;
+ unsigned long vgr[16];
+ unsigned long vbgr[16];
+ unsigned long vnat;
+ unsigned long vbnat;
+ unsigned long vcpuid[5];
+ unsigned long vpsr;
+ unsigned long vpr;
+ unsigned long vcr[128];
+};
+
+struct kvm_regs {
+ char *saved_guest;
+ char *saved_stack;
+ struct saved_vpd vpd;
+ /*Arch-regs*/
+ int mp_state;
+ unsigned long vmm_rr;
+ /* TR and TC. */
+ struct thash_data itrs[NITRS];
+ struct thash_data dtrs[NDTRS];
+ /* Bit is set if there is a tr/tc for the region. */
+ unsigned char itr_regions;
+ unsigned char dtr_regions;
+ unsigned char tc_regions;
+
+ char irq_check;
+ unsigned long saved_itc;
+ unsigned long itc_check;
+ unsigned long timer_check;
+ unsigned long timer_pending;
+ unsigned long last_itc;
+
+ unsigned long vrr[8];
+ unsigned long ibr[8];
+ unsigned long dbr[8];
+ unsigned long insvc[4]; /* Interrupt in service. */
+ unsigned long xtp;
+
+ unsigned long metaphysical_rr0; /* from kvm_arch (so is pinned) */
+ unsigned long metaphysical_rr4; /* from kvm_arch (so is pinned) */
+ unsigned long metaphysical_saved_rr0; /* from kvm_arch */
+ unsigned long metaphysical_saved_rr4; /* from kvm_arch */
+ unsigned long fp_psr; /*used for lazy float register */
+ unsigned long saved_gp;
+ /*for phycial emulation */
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
#endif
diff --git a/include/asm-ia64/kvm_host.h b/include/asm-ia64/kvm_host.h
new file mode 100644
index 000000000000..c082c208c1f3
--- /dev/null
+++ b/include/asm-ia64/kvm_host.h
@@ -0,0 +1,524 @@
+/*
+ * kvm_host.h: used for kvm module, and hold ia64-specific sections.
+ *
+ * Copyright (C) 2007, Intel Corporation.
+ *
+ * Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 __ASM_KVM_HOST_H
+#define __ASM_KVM_HOST_H
+
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+#include <linux/kvm_types.h>
+
+#include <asm/pal.h>
+#include <asm/sal.h>
+
+#define KVM_MAX_VCPUS 4
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+
+/* define exit reasons from vmm to kvm*/
+#define EXIT_REASON_VM_PANIC 0
+#define EXIT_REASON_MMIO_INSTRUCTION 1
+#define EXIT_REASON_PAL_CALL 2
+#define EXIT_REASON_SAL_CALL 3
+#define EXIT_REASON_SWITCH_RR6 4
+#define EXIT_REASON_VM_DESTROY 5
+#define EXIT_REASON_EXTERNAL_INTERRUPT 6
+#define EXIT_REASON_IPI 7
+#define EXIT_REASON_PTC_G 8
+
+/*Define vmm address space and vm data space.*/
+#define KVM_VMM_SIZE (16UL<<20)
+#define KVM_VMM_SHIFT 24
+#define KVM_VMM_BASE 0xD000000000000000UL
+#define VMM_SIZE (8UL<<20)
+
+/*
+ * Define vm_buffer, used by PAL Services, base address.
+ * Note: vmbuffer is in the VMM-BLOCK, the size must be < 8M
+ */
+#define KVM_VM_BUFFER_BASE (KVM_VMM_BASE + VMM_SIZE)
+#define KVM_VM_BUFFER_SIZE (8UL<<20)
+
+/*Define Virtual machine data layout.*/
+#define KVM_VM_DATA_SHIFT 24
+#define KVM_VM_DATA_SIZE (1UL << KVM_VM_DATA_SHIFT)
+#define KVM_VM_DATA_BASE (KVM_VMM_BASE + KVM_VMM_SIZE)
+
+
+#define KVM_P2M_BASE KVM_VM_DATA_BASE
+#define KVM_P2M_OFS 0
+#define KVM_P2M_SIZE (8UL << 20)
+
+#define KVM_VHPT_BASE (KVM_P2M_BASE + KVM_P2M_SIZE)
+#define KVM_VHPT_OFS KVM_P2M_SIZE
+#define KVM_VHPT_BLOCK_SIZE (2UL << 20)
+#define VHPT_SHIFT 18
+#define VHPT_SIZE (1UL << VHPT_SHIFT)
+#define VHPT_NUM_ENTRIES (1<<(VHPT_SHIFT-5))
+
+#define KVM_VTLB_BASE (KVM_VHPT_BASE+KVM_VHPT_BLOCK_SIZE)
+#define KVM_VTLB_OFS (KVM_VHPT_OFS+KVM_VHPT_BLOCK_SIZE)
+#define KVM_VTLB_BLOCK_SIZE (1UL<<20)
+#define VTLB_SHIFT 17
+#define VTLB_SIZE (1UL<<VTLB_SHIFT)
+#define VTLB_NUM_ENTRIES (1<<(VTLB_SHIFT-5))
+
+#define KVM_VPD_BASE (KVM_VTLB_BASE+KVM_VTLB_BLOCK_SIZE)
+#define KVM_VPD_OFS (KVM_VTLB_OFS+KVM_VTLB_BLOCK_SIZE)
+#define KVM_VPD_BLOCK_SIZE (2UL<<20)
+#define VPD_SHIFT 16
+#define VPD_SIZE (1UL<<VPD_SHIFT)
+
+#define KVM_VCPU_BASE (KVM_VPD_BASE+KVM_VPD_BLOCK_SIZE)
+#define KVM_VCPU_OFS (KVM_VPD_OFS+KVM_VPD_BLOCK_SIZE)
+#define KVM_VCPU_BLOCK_SIZE (2UL<<20)
+#define VCPU_SHIFT 18
+#define VCPU_SIZE (1UL<<VCPU_SHIFT)
+#define MAX_VCPU_NUM KVM_VCPU_BLOCK_SIZE/VCPU_SIZE
+
+#define KVM_VM_BASE (KVM_VCPU_BASE+KVM_VCPU_BLOCK_SIZE)
+#define KVM_VM_OFS (KVM_VCPU_OFS+KVM_VCPU_BLOCK_SIZE)
+#define KVM_VM_BLOCK_SIZE (1UL<<19)
+
+#define KVM_MEM_DIRTY_LOG_BASE (KVM_VM_BASE+KVM_VM_BLOCK_SIZE)
+#define KVM_MEM_DIRTY_LOG_OFS (KVM_VM_OFS+KVM_VM_BLOCK_SIZE)
+#define KVM_MEM_DIRTY_LOG_SIZE (1UL<<19)
+
+/* Get vpd, vhpt, tlb, vcpu, base*/
+#define VPD_ADDR(n) (KVM_VPD_BASE+n*VPD_SIZE)
+#define VHPT_ADDR(n) (KVM_VHPT_BASE+n*VHPT_SIZE)
+#define VTLB_ADDR(n) (KVM_VTLB_BASE+n*VTLB_SIZE)
+#define VCPU_ADDR(n) (KVM_VCPU_BASE+n*VCPU_SIZE)
+
+/*IO section definitions*/
+#define IOREQ_READ 1
+#define IOREQ_WRITE 0
+
+#define STATE_IOREQ_NONE 0
+#define STATE_IOREQ_READY 1
+#define STATE_IOREQ_INPROCESS 2
+#define STATE_IORESP_READY 3
+
+/*Guest Physical address layout.*/
+#define GPFN_MEM (0UL << 60) /* Guest pfn is normal mem */
+#define GPFN_FRAME_BUFFER (1UL << 60) /* VGA framebuffer */
+#define GPFN_LOW_MMIO (2UL << 60) /* Low MMIO range */
+#define GPFN_PIB (3UL << 60) /* PIB base */
+#define GPFN_IOSAPIC (4UL << 60) /* IOSAPIC base */
+#define GPFN_LEGACY_IO (5UL << 60) /* Legacy I/O base */
+#define GPFN_GFW (6UL << 60) /* Guest Firmware */
+#define GPFN_HIGH_MMIO (7UL << 60) /* High MMIO range */
+
+#define GPFN_IO_MASK (7UL << 60) /* Guest pfn is I/O type */
+#define GPFN_INV_MASK (1UL << 63) /* Guest pfn is invalid */
+#define INVALID_MFN (~0UL)
+#define MEM_G (1UL << 30)
+#define MEM_M (1UL << 20)
+#define MMIO_START (3 * MEM_G)
+#define MMIO_SIZE (512 * MEM_M)
+#define VGA_IO_START 0xA0000UL
+#define VGA_IO_SIZE 0x20000
+#define LEGACY_IO_START (MMIO_START + MMIO_SIZE)
+#define LEGACY_IO_SIZE (64 * MEM_M)
+#define IO_SAPIC_START 0xfec00000UL
+#define IO_SAPIC_SIZE 0x100000
+#define PIB_START 0xfee00000UL
+#define PIB_SIZE 0x200000
+#define GFW_START (4 * MEM_G - 16 * MEM_M)
+#define GFW_SIZE (16 * MEM_M)
+
+/*Deliver mode, defined for ioapic.c*/
+#define dest_Fixed IOSAPIC_FIXED
+#define dest_LowestPrio IOSAPIC_LOWEST_PRIORITY
+
+#define NMI_VECTOR 2
+#define ExtINT_VECTOR 0
+#define NULL_VECTOR (-1)
+#define IA64_SPURIOUS_INT_VECTOR 0x0f
+
+#define VCPU_LID(v) (((u64)(v)->vcpu_id) << 24)
+
+/*
+ *Delivery mode
+ */
+#define SAPIC_DELIV_SHIFT 8
+#define SAPIC_FIXED 0x0
+#define SAPIC_LOWEST_PRIORITY 0x1
+#define SAPIC_PMI 0x2
+#define SAPIC_NMI 0x4
+#define SAPIC_INIT 0x5
+#define SAPIC_EXTINT 0x7
+
+/*
+ * vcpu->requests bit members for arch
+ */
+#define KVM_REQ_PTC_G 32
+#define KVM_REQ_RESUME 33
+
+#define KVM_PAGES_PER_HPAGE 1
+
+struct kvm;
+struct kvm_vcpu;
+struct kvm_guest_debug{
+};
+
+struct kvm_mmio_req {
+ uint64_t addr; /* physical address */
+ uint64_t size; /* size in bytes */
+ uint64_t data; /* data (or paddr of data) */
+ uint8_t state:4;
+ uint8_t dir:1; /* 1=read, 0=write */
+};
+
+/*Pal data struct */
+struct kvm_pal_call{
+ /*In area*/
+ uint64_t gr28;
+ uint64_t gr29;
+ uint64_t gr30;
+ uint64_t gr31;
+ /*Out area*/
+ struct ia64_pal_retval ret;
+};
+
+/* Sal data structure */
+struct kvm_sal_call{
+ /*In area*/
+ uint64_t in0;
+ uint64_t in1;
+ uint64_t in2;
+ uint64_t in3;
+ uint64_t in4;
+ uint64_t in5;
+ uint64_t in6;
+ uint64_t in7;
+ struct sal_ret_values ret;
+};
+
+/*Guest change rr6*/
+struct kvm_switch_rr6 {
+ uint64_t old_rr;
+ uint64_t new_rr;
+};
+
+union ia64_ipi_a{
+ unsigned long val;
+ struct {
+ unsigned long rv : 3;
+ unsigned long ir : 1;
+ unsigned long eid : 8;
+ unsigned long id : 8;
+ unsigned long ib_base : 44;
+ };
+};
+
+union ia64_ipi_d {
+ unsigned long val;
+ struct {
+ unsigned long vector : 8;
+ unsigned long dm : 3;
+ unsigned long ig : 53;
+ };
+};
+
+/*ipi check exit data*/
+struct kvm_ipi_data{
+ union ia64_ipi_a addr;
+ union ia64_ipi_d data;
+};
+
+/*global purge data*/
+struct kvm_ptc_g {
+ unsigned long vaddr;
+ unsigned long rr;
+ unsigned long ps;
+ struct kvm_vcpu *vcpu;
+};
+
+/*Exit control data */
+struct exit_ctl_data{
+ uint32_t exit_reason;
+ uint32_t vm_status;
+ union {
+ struct kvm_mmio_req ioreq;
+ struct kvm_pal_call pal_data;
+ struct kvm_sal_call sal_data;
+ struct kvm_switch_rr6 rr_data;
+ struct kvm_ipi_data ipi_data;
+ struct kvm_ptc_g ptc_g_data;
+ } u;
+};
+
+union pte_flags {
+ unsigned long val;
+ struct {
+ unsigned long p : 1; /*0 */
+ unsigned long : 1; /* 1 */
+ unsigned long ma : 3; /* 2-4 */
+ unsigned long a : 1; /* 5 */
+ unsigned long d : 1; /* 6 */
+ unsigned long pl : 2; /* 7-8 */
+ unsigned long ar : 3; /* 9-11 */
+ unsigned long ppn : 38; /* 12-49 */
+ unsigned long : 2; /* 50-51 */
+ unsigned long ed : 1; /* 52 */
+ };
+};
+
+union ia64_pta {
+ unsigned long val;
+ struct {
+ unsigned long ve : 1;
+ unsigned long reserved0 : 1;
+ unsigned long size : 6;
+ unsigned long vf : 1;
+ unsigned long reserved1 : 6;
+ unsigned long base : 49;
+ };
+};
+
+struct thash_cb {
+ /* THASH base information */
+ struct thash_data *hash; /* hash table pointer */
+ union ia64_pta pta;
+ int num;
+};
+
+struct kvm_vcpu_stat {
+};
+
+struct kvm_vcpu_arch {
+ int launched;
+ int last_exit;
+ int last_run_cpu;
+ int vmm_tr_slot;
+ int vm_tr_slot;
+
+#define KVM_MP_STATE_RUNNABLE 0
+#define KVM_MP_STATE_UNINITIALIZED 1
+#define KVM_MP_STATE_INIT_RECEIVED 2
+#define KVM_MP_STATE_HALTED 3
+ int mp_state;
+
+#define MAX_PTC_G_NUM 3
+ int ptc_g_count;
+ struct kvm_ptc_g ptc_g_data[MAX_PTC_G_NUM];
+
+ /*halt timer to wake up sleepy vcpus*/
+ struct hrtimer hlt_timer;
+ long ht_active;
+
+ struct kvm_lapic *apic; /* kernel irqchip context */
+ struct vpd *vpd;
+
+ /* Exit data for vmm_transition*/
+ struct exit_ctl_data exit_data;
+
+ cpumask_t cache_coherent_map;
+
+ unsigned long vmm_rr;
+ unsigned long host_rr6;
+ unsigned long psbits[8];
+ unsigned long cr_iipa;
+ unsigned long cr_isr;
+ unsigned long vsa_base;
+ unsigned long dirty_log_lock_pa;
+ unsigned long __gp;
+ /* TR and TC. */
+ struct thash_data itrs[NITRS];
+ struct thash_data dtrs[NDTRS];
+ /* Bit is set if there is a tr/tc for the region. */
+ unsigned char itr_regions;
+ unsigned char dtr_regions;
+ unsigned char tc_regions;
+ /* purge all */
+ unsigned long ptce_base;
+ unsigned long ptce_count[2];
+ unsigned long ptce_stride[2];
+ /* itc/itm */
+ unsigned long last_itc;
+ long itc_offset;
+ unsigned long itc_check;
+ unsigned long timer_check;
+ unsigned long timer_pending;
+
+ unsigned long vrr[8];
+ unsigned long ibr[8];
+ unsigned long dbr[8];
+ unsigned long insvc[4]; /* Interrupt in service. */
+ unsigned long xtp;
+
+ unsigned long metaphysical_rr0; /* from kvm_arch (so is pinned) */
+ unsigned long metaphysical_rr4; /* from kvm_arch (so is pinned) */
+ unsigned long metaphysical_saved_rr0; /* from kvm_arch */
+ unsigned long metaphysical_saved_rr4; /* from kvm_arch */
+ unsigned long fp_psr; /*used for lazy float register */
+ unsigned long saved_gp;
+ /*for phycial emulation */
+ int mode_flags;
+ struct thash_cb vtlb;
+ struct thash_cb vhpt;
+ char irq_check;
+ char irq_new_pending;
+
+ unsigned long opcode;
+ unsigned long cause;
+ union context host;
+ union context guest;
+};
+
+struct kvm_vm_stat {
+ u64 remote_tlb_flush;
+};
+
+struct kvm_sal_data {
+ unsigned long boot_ip;
+ unsigned long boot_gp;
+};
+
+struct kvm_arch {
+ unsigned long vm_base;
+ unsigned long metaphysical_rr0;
+ unsigned long metaphysical_rr4;
+ unsigned long vmm_init_rr;
+ unsigned long vhpt_base;
+ unsigned long vtlb_base;
+ unsigned long vpd_base;
+ spinlock_t dirty_log_lock;
+ struct kvm_ioapic *vioapic;
+ struct kvm_vm_stat stat;
+ struct kvm_sal_data rdv_sal_data;
+};
+
+union cpuid3_t {
+ u64 value;
+ struct {
+ u64 number : 8;
+ u64 revision : 8;
+ u64 model : 8;
+ u64 family : 8;
+ u64 archrev : 8;
+ u64 rv : 24;
+ };
+};
+
+struct kvm_pt_regs {
+ /* The following registers are saved by SAVE_MIN: */
+ unsigned long b6; /* scratch */
+ unsigned long b7; /* scratch */
+
+ unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */
+ unsigned long ar_ssd; /* reserved for future use (scratch) */
+
+ unsigned long r8; /* scratch (return value register 0) */
+ unsigned long r9; /* scratch (return value register 1) */
+ unsigned long r10; /* scratch (return value register 2) */
+ unsigned long r11; /* scratch (return value register 3) */
+
+ unsigned long cr_ipsr; /* interrupted task's psr */
+ unsigned long cr_iip; /* interrupted task's instruction pointer */
+ unsigned long cr_ifs; /* interrupted task's function state */
+
+ unsigned long ar_unat; /* interrupted task's NaT register (preserved) */
+ unsigned long ar_pfs; /* prev function state */
+ unsigned long ar_rsc; /* RSE configuration */
+ /* The following two are valid only if cr_ipsr.cpl > 0: */
+ unsigned long ar_rnat; /* RSE NaT */
+ unsigned long ar_bspstore; /* RSE bspstore */
+
+ unsigned long pr; /* 64 predicate registers (1 bit each) */
+ unsigned long b0; /* return pointer (bp) */
+ unsigned long loadrs; /* size of dirty partition << 16 */
+
+ unsigned long r1; /* the gp pointer */
+ unsigned long r12; /* interrupted task's memory stack pointer */
+ unsigned long r13; /* thread pointer */
+
+ unsigned long ar_fpsr; /* floating point status (preserved) */
+ unsigned long r15; /* scratch */
+
+ /* The remaining registers are NOT saved for system calls. */
+ unsigned long r14; /* scratch */
+ unsigned long r2; /* scratch */
+ unsigned long r3; /* scratch */
+ unsigned long r16; /* scratch */
+ unsigned long r17; /* scratch */
+ unsigned long r18; /* scratch */
+ unsigned long r19; /* scratch */
+ unsigned long r20; /* scratch */
+ unsigned long r21; /* scratch */
+ unsigned long r22; /* scratch */
+ unsigned long r23; /* scratch */
+ unsigned long r24; /* scratch */
+ unsigned long r25; /* scratch */
+ unsigned long r26; /* scratch */
+ unsigned long r27; /* scratch */
+ unsigned long r28; /* scratch */
+ unsigned long r29; /* scratch */
+ unsigned long r30; /* scratch */
+ unsigned long r31; /* scratch */
+ unsigned long ar_ccv; /* compare/exchange value (scratch) */
+
+ /*
+ * Floating point registers that the kernel considers scratch:
+ */
+ struct ia64_fpreg f6; /* scratch */
+ struct ia64_fpreg f7; /* scratch */
+ struct ia64_fpreg f8; /* scratch */
+ struct ia64_fpreg f9; /* scratch */
+ struct ia64_fpreg f10; /* scratch */
+ struct ia64_fpreg f11; /* scratch */
+
+ unsigned long r4; /* preserved */
+ unsigned long r5; /* preserved */
+ unsigned long r6; /* preserved */
+ unsigned long r7; /* preserved */
+ unsigned long eml_unat; /* used for emulating instruction */
+ unsigned long pad0; /* alignment pad */
+};
+
+static inline struct kvm_pt_regs *vcpu_regs(struct kvm_vcpu *v)
+{
+ return (struct kvm_pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1;
+}
+
+typedef int kvm_vmm_entry(void);
+typedef void kvm_tramp_entry(union context *host, union context *guest);
+
+struct kvm_vmm_info{
+ struct module *module;
+ kvm_vmm_entry *vmm_entry;
+ kvm_tramp_entry *tramp_entry;
+ unsigned long vmm_ivt;
+};
+
+int kvm_highest_pending_irq(struct kvm_vcpu *vcpu);
+int kvm_emulate_halt(struct kvm_vcpu *vcpu);
+int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
+void kvm_sal_emul(struct kvm_vcpu *vcpu);
+
+#endif
diff --git a/include/asm-ia64/kvm_para.h b/include/asm-ia64/kvm_para.h
new file mode 100644
index 000000000000..9f9796bb3441
--- /dev/null
+++ b/include/asm-ia64/kvm_para.h
@@ -0,0 +1,29 @@
+#ifndef __IA64_KVM_PARA_H
+#define __IA64_KVM_PARA_H
+
+/*
+ * asm-ia64/kvm_para.h
+ *
+ * Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 4999a6c63775..36f39321b768 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -54,9 +54,6 @@
# define HPAGE_MASK (~(HPAGE_SIZE - 1))
# define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
-# define ARCH_HAS_HUGEPAGE_ONLY_RANGE
-# define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-# define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
#endif /* CONFIG_HUGETLB_PAGE */
#ifdef __ASSEMBLY__
@@ -153,9 +150,6 @@ typedef union ia64_va {
# define htlbpage_to_page(x) (((unsigned long) REGION_NUMBER(x) << 61) \
| (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT)))
# define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
-# define is_hugepage_only_range(mm, addr, len) \
- (REGION_NUMBER(addr) == RGN_HPAGE || \
- REGION_NUMBER((addr)+(len)-1) == RGN_HPAGE)
extern unsigned int hpage_shift;
#endif
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index ed70862ea247..7a9bff47564f 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -302,6 +302,8 @@ ia64_phys_addr_valid (unsigned long addr)
#define pte_dirty(pte) ((pte_val(pte) & _PAGE_D) != 0)
#define pte_young(pte) ((pte_val(pte) & _PAGE_A) != 0)
#define pte_file(pte) ((pte_val(pte) & _PAGE_FILE) != 0)
+#define pte_special(pte) 0
+
/*
* Note: we convert AR_RWX to AR_RX and AR_RW to AR_R by clearing the 2nd bit in the
* access rights:
@@ -313,6 +315,7 @@ ia64_phys_addr_valid (unsigned long addr)
#define pte_mkclean(pte) (__pte(pte_val(pte) & ~_PAGE_D))
#define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D))
#define pte_mkhuge(pte) (__pte(pte_val(pte)))
+#define pte_mkspecial(pte) (pte)
/*
* Because ia64's Icache and Dcache is not coherent (on a cpu), we need to
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 741f7ecb986a..6aff126fc07e 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -119,6 +119,69 @@ struct ia64_psr {
__u64 reserved4 : 19;
};
+union ia64_isr {
+ __u64 val;
+ struct {
+ __u64 code : 16;
+ __u64 vector : 8;
+ __u64 reserved1 : 8;
+ __u64 x : 1;
+ __u64 w : 1;
+ __u64 r : 1;
+ __u64 na : 1;
+ __u64 sp : 1;
+ __u64 rs : 1;
+ __u64 ir : 1;
+ __u64 ni : 1;
+ __u64 so : 1;
+ __u64 ei : 2;
+ __u64 ed : 1;
+ __u64 reserved2 : 20;
+ };
+};
+
+union ia64_lid {
+ __u64 val;
+ struct {
+ __u64 rv : 16;
+ __u64 eid : 8;
+ __u64 id : 8;
+ __u64 ig : 32;
+ };
+};
+
+union ia64_tpr {
+ __u64 val;
+ struct {
+ __u64 ig0 : 4;
+ __u64 mic : 4;
+ __u64 rsv : 8;
+ __u64 mmi : 1;
+ __u64 ig1 : 47;
+ };
+};
+
+union ia64_itir {
+ __u64 val;
+ struct {
+ __u64 rv3 : 2; /* 0-1 */
+ __u64 ps : 6; /* 2-7 */
+ __u64 key : 24; /* 8-31 */
+ __u64 rv4 : 32; /* 32-63 */
+ };
+};
+
+union ia64_rr {
+ __u64 val;
+ struct {
+ __u64 ve : 1; /* enable hw walker */
+ __u64 reserved0: 1; /* reserved */
+ __u64 ps : 6; /* log page size */
+ __u64 rid : 24; /* region id */
+ __u64 reserved1: 32; /* reserved */
+ };
+};
+
/*
* CPU type, hardware bug flags, and per-CPU state. Frequently used
* state comes earlier:
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
index dff8128fa58e..26e250bfb912 100644
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -146,23 +146,23 @@ do { \
# define local_irq_save(x) \
do { \
- unsigned long psr; \
+ unsigned long __psr; \
\
- __local_irq_save(psr); \
- if (psr & IA64_PSR_I) \
+ __local_irq_save(__psr); \
+ if (__psr & IA64_PSR_I) \
__save_ip(); \
- (x) = psr; \
+ (x) = __psr; \
} while (0)
-# define local_irq_disable() do { unsigned long x; local_irq_save(x); } while (0)
+# define local_irq_disable() do { unsigned long __x; local_irq_save(__x); } while (0)
# define local_irq_restore(x) \
do { \
- unsigned long old_psr, psr = (x); \
+ unsigned long __old_psr, __psr = (x); \
\
- local_save_flags(old_psr); \
- __local_irq_restore(psr); \
- if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) \
+ local_save_flags(__old_psr); \
+ __local_irq_restore(__psr); \
+ if ((__old_psr & IA64_PSR_I) && !(__psr & IA64_PSR_I)) \
__save_ip(); \
} while (0)
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 86505387be08..e6359c566b50 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -214,6 +214,11 @@ static inline int pte_file(pte_t pte)
return pte_val(pte) & _PAGE_FILE;
}
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
+
static inline pte_t pte_mkclean(pte_t pte)
{
pte_val(pte) &= ~_PAGE_DIRTY;
@@ -250,6 +255,11 @@ static inline pte_t pte_mkwrite(pte_t pte)
return pte;
}
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return pte;
+}
+
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
{
return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
diff --git a/include/asm-m68k/motorola_pgtable.h b/include/asm-m68k/motorola_pgtable.h
index 13135d4821d8..8e9a8a754dde 100644
--- a/include/asm-m68k/motorola_pgtable.h
+++ b/include/asm-m68k/motorola_pgtable.h
@@ -168,6 +168,7 @@ static inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RONLY);
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RONLY; return pte; }
static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
@@ -185,6 +186,7 @@ static inline pte_t pte_mkcache(pte_t pte)
pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode;
return pte;
}
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
diff --git a/include/asm-m68k/sun3_pgtable.h b/include/asm-m68k/sun3_pgtable.h
index b766fc261bde..f847ec732d62 100644
--- a/include/asm-m68k/sun3_pgtable.h
+++ b/include/asm-m68k/sun3_pgtable.h
@@ -169,6 +169,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & SUN3_PAGE_WRITEA
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & SUN3_PAGE_MODIFIED; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & SUN3_PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & SUN3_PAGE_ACCESSED; }
+static inline int pte_special(pte_t pte) { return 0; }
static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_WRITEABLE; return pte; }
static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_MODIFIED; return pte; }
@@ -181,6 +182,7 @@ static inline pte_t pte_mknocache(pte_t pte) { pte_val(pte) |= SUN3_PAGE_NOCACHE
//static inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) &= SUN3_PAGE_NOCACHE; return pte; }
// until then, use:
static inline pte_t pte_mkcache(pte_t pte) { return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index ec75ce4cdb8c..c2bd126c3b4e 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -591,6 +591,11 @@ static inline int __ilog2(unsigned long x)
return 63 - lz;
}
+static inline unsigned long __fls(unsigned long x)
+{
+ return __ilog2(x);
+}
+
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
/*
diff --git a/include/asm-mips/cmp.h b/include/asm-mips/cmp.h
new file mode 100644
index 000000000000..89a73fb93ae6
--- /dev/null
+++ b/include/asm-mips/cmp.h
@@ -0,0 +1,18 @@
+#ifndef _ASM_CMP_H
+#define _ASM_CMP_H
+
+/*
+ * Definitions for CMP multitasking on MIPS cores
+ */
+struct task_struct;
+
+extern void cmp_smp_setup(void);
+extern void cmp_smp_finish(void);
+extern void cmp_boot_secondary(int cpu, struct task_struct *t);
+extern void cmp_init_secondary(void);
+extern void cmp_cpus_done(void);
+extern void cmp_prepare_cpus(unsigned int max_cpus);
+
+/* This is platform specific */
+extern void cmp_send_ipi(int cpu, unsigned int action);
+#endif /* _ASM_CMP_H */
diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h
index bf5bbc78a9f7..1c35cac6f35b 100644
--- a/include/asm-mips/cpu.h
+++ b/include/asm-mips/cpu.h
@@ -29,7 +29,7 @@
#define PRID_COMP_ALCHEMY 0x030000
#define PRID_COMP_SIBYTE 0x040000
#define PRID_COMP_SANDCRAFT 0x050000
-#define PRID_COMP_PHILIPS 0x060000
+#define PRID_COMP_NXP 0x060000
#define PRID_COMP_TOSHIBA 0x070000
#define PRID_COMP_LSI 0x080000
#define PRID_COMP_LEXRA 0x0b0000
@@ -89,6 +89,7 @@
#define PRID_IMP_34K 0x9500
#define PRID_IMP_24KE 0x9600
#define PRID_IMP_74K 0x9700
+#define PRID_IMP_1004K 0x9900
#define PRID_IMP_LOONGSON1 0x4200
#define PRID_IMP_LOONGSON2 0x6300
@@ -194,9 +195,9 @@ enum cpu_type_enum {
/*
* MIPS32 class processors
*/
- CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_74K, CPU_AU1000,
- CPU_AU1100, CPU_AU1200, CPU_AU1210, CPU_AU1250, CPU_AU1500, CPU_AU1550,
- CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
+ CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
+ CPU_AU1000, CPU_AU1100, CPU_AU1200, CPU_AU1210, CPU_AU1250, CPU_AU1500,
+ CPU_AU1550, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
/*
* MIPS64 class processors
diff --git a/include/asm-mips/dec/ioasic.h b/include/asm-mips/dec/ioasic.h
index 486a5b0a1302..98badd6bf22d 100644
--- a/include/asm-mips/dec/ioasic.h
+++ b/include/asm-mips/dec/ioasic.h
@@ -33,4 +33,6 @@ static inline u32 ioasic_read(unsigned int reg)
extern void init_ioasic_irqs(int base);
+extern void dec_ioasic_clocksource_init(void);
+
#endif /* __ASM_DEC_IOASIC_H */
diff --git a/include/asm-mips/ds1287.h b/include/asm-mips/ds1287.h
new file mode 100644
index 000000000000..ba1702e86931
--- /dev/null
+++ b/include/asm-mips/ds1287.h
@@ -0,0 +1,27 @@
+/*
+ * DS1287 timer functions.
+ *
+ * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __ASM_DS1287_H
+#define __ASM_DS1287_H
+
+extern int ds1287_timer_state(void);
+extern void ds1287_set_base_clock(unsigned int clock);
+extern int ds1287_clockevent_init(int irq);
+
+#endif
diff --git a/include/asm-mips/gcmpregs.h b/include/asm-mips/gcmpregs.h
new file mode 100644
index 000000000000..d74a8a4ca861
--- /dev/null
+++ b/include/asm-mips/gcmpregs.h
@@ -0,0 +1,117 @@
+/*
+ * 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) 2000, 07 MIPS Technologies, Inc.
+ *
+ * Multiprocessor Subsystem Register Definitions
+ *
+ */
+#ifndef _ASM_GCMPREGS_H
+#define _ASM_GCMPREGS_H
+
+
+/* Offsets to major blocks within GCMP from GCMP base */
+#define GCMP_GCB_OFS 0x0000 /* Global Control Block */
+#define GCMP_CLCB_OFS 0x2000 /* Core Local Control Block */
+#define GCMP_COCB_OFS 0x4000 /* Core Other Control Block */
+#define GCMP_GDB_OFS 0x8000 /* Global Debug Block */
+
+/* Offsets to individual GCMP registers from GCMP base */
+#define GCMPOFS(block, tag, reg) (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS)
+
+#define GCMPGCBOFS(reg) GCMPOFS(GCB, GCB, reg)
+#define GCMPCLCBOFS(reg) GCMPOFS(CLCB, CCB, reg)
+#define GCMPCOCBOFS(reg) GCMPOFS(COCB, CCB, reg)
+#define GCMPGDBOFS(reg) GCMPOFS(GDB, GDB, reg)
+
+/* GCMP register access */
+#define GCMPGCB(reg) REGP(_gcmp_base, GCMPGCBOFS(reg))
+#define GCMPCLCB(reg) REGP(_gcmp_base, GCMPCLCBOFS(reg))
+#define GCMPCOCB(reg) REGP(_gcmp_base, GCMPCOCBOFS(reg))
+#define GCMPGDB(reg) REGP(_gcmp_base, GCMPGDBOFS(reg))
+
+/* Mask generation */
+#define GCMPMSK(block, reg, bits) (MSK(bits)<<GCMP_##block##_##reg##_SHF)
+#define GCMPGCBMSK(reg, bits) GCMPMSK(GCB, reg, bits)
+#define GCMPCCBMSK(reg, bits) GCMPMSK(CCB, reg, bits)
+#define GCMPGDBMSK(reg, bits) GCMPMSK(GDB, reg, bits)
+
+/* GCB registers */
+#define GCMP_GCB_GC_OFS 0x0000 /* Global Config Register */
+#define GCMP_GCB_GC_NUMIOCU_SHF 8
+#define GCMP_GCB_GC_NUMIOCU_MSK GCMPGCBMSK(GC_NUMIOCU, 4)
+#define GCMP_GCB_GC_NUMCORES_SHF 0
+#define GCMP_GCB_GC_NUMCORES_MSK GCMPGCBMSK(GC_NUMCORES, 8)
+#define GCMP_GCB_GCMPB_OFS 0x0008 /* Global GCMP Base */
+#define GCMP_GCB_GCMPB_GCMPBASE_SHF 15
+#define GCMP_GCB_GCMPB_GCMPBASE_MSK GCMPGCBMSK(GCMPB_GCMPBASE, 17)
+#define GCMP_GCB_GCMPB_CMDEFTGT_SHF 0
+#define GCMP_GCB_GCMPB_CMDEFTGT_MSK GCMPGCBMSK(GCMPB_CMDEFTGT, 2)
+#define GCMP_GCB_GCMPB_CMDEFTGT_MEM 0
+#define GCMP_GCB_GCMPB_CMDEFTGT_MEM1 1
+#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU1 2
+#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU2 3
+#define GCMP_GCB_CCMC_OFS 0x0010 /* Global CM Control */
+#define GCMP_GCB_GCSRAP_OFS 0x0020 /* Global CSR Access Privilege */
+#define GCMP_GCB_GCSRAP_CMACCESS_SHF 0
+#define GCMP_GCB_GCSRAP_CMACCESS_MSK GCMPGCBMSK(GCSRAP_CMACCESS, 8)
+#define GCMP_GCB_GCMPREV_OFS 0x0030 /* GCMP Revision Register */
+#define GCMP_GCB_GCMEM_OFS 0x0040 /* Global CM Error Mask */
+#define GCMP_GCB_GCMEC_OFS 0x0048 /* Global CM Error Cause */
+#define GCMP_GCB_GMEC_ERROR_TYPE_SHF 27
+#define GCMP_GCB_GMEC_ERROR_TYPE_MSK GCMPGCBMSK(GMEC_ERROR_TYPE, 5)
+#define GCMP_GCB_GMEC_ERROR_INFO_SHF 0
+#define GCMP_GCB_GMEC_ERROR_INFO_MSK GCMPGCBMSK(GMEC_ERROR_INFO, 27)
+#define GCMP_GCB_GCMEA_OFS 0x0050 /* Global CM Error Address */
+#define GCMP_GCB_GCMEO_OFS 0x0058 /* Global CM Error Multiple */
+#define GCMP_GCB_GMEO_ERROR_2ND_SHF 0
+#define GCMP_GCB_GMEO_ERROR_2ND_MSK GCMPGCBMSK(GMEO_ERROR_2ND, 5)
+#define GCMP_GCB_GICBA_OFS 0x0080 /* Global Interrupt Controller Base Address */
+#define GCMP_GCB_GICBA_BASE_SHF 17
+#define GCMP_GCB_GICBA_BASE_MSK GCMPGCBMSK(GICBA_BASE, 15)
+#define GCMP_GCB_GICBA_EN_SHF 0
+#define GCMP_GCB_GICBA_EN_MSK GCMPGCBMSK(GICBA_EN, 1)
+
+/* GCB Regions */
+#define GCMP_GCB_CMxBASE_OFS(n) (0x0090+16*(n)) /* Global Region[0-3] Base Address */
+#define GCMP_GCB_CMxBASE_BASE_SHF 16
+#define GCMP_GCB_CMxBASE_BASE_MSK GCMPGCBMSK(CMxBASE_BASE, 16)
+#define GCMP_GCB_CMxMASK_OFS(n) (0x0098+16*(n)) /* Global Region[0-3] Address Mask */
+#define GCMP_GCB_CMxMASK_MASK_SHF 16
+#define GCMP_GCB_CMxMASK_MASK_MSK GCMPGCBMSK(CMxMASK_MASK, 16)
+#define GCMP_GCB_CMxMASK_CMREGTGT_SHF 0
+#define GCMP_GCB_CMxMASK_CMREGTGT_MSK GCMPGCBMSK(CMxMASK_CMREGTGT, 2)
+#define GCMP_GCB_CMxMASK_CMREGTGT_MEM 0
+#define GCMP_GCB_CMxMASK_CMREGTGT_MEM1 1
+#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU1 2
+#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU2 3
+
+
+/* Core local/Core other control block registers */
+#define GCMP_CCB_RESETR_OFS 0x0000 /* Reset Release */
+#define GCMP_CCB_RESETR_INRESET_SHF 0
+#define GCMP_CCB_RESETR_INRESET_MSK GCMPCCBMSK(RESETR_INRESET, 16)
+#define GCMP_CCB_COHCTL_OFS 0x0008 /* Coherence Control */
+#define GCMP_CCB_COHCTL_DOMAIN_SHF 0
+#define GCMP_CCB_COHCTL_DOMAIN_MSK GCMPCCBMSK(COHCTL_DOMAIN, 8)
+#define GCMP_CCB_CFG_OFS 0x0010 /* Config */
+#define GCMP_CCB_CFG_IOCUTYPE_SHF 10
+#define GCMP_CCB_CFG_IOCUTYPE_MSK GCMPCCBMSK(CFG_IOCUTYPE, 2)
+#define GCMP_CCB_CFG_IOCUTYPE_CPU 0
+#define GCMP_CCB_CFG_IOCUTYPE_NCIOCU 1
+#define GCMP_CCB_CFG_IOCUTYPE_CIOCU 2
+#define GCMP_CCB_CFG_NUMVPE_SHF 0
+#define GCMP_CCB_CFG_NUMVPE_MSK GCMPCCBMSK(CFG_NUMVPE, 10)
+#define GCMP_CCB_OTHER_OFS 0x0018 /* Other Address */
+#define GCMP_CCB_OTHER_CORENUM_SHF 16
+#define GCMP_CCB_OTHER_CORENUM_MSK GCMPCCBMSK(OTHER_CORENUM, 16)
+#define GCMP_CCB_RESETBASE_OFS 0x0020 /* Reset Exception Base */
+#define GCMP_CCB_RESETBASE_BEV_SHF 12
+#define GCMP_CCB_RESETBASE_BEV_MSK GCMPCCBMSK(RESETBASE_BEV, 20)
+#define GCMP_CCB_ID_OFS 0x0028 /* Identification */
+#define GCMP_CCB_DINTGROUP_OFS 0x0030 /* DINT Group Participate */
+#define GCMP_CCB_DBGGROUP_OFS 0x0100 /* DebugBreak Group */
+
+#endif /* _ASM_GCMPREGS_H */
diff --git a/include/asm-mips/gic.h b/include/asm-mips/gic.h
new file mode 100644
index 000000000000..01b2f92dc33d
--- /dev/null
+++ b/include/asm-mips/gic.h
@@ -0,0 +1,487 @@
+/*
+ * 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) 2000, 07 MIPS Technologies, Inc.
+ *
+ * GIC Register Definitions
+ *
+ */
+#ifndef _ASM_GICREGS_H
+#define _ASM_GICREGS_H
+
+#undef GICISBYTELITTLEENDIAN
+#define GICISWORDLITTLEENDIAN
+
+/* Constants */
+#define GIC_POL_POS 1
+#define GIC_POL_NEG 0
+#define GIC_TRIG_EDGE 1
+#define GIC_TRIG_LEVEL 0
+
+#define GIC_NUM_INTRS 32
+
+#define MSK(n) ((1 << (n)) - 1)
+#define REG32(addr) (*(volatile unsigned int *) (addr))
+#define REG(base, offs) REG32((unsigned int)(base) + offs##_##OFS)
+#define REGP(base, phys) REG32((unsigned int)(base) + (phys))
+
+/* Accessors */
+#define GIC_REG(segment, offset) \
+ REG32(_gic_base + segment##_##SECTION_OFS + offset##_##OFS)
+#define GIC_REG_ADDR(segment, offset) \
+ REG32(_gic_base + segment##_##SECTION_OFS + offset)
+
+#define GIC_ABS_REG(segment, offset) \
+ (_gic_base + segment##_##SECTION_OFS + offset##_##OFS)
+#define GIC_REG_ABS_ADDR(segment, offset) \
+ (_gic_base + segment##_##SECTION_OFS + offset)
+
+#ifdef GICISBYTELITTLEENDIAN
+#define GICREAD(reg, data) (data) = (reg), (data) = le32_to_cpu(data)
+#define GICWRITE(reg, data) (reg) = cpu_to_le32(data)
+#define GICBIS(reg, bits) \
+ ({unsigned int data; \
+ GICREAD(reg, data); \
+ data |= bits; \
+ GICWRITE(reg, data); \
+ })
+
+#else
+#define GICREAD(reg, data) (data) = (reg)
+#define GICWRITE(reg, data) (reg) = (data)
+#define GICBIS(reg, bits) (reg) |= (bits)
+#endif
+
+
+/* GIC Address Space */
+#define SHARED_SECTION_OFS 0x0000
+#define SHARED_SECTION_SIZE 0x8000
+#define VPE_LOCAL_SECTION_OFS 0x8000
+#define VPE_LOCAL_SECTION_SIZE 0x4000
+#define VPE_OTHER_SECTION_OFS 0xc000
+#define VPE_OTHER_SECTION_SIZE 0x4000
+#define USM_VISIBLE_SECTION_OFS 0x10000
+#define USM_VISIBLE_SECTION_SIZE 0x10000
+
+/* Register Map for Shared Section */
+#if defined(CONFIG_CPU_LITTLE_ENDIAN) || defined(GICISWORDLITTLEENDIAN)
+
+#define GIC_SH_CONFIG_OFS 0x0000
+
+/* Shared Global Counter */
+#define GIC_SH_COUNTER_31_00_OFS 0x0010
+#define GIC_SH_COUNTER_63_32_OFS 0x0014
+
+/* Interrupt Polarity */
+#define GIC_SH_POL_31_0_OFS 0x0100
+#define GIC_SH_POL_63_32_OFS 0x0104
+#define GIC_SH_POL_95_64_OFS 0x0108
+#define GIC_SH_POL_127_96_OFS 0x010c
+#define GIC_SH_POL_159_128_OFS 0x0110
+#define GIC_SH_POL_191_160_OFS 0x0114
+#define GIC_SH_POL_223_192_OFS 0x0118
+#define GIC_SH_POL_255_224_OFS 0x011c
+
+/* Edge/Level Triggering */
+#define GIC_SH_TRIG_31_0_OFS 0x0180
+#define GIC_SH_TRIG_63_32_OFS 0x0184
+#define GIC_SH_TRIG_95_64_OFS 0x0188
+#define GIC_SH_TRIG_127_96_OFS 0x018c
+#define GIC_SH_TRIG_159_128_OFS 0x0190
+#define GIC_SH_TRIG_191_160_OFS 0x0194
+#define GIC_SH_TRIG_223_192_OFS 0x0198
+#define GIC_SH_TRIG_255_224_OFS 0x019c
+
+/* Dual Edge Triggering */
+#define GIC_SH_DUAL_31_0_OFS 0x0200
+#define GIC_SH_DUAL_63_32_OFS 0x0204
+#define GIC_SH_DUAL_95_64_OFS 0x0208
+#define GIC_SH_DUAL_127_96_OFS 0x020c
+#define GIC_SH_DUAL_159_128_OFS 0x0210
+#define GIC_SH_DUAL_191_160_OFS 0x0214
+#define GIC_SH_DUAL_223_192_OFS 0x0218
+#define GIC_SH_DUAL_255_224_OFS 0x021c
+
+/* Set/Clear corresponding bit in Edge Detect Register */
+#define GIC_SH_WEDGE_OFS 0x0280
+
+/* Reset Mask - Disables Interrupt */
+#define GIC_SH_RMASK_31_0_OFS 0x0300
+#define GIC_SH_RMASK_63_32_OFS 0x0304
+#define GIC_SH_RMASK_95_64_OFS 0x0308
+#define GIC_SH_RMASK_127_96_OFS 0x030c
+#define GIC_SH_RMASK_159_128_OFS 0x0310
+#define GIC_SH_RMASK_191_160_OFS 0x0314
+#define GIC_SH_RMASK_223_192_OFS 0x0318
+#define GIC_SH_RMASK_255_224_OFS 0x031c
+
+/* Set Mask (WO) - Enables Interrupt */
+#define GIC_SH_SMASK_31_0_OFS 0x0380
+#define GIC_SH_SMASK_63_32_OFS 0x0384
+#define GIC_SH_SMASK_95_64_OFS 0x0388
+#define GIC_SH_SMASK_127_96_OFS 0x038c
+#define GIC_SH_SMASK_159_128_OFS 0x0390
+#define GIC_SH_SMASK_191_160_OFS 0x0394
+#define GIC_SH_SMASK_223_192_OFS 0x0398
+#define GIC_SH_SMASK_255_224_OFS 0x039c
+
+/* Global Interrupt Mask Register (RO) - Bit Set == Interrupt enabled */
+#define GIC_SH_MASK_31_0_OFS 0x0400
+#define GIC_SH_MASK_63_32_OFS 0x0404
+#define GIC_SH_MASK_95_64_OFS 0x0408
+#define GIC_SH_MASK_127_96_OFS 0x040c
+#define GIC_SH_MASK_159_128_OFS 0x0410
+#define GIC_SH_MASK_191_160_OFS 0x0414
+#define GIC_SH_MASK_223_192_OFS 0x0418
+#define GIC_SH_MASK_255_224_OFS 0x041c
+
+/* Pending Global Interrupts (RO) */
+#define GIC_SH_PEND_31_0_OFS 0x0480
+#define GIC_SH_PEND_63_32_OFS 0x0484
+#define GIC_SH_PEND_95_64_OFS 0x0488
+#define GIC_SH_PEND_127_96_OFS 0x048c
+#define GIC_SH_PEND_159_128_OFS 0x0490
+#define GIC_SH_PEND_191_160_OFS 0x0494
+#define GIC_SH_PEND_223_192_OFS 0x0498
+#define GIC_SH_PEND_255_224_OFS 0x049c
+
+#define GIC_SH_INTR_MAP_TO_PIN_BASE_OFS 0x0500
+
+/* Maps Interrupt X to a Pin */
+#define GIC_SH_MAP_TO_PIN(intr) \
+ (GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + (4 * intr))
+
+#define GIC_SH_INTR_MAP_TO_VPE_BASE_OFS 0x2000
+
+/* Maps Interrupt X to a VPE */
+#define GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe) \
+ (GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + (32 * (intr)) + (((vpe) / 32) * 4))
+#define GIC_SH_MAP_TO_VPE_REG_BIT(vpe) (1 << ((vpe) % 32))
+
+/* Polarity : Reset Value is always 0 */
+#define GIC_SH_SET_POLARITY_OFS 0x0100
+#define GIC_SET_POLARITY(intr, pol) \
+ GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_POLARITY_OFS + (((intr) / 32) * 4)), (pol) << ((intr) % 32))
+
+/* Triggering : Reset Value is always 0 */
+#define GIC_SH_SET_TRIGGER_OFS 0x0180
+#define GIC_SET_TRIGGER(intr, trig) \
+ GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_TRIGGER_OFS + (((intr) / 32) * 4)), (trig) << ((intr) % 32))
+
+/* Mask manipulation */
+#define GIC_SH_SMASK_OFS 0x0380
+#define GIC_SET_INTR_MASK(intr, val) \
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_SMASK_OFS + (((intr) / 32) * 4)), ((val) << ((intr) % 32)))
+
+#define GIC_SH_RMASK_OFS 0x0300
+#define GIC_CLR_INTR_MASK(intr, val) \
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_RMASK_OFS + (((intr) / 32) * 4)), ((val) << ((intr) % 32)))
+
+/* Register Map for Local Section */
+#define GIC_VPE_CTL_OFS 0x0000
+#define GIC_VPE_PEND_OFS 0x0004
+#define GIC_VPE_MASK_OFS 0x0008
+#define GIC_VPE_RMASK_OFS 0x000c
+#define GIC_VPE_SMASK_OFS 0x0010
+#define GIC_VPE_WD_MAP_OFS 0x0040
+#define GIC_VPE_COMPARE_MAP_OFS 0x0044
+#define GIC_VPE_TIMER_MAP_OFS 0x0048
+#define GIC_VPE_PERFCTR_MAP_OFS 0x0050
+#define GIC_VPE_SWINT0_MAP_OFS 0x0054
+#define GIC_VPE_SWINT1_MAP_OFS 0x0058
+#define GIC_VPE_OTHER_ADDR_OFS 0x0080
+#define GIC_VPE_WD_CONFIG0_OFS 0x0090
+#define GIC_VPE_WD_COUNT0_OFS 0x0094
+#define GIC_VPE_WD_INITIAL0_OFS 0x0098
+#define GIC_VPE_COMPARE_LO_OFS 0x00a0
+#define GIC_VPE_COMPARE_HI 0x00a4
+
+#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100
+#define GIC_VPE_EIC_SS(intr) \
+ (GIC_EIC_SHADOW_SET_BASE + (4 * intr))
+
+#define GIC_VPE_EIC_VEC_BASE 0x0800
+#define GIC_VPE_EIC_VEC(intr) \
+ (GIC_VPE_EIC_VEC_BASE + (4 * intr))
+
+#define GIC_VPE_TENABLE_NMI_OFS 0x1000
+#define GIC_VPE_TENABLE_YQ_OFS 0x1004
+#define GIC_VPE_TENABLE_INT_31_0_OFS 0x1080
+#define GIC_VPE_TENABLE_INT_63_32_OFS 0x1084
+
+/* User Mode Visible Section Register Map */
+#define GIC_UMV_SH_COUNTER_31_00_OFS 0x0000
+#define GIC_UMV_SH_COUNTER_63_32_OFS 0x0004
+
+#else /* CONFIG_CPU_BIG_ENDIAN */
+
+#define GIC_SH_CONFIG_OFS 0x0000
+
+/* Shared Global Counter */
+#define GIC_SH_COUNTER_31_00_OFS 0x0014
+#define GIC_SH_COUNTER_63_32_OFS 0x0010
+
+/* Interrupt Polarity */
+#define GIC_SH_POL_31_0_OFS 0x0104
+#define GIC_SH_POL_63_32_OFS 0x0100
+#define GIC_SH_POL_95_64_OFS 0x010c
+#define GIC_SH_POL_127_96_OFS 0x0108
+#define GIC_SH_POL_159_128_OFS 0x0114
+#define GIC_SH_POL_191_160_OFS 0x0110
+#define GIC_SH_POL_223_192_OFS 0x011c
+#define GIC_SH_POL_255_224_OFS 0x0118
+
+/* Edge/Level Triggering */
+#define GIC_SH_TRIG_31_0_OFS 0x0184
+#define GIC_SH_TRIG_63_32_OFS 0x0180
+#define GIC_SH_TRIG_95_64_OFS 0x018c
+#define GIC_SH_TRIG_127_96_OFS 0x0188
+#define GIC_SH_TRIG_159_128_OFS 0x0194
+#define GIC_SH_TRIG_191_160_OFS 0x0190
+#define GIC_SH_TRIG_223_192_OFS 0x019c
+#define GIC_SH_TRIG_255_224_OFS 0x0198
+
+/* Dual Edge Triggering */
+#define GIC_SH_DUAL_31_0_OFS 0x0204
+#define GIC_SH_DUAL_63_32_OFS 0x0200
+#define GIC_SH_DUAL_95_64_OFS 0x020c
+#define GIC_SH_DUAL_127_96_OFS 0x0208
+#define GIC_SH_DUAL_159_128_OFS 0x0214
+#define GIC_SH_DUAL_191_160_OFS 0x0210
+#define GIC_SH_DUAL_223_192_OFS 0x021c
+#define GIC_SH_DUAL_255_224_OFS 0x0218
+
+/* Set/Clear corresponding bit in Edge Detect Register */
+#define GIC_SH_WEDGE_OFS 0x0280
+
+/* Reset Mask - Disables Interrupt */
+#define GIC_SH_RMASK_31_0_OFS 0x0304
+#define GIC_SH_RMASK_63_32_OFS 0x0300
+#define GIC_SH_RMASK_95_64_OFS 0x030c
+#define GIC_SH_RMASK_127_96_OFS 0x0308
+#define GIC_SH_RMASK_159_128_OFS 0x0314
+#define GIC_SH_RMASK_191_160_OFS 0x0310
+#define GIC_SH_RMASK_223_192_OFS 0x031c
+#define GIC_SH_RMASK_255_224_OFS 0x0318
+
+/* Set Mask (WO) - Enables Interrupt */
+#define GIC_SH_SMASK_31_0_OFS 0x0384
+#define GIC_SH_SMASK_63_32_OFS 0x0380
+#define GIC_SH_SMASK_95_64_OFS 0x038c
+#define GIC_SH_SMASK_127_96_OFS 0x0388
+#define GIC_SH_SMASK_159_128_OFS 0x0394
+#define GIC_SH_SMASK_191_160_OFS 0x0390
+#define GIC_SH_SMASK_223_192_OFS 0x039c
+#define GIC_SH_SMASK_255_224_OFS 0x0398
+
+/* Global Interrupt Mask Register (RO) - Bit Set == Interrupt enabled */
+#define GIC_SH_MASK_31_0_OFS 0x0404
+#define GIC_SH_MASK_63_32_OFS 0x0400
+#define GIC_SH_MASK_95_64_OFS 0x040c
+#define GIC_SH_MASK_127_96_OFS 0x0408
+#define GIC_SH_MASK_159_128_OFS 0x0414
+#define GIC_SH_MASK_191_160_OFS 0x0410
+#define GIC_SH_MASK_223_192_OFS 0x041c
+#define GIC_SH_MASK_255_224_OFS 0x0418
+
+/* Pending Global Interrupts (RO) */
+#define GIC_SH_PEND_31_0_OFS 0x0484
+#define GIC_SH_PEND_63_32_OFS 0x0480
+#define GIC_SH_PEND_95_64_OFS 0x048c
+#define GIC_SH_PEND_127_96_OFS 0x0488
+#define GIC_SH_PEND_159_128_OFS 0x0494
+#define GIC_SH_PEND_191_160_OFS 0x0490
+#define GIC_SH_PEND_223_192_OFS 0x049c
+#define GIC_SH_PEND_255_224_OFS 0x0498
+
+#define GIC_SH_INTR_MAP_TO_PIN_BASE_OFS 0x0500
+
+/* Maps Interrupt X to a Pin */
+#define GIC_SH_MAP_TO_PIN(intr) \
+ (GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + (4 * intr))
+
+#define GIC_SH_INTR_MAP_TO_VPE_BASE_OFS 0x2004
+
+/*
+ * Maps Interrupt X to a VPE. This is more complex than the LE case, as
+ * odd and even registers need to be transposed. It does work - trust me!
+ */
+#define GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe) \
+ (GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + (32 * (intr)) + \
+ (((((vpe) / 32) ^ 1) - 1) * 4))
+#define GIC_SH_MAP_TO_VPE_REG_BIT(vpe) (1 << ((vpe) % 32))
+
+/* Polarity */
+#define GIC_SH_SET_POLARITY_OFS 0x0100
+#define GIC_SET_POLARITY(intr, pol) \
+ GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_POLARITY_OFS + 4 + (((((intr) / 32) ^ 1) - 1) * 4)), (pol) << ((intr) % 32))
+
+/* Triggering */
+#define GIC_SH_SET_TRIGGER_OFS 0x0180
+#define GIC_SET_TRIGGER(intr, trig) \
+ GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_TRIGGER_OFS + 4 + (((((intr) / 32) ^ 1) - 1) * 4)), (trig) << ((intr) % 32))
+
+/* Mask manipulation */
+#define GIC_SH_SMASK_OFS 0x0380
+#define GIC_SET_INTR_MASK(intr, val) \
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_SMASK_OFS + 4 + (((((intr) / 32) ^ 1) - 1) * 4)), ((val) << ((intr) % 32)))
+
+#define GIC_SH_RMASK_OFS 0x0300
+#define GIC_CLR_INTR_MASK(intr, val) \
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_RMASK_OFS + 4 + (((((intr) / 32) ^ 1) - 1) * 4)), ((val) << ((intr) % 32))
+
+/* Register Map for Local Section */
+#define GIC_VPE_CTL_OFS 0x0000
+#define GIC_VPE_PEND_OFS 0x0004
+#define GIC_VPE_MASK_OFS 0x0008
+#define GIC_VPE_RMASK_OFS 0x000c
+#define GIC_VPE_SMASK_OFS 0x0010
+#define GIC_VPE_WD_MAP_OFS 0x0040
+#define GIC_VPE_COMPARE_MAP_OFS 0x0044
+#define GIC_VPE_TIMER_MAP_OFS 0x0048
+#define GIC_VPE_PERFCTR_MAP_OFS 0x0050
+#define GIC_VPE_SWINT0_MAP_OFS 0x0054
+#define GIC_VPE_SWINT1_MAP_OFS 0x0058
+#define GIC_VPE_OTHER_ADDR_OFS 0x0080
+#define GIC_VPE_WD_CONFIG0_OFS 0x0090
+#define GIC_VPE_WD_COUNT0_OFS 0x0094
+#define GIC_VPE_WD_INITIAL0_OFS 0x0098
+#define GIC_VPE_COMPARE_LO_OFS 0x00a4
+#define GIC_VPE_COMPARE_HI_OFS 0x00a0
+
+#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100
+#define GIC_VPE_EIC_SS(intr) \
+ (GIC_EIC_SHADOW_SET_BASE + (4 * intr))
+
+#define GIC_VPE_EIC_VEC_BASE 0x0800
+#define GIC_VPE_EIC_VEC(intr) \
+ (GIC_VPE_EIC_VEC_BASE + (4 * intr))
+
+#define GIC_VPE_TENABLE_NMI_OFS 0x1000
+#define GIC_VPE_TENABLE_YQ_OFS 0x1004
+#define GIC_VPE_TENABLE_INT_31_0_OFS 0x1080
+#define GIC_VPE_TENABLE_INT_63_32_OFS 0x1084
+
+/* User Mode Visible Section Register Map */
+#define GIC_UMV_SH_COUNTER_31_00_OFS 0x0004
+#define GIC_UMV_SH_COUNTER_63_32_OFS 0x0000
+
+#endif /* !LE */
+
+/* Masks */
+#define GIC_SH_CONFIG_COUNTSTOP_SHF 28
+#define GIC_SH_CONFIG_COUNTSTOP_MSK (MSK(1) << GIC_SH_CONFIG_COUNTSTOP_SHF)
+
+#define GIC_SH_CONFIG_COUNTBITS_SHF 24
+#define GIC_SH_CONFIG_COUNTBITS_MSK (MSK(4) << GIC_SH_CONFIG_COUNTBITS_SHF)
+
+#define GIC_SH_CONFIG_NUMINTRS_SHF 16
+#define GIC_SH_CONFIG_NUMINTRS_MSK (MSK(8) << GIC_SH_CONFIG_NUMINTRS_SHF)
+
+#define GIC_SH_CONFIG_NUMVPES_SHF 0
+#define GIC_SH_CONFIG_NUMVPES_MSK (MSK(8) << GIC_SH_CONFIG_NUMVPES_SHF)
+
+#define GIC_SH_WEDGE_SET(intr) (intr | (0x1 << 31))
+#define GIC_SH_WEDGE_CLR(intr) (intr & ~(0x1 << 31))
+
+#define GIC_MAP_TO_PIN_SHF 31
+#define GIC_MAP_TO_PIN_MSK (MSK(1) << GIC_MAP_TO_PIN_SHF)
+#define GIC_MAP_TO_NMI_SHF 30
+#define GIC_MAP_TO_NMI_MSK (MSK(1) << GIC_MAP_TO_NMI_SHF)
+#define GIC_MAP_TO_YQ_SHF 29
+#define GIC_MAP_TO_YQ_MSK (MSK(1) << GIC_MAP_TO_YQ_SHF)
+#define GIC_MAP_SHF 0
+#define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF)
+
+/* GIC_VPE_CTL Masks */
+#define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2
+#define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF)
+#define GIC_VPE_CTL_TIMER_RTBL_SHF 1
+#define GIC_VPE_CTL_TIMER_RTBL_MSK (MSK(1) << GIC_VPE_CTL_TIMER_RTBL_SHF)
+#define GIC_VPE_CTL_EIC_MODE_SHF 0
+#define GIC_VPE_CTL_EIC_MODE_MSK (MSK(1) << GIC_VPE_CTL_EIC_MODE_SHF)
+
+/* GIC_VPE_PEND Masks */
+#define GIC_VPE_PEND_WD_SHF 0
+#define GIC_VPE_PEND_WD_MSK (MSK(1) << GIC_VPE_PEND_WD_SHF)
+#define GIC_VPE_PEND_CMP_SHF 1
+#define GIC_VPE_PEND_CMP_MSK (MSK(1) << GIC_VPE_PEND_CMP_SHF)
+#define GIC_VPE_PEND_TIMER_SHF 2
+#define GIC_VPE_PEND_TIMER_MSK (MSK(1) << GIC_VPE_PEND_TIMER_SHF)
+#define GIC_VPE_PEND_PERFCOUNT_SHF 3
+#define GIC_VPE_PEND_PERFCOUNT_MSK (MSK(1) << GIC_VPE_PEND_PERFCOUNT_SHF)
+#define GIC_VPE_PEND_SWINT0_SHF 4
+#define GIC_VPE_PEND_SWINT0_MSK (MSK(1) << GIC_VPE_PEND_SWINT0_SHF)
+#define GIC_VPE_PEND_SWINT1_SHF 5
+#define GIC_VPE_PEND_SWINT1_MSK (MSK(1) << GIC_VPE_PEND_SWINT1_SHF)
+
+/* GIC_VPE_RMASK Masks */
+#define GIC_VPE_RMASK_WD_SHF 0
+#define GIC_VPE_RMASK_WD_MSK (MSK(1) << GIC_VPE_RMASK_WD_SHF)
+#define GIC_VPE_RMASK_CMP_SHF 1
+#define GIC_VPE_RMASK_CMP_MSK (MSK(1) << GIC_VPE_RMASK_CMP_SHF)
+#define GIC_VPE_RMASK_TIMER_SHF 2
+#define GIC_VPE_RMASK_TIMER_MSK (MSK(1) << GIC_VPE_RMASK_TIMER_SHF)
+#define GIC_VPE_RMASK_PERFCNT_SHF 3
+#define GIC_VPE_RMASK_PERFCNT_MSK (MSK(1) << GIC_VPE_RMASK_PERFCNT_SHF)
+#define GIC_VPE_RMASK_SWINT0_SHF 4
+#define GIC_VPE_RMASK_SWINT0_MSK (MSK(1) << GIC_VPE_RMASK_SWINT0_SHF)
+#define GIC_VPE_RMASK_SWINT1_SHF 5
+#define GIC_VPE_RMASK_SWINT1_MSK (MSK(1) << GIC_VPE_RMASK_SWINT1_SHF)
+
+/* GIC_VPE_SMASK Masks */
+#define GIC_VPE_SMASK_WD_SHF 0
+#define GIC_VPE_SMASK_WD_MSK (MSK(1) << GIC_VPE_SMASK_WD_SHF)
+#define GIC_VPE_SMASK_CMP_SHF 1
+#define GIC_VPE_SMASK_CMP_MSK (MSK(1) << GIC_VPE_SMASK_CMP_SHF)
+#define GIC_VPE_SMASK_TIMER_SHF 2
+#define GIC_VPE_SMASK_TIMER_MSK (MSK(1) << GIC_VPE_SMASK_TIMER_SHF)
+#define GIC_VPE_SMASK_PERFCNT_SHF 3
+#define GIC_VPE_SMASK_PERFCNT_MSK (MSK(1) << GIC_VPE_SMASK_PERFCNT_SHF)
+#define GIC_VPE_SMASK_SWINT0_SHF 4
+#define GIC_VPE_SMASK_SWINT0_MSK (MSK(1) << GIC_VPE_SMASK_SWINT0_SHF)
+#define GIC_VPE_SMASK_SWINT1_SHF 5
+#define GIC_VPE_SMASK_SWINT1_MSK (MSK(1) << GIC_VPE_SMASK_SWINT1_SHF)
+
+/*
+ * Set the Mapping of Interrupt X to a VPE.
+ */
+#define GIC_SH_MAP_TO_VPE_SMASK(intr, vpe) \
+ GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \
+ GIC_SH_MAP_TO_VPE_REG_BIT(vpe))
+
+struct gic_pcpu_mask {
+ DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS);
+};
+
+struct gic_pending_regs {
+ DECLARE_BITMAP(pending, GIC_NUM_INTRS);
+};
+
+struct gic_intrmask_regs {
+ DECLARE_BITMAP(intrmask, GIC_NUM_INTRS);
+};
+
+/*
+ * Interrupt Meta-data specification. The ipiflag helps
+ * in building ipi_map.
+ */
+struct gic_intr_map {
+ unsigned int intrnum; /* Ext Intr Num */
+ unsigned int cpunum; /* Directed to this CPU */
+ unsigned int pin; /* Directed to this Pin */
+ unsigned int polarity; /* Polarity : +/- */
+ unsigned int trigtype; /* Trigger : Edge/Levl */
+ unsigned int ipiflag; /* Is used for IPI ? */
+};
+
+extern void gic_init(unsigned long gic_base_addr,
+ unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
+ unsigned int intrmap_size, unsigned int irqbase);
+
+extern unsigned int gic_get_int(void);
+extern void gic_send_ipi(unsigned int intr);
+
+#endif /* _ASM_GICREGS_H */
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index e62058b0d28c..f18d2816cbec 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -273,7 +273,7 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
* memory-like regions on I/O busses.
*/
#define ioremap_cachable(offset, size) \
- __ioremap_mode((offset), (size), PAGE_CACHABLE_DEFAULT)
+ __ioremap_mode((offset), (size), _page_cachable_default)
/*
* These two are MIPS specific ioremap variant. ioremap_cacheable_cow
diff --git a/include/asm-mips/jmr3927/jmr3927.h b/include/asm-mips/jmr3927/jmr3927.h
index 81602c8047eb..a162268f17df 100644
--- a/include/asm-mips/jmr3927/jmr3927.h
+++ b/include/asm-mips/jmr3927/jmr3927.h
@@ -99,8 +99,8 @@
#define jmr3927_led_and_set(n/*0-16*/) jmr3927_ioc_reg_out((~(n)) & jmr3927_ioc_reg_in(JMR3927_IOC_LED_ADDR), JMR3927_IOC_LED_ADDR)
/* DIPSW4 macro */
-#define jmr3927_dipsw1() ((tx3927_pioptr->din & (1 << 11)) == 0)
-#define jmr3927_dipsw2() ((tx3927_pioptr->din & (1 << 10)) == 0)
+#define jmr3927_dipsw1() (gpio_get_value(11) == 0)
+#define jmr3927_dipsw2() (gpio_get_value(10) == 0)
#define jmr3927_dipsw3() ((jmr3927_ioc_reg_in(JMR3927_IOC_DIPSW_ADDR) & 2) == 0)
#define jmr3927_dipsw4() ((jmr3927_ioc_reg_in(JMR3927_IOC_DIPSW_ADDR) & 1) == 0)
diff --git a/include/asm-mips/jmr3927/tx3927.h b/include/asm-mips/jmr3927/tx3927.h
index 338f99882a39..fb580333c102 100644
--- a/include/asm-mips/jmr3927/tx3927.h
+++ b/include/asm-mips/jmr3927/tx3927.h
@@ -314,6 +314,6 @@ struct tx3927_ccfg_reg {
#define tx3927_ccfgptr ((struct tx3927_ccfg_reg *)TX3927_CCFG_REG)
#define tx3927_tmrptr(ch) ((struct txx927_tmr_reg *)TX3927_TMR_REG(ch))
#define tx3927_sioptr(ch) ((struct txx927_sio_reg *)TX3927_SIO_REG(ch))
-#define tx3927_pioptr ((struct txx927_pio_reg *)TX3927_PIO_REG)
+#define tx3927_pioptr ((struct txx9_pio_reg __iomem *)TX3927_PIO_REG)
#endif /* __ASM_TX3927_H */
diff --git a/include/asm-mips/jmr3927/txx927.h b/include/asm-mips/jmr3927/txx927.h
index 0474fe8dac3f..25dcf2feb095 100644
--- a/include/asm-mips/jmr3927/txx927.h
+++ b/include/asm-mips/jmr3927/txx927.h
@@ -22,18 +22,6 @@ struct txx927_sio_reg {
volatile unsigned long rfifo;
};
-struct txx927_pio_reg {
- volatile unsigned long dout;
- volatile unsigned long din;
- volatile unsigned long dir;
- volatile unsigned long od;
- volatile unsigned long flag[2];
- volatile unsigned long pol;
- volatile unsigned long intc;
- volatile unsigned long maskcpu;
- volatile unsigned long maskext;
-};
-
/*
* SIO
*/
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 5bb57bf2b9d7..a05555165d05 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -3,9 +3,8 @@
* BRIEF MODULE DESCRIPTION
* Include file for Alchemy Semiconductor's Au1k CPU.
*
- * Copyright 2000,2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
+ * Copyright 2000-2001, 2006-2008 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. <source@mvista.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -117,13 +116,6 @@ extern struct au1xxx_irqmap au1xxx_irq_map[];
#endif /* !defined (_LANGUAGE_ASSEMBLY) */
-#ifdef CONFIG_PM
-/* no CP0 timer irq */
-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
-#else
-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
-#endif
-
/*
* SDRAM Register Offsets
*/
@@ -1693,20 +1685,6 @@ enum soc_au1200_ints {
#define IOMEM_RESOURCE_START 0x10000000
#define IOMEM_RESOURCE_END 0xffffffff
- /*
- * Borrowed from the PPC arch:
- * The following macro is used to lookup irqs in a standard table
- * format for those PPC systems that do not already have PCI
- * interrupts properly routed.
- */
- /* FIXME - double check this from asm-ppc/pci-bridge.h */
-#define PCI_IRQ_TABLE_LOOKUP \
- ({ long _ctl_ = -1; \
- if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \
- _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \
- _ctl_; })
-
-
#else /* Au1000 and Au1100 and Au1200 */
/* don't allow any legacy ports probing */
diff --git a/include/asm-mips/mach-au1x00/au1xxx_ide.h b/include/asm-mips/mach-au1x00/au1xxx_ide.h
index 89655c0cdcd6..b493a5e46c63 100644
--- a/include/asm-mips/mach-au1x00/au1xxx_ide.h
+++ b/include/asm-mips/mach-au1x00/au1xxx_ide.h
@@ -70,7 +70,6 @@ typedef struct
ide_hwif_t *hwif;
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
ide_drive_t *drive;
- u8 white_list, black_list;
struct dbdma_cmd *dma_table_cpu;
dma_addr_t dma_table_dma;
#endif
@@ -81,47 +80,6 @@ typedef struct
#endif
} _auide_hwif;
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-/* HD white list */
-static const struct drive_list_entry dma_white_list [] = {
-/*
- * Hitachi
- */
- { "HITACHI_DK14FA-20" , NULL },
- { "HTS726060M9AT00" , NULL },
-/*
- * Maxtor
- */
- { "Maxtor 6E040L0" , NULL },
- { "Maxtor 6Y080P0" , NULL },
- { "Maxtor 6Y160P0" , NULL },
-/*
- * Seagate
- */
- { "ST3120026A" , NULL },
- { "ST320014A" , NULL },
- { "ST94011A" , NULL },
- { "ST340016A" , NULL },
-/*
- * Western Digital
- */
- { "WDC WD400UE-00HCT0" , NULL },
- { "WDC WD400JB-00JJC0" , NULL },
- { NULL , NULL }
-};
-
-/* HD black list */
-static const struct drive_list_entry dma_black_list [] = {
-/*
- * Western Digital
- */
- { "WDC WD100EB-00CGH0" , NULL },
- { "WDC WD200BB-00AUA1" , NULL },
- { "WDC AC24300L" , NULL },
- { NULL , NULL }
-};
-#endif
-
/*******************************************************************************
* PIO Mode timing calculation : *
* *
diff --git a/include/asm-mips/mach-db1x00/db1200.h b/include/asm-mips/mach-db1x00/db1200.h
index d2e28e64932e..eedd048a7261 100644
--- a/include/asm-mips/mach-db1x00/db1200.h
+++ b/include/asm-mips/mach-db1x00/db1200.h
@@ -169,15 +169,15 @@ static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
#define BCSR_INT_SD0INSERT 0x1000
#define BCSR_INT_SD0EJECT 0x2000
-#define AU1XXX_SMC91111_PHYS_ADDR (0x19000300)
-#define AU1XXX_SMC91111_IRQ DB1200_ETH_INT
-
-#define AU1XXX_ATA_PHYS_ADDR (0x18800000)
-#define AU1XXX_ATA_REG_OFFSET (5)
-#define AU1XXX_ATA_PHYS_LEN (16 << AU1XXX_ATA_REG_OFFSET)
-#define AU1XXX_ATA_INT DB1200_IDE_INT
-#define AU1XXX_ATA_DDMA_REQ DSCR_CMD0_DMA_REQ1;
-#define AU1XXX_ATA_RQSIZE 128
+#define SMC91C111_PHYS_ADDR 0x19000300
+#define SMC91C111_INT DB1200_ETH_INT
+
+#define IDE_PHYS_ADDR 0x18800000
+#define IDE_REG_SHIFT 5
+#define IDE_PHYS_LEN (16 << IDE_REG_SHIFT)
+#define IDE_INT DB1200_IDE_INT
+#define IDE_DDMA_REQ DSCR_CMD0_DMA_REQ1
+#define IDE_RQSIZE 128
#define NAND_PHYS_ADDR 0x20000000
diff --git a/include/asm-mips/mach-generic/gpio.h b/include/asm-mips/mach-generic/gpio.h
index 6eaf5efedf3a..e6b376bd9d06 100644
--- a/include/asm-mips/mach-generic/gpio.h
+++ b/include/asm-mips/mach-generic/gpio.h
@@ -1,12 +1,18 @@
#ifndef __ASM_MACH_GENERIC_GPIO_H
#define __ASM_MACH_GENERIC_GPIO_H
+#ifdef CONFIG_HAVE_GPIO_LIB
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#else
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
+#endif
int gpio_to_irq(unsigned gpio);
int irq_to_gpio(unsigned irq);
diff --git a/include/asm-mips/mach-ip27/topology.h b/include/asm-mips/mach-ip27/topology.h
index 372291f53fb9..7785bec732f2 100644
--- a/include/asm-mips/mach-ip27/topology.h
+++ b/include/asm-mips/mach-ip27/topology.h
@@ -54,4 +54,6 @@ extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
.nr_balance_failed = 0, \
}
+#include <asm-generic/topology.h>
+
#endif /* _ASM_MACH_TOPOLOGY_H */
diff --git a/include/asm-mips/mach-pb1x00/pb1200.h b/include/asm-mips/mach-pb1x00/pb1200.h
index edaa489b58f1..e2c6bcac3b42 100644
--- a/include/asm-mips/mach-pb1x00/pb1200.h
+++ b/include/asm-mips/mach-pb1x00/pb1200.h
@@ -182,15 +182,15 @@ static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
#define SET_VCC_VPP(VCC, VPP, SLOT)\
((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
-#define AU1XXX_SMC91111_PHYS_ADDR (0x0D000300)
-#define AU1XXX_SMC91111_IRQ PB1200_ETH_INT
-
-#define AU1XXX_ATA_PHYS_ADDR (0x0C800000)
-#define AU1XXX_ATA_REG_OFFSET (5)
-#define AU1XXX_ATA_PHYS_LEN (16 << AU1XXX_ATA_REG_OFFSET)
-#define AU1XXX_ATA_INT PB1200_IDE_INT
-#define AU1XXX_ATA_DDMA_REQ DSCR_CMD0_DMA_REQ1;
-#define AU1XXX_ATA_RQSIZE 128
+#define SMC91C111_PHYS_ADDR 0x0D000300
+#define SMC91C111_INT PB1200_ETH_INT
+
+#define IDE_PHYS_ADDR 0x0C800000
+#define IDE_REG_SHIFT 5
+#define IDE_PHYS_LEN (16 << IDE_REG_SHIFT)
+#define IDE_INT PB1200_IDE_INT
+#define IDE_DDMA_REQ DSCR_CMD0_DMA_REQ1
+#define IDE_RQSIZE 128
#define NAND_PHYS_ADDR 0x1C000000
diff --git a/include/asm-mips/mips-boards/generic.h b/include/asm-mips/mips-boards/generic.h
index 1c39d339521e..33407bee4e73 100644
--- a/include/asm-mips/mips-boards/generic.h
+++ b/include/asm-mips/mips-boards/generic.h
@@ -68,6 +68,7 @@
#define MIPS_REVISION_CORID_CORE_FPGA3 9
#define MIPS_REVISION_CORID_CORE_24K 10
#define MIPS_REVISION_CORID_CORE_FPGA4 11
+#define MIPS_REVISION_CORID_CORE_FPGA5 12
/**** Artificial corid defines ****/
/*
diff --git a/include/asm-mips/mips-boards/launch.h b/include/asm-mips/mips-boards/launch.h
new file mode 100644
index 000000000000..d8ae7f95a522
--- /dev/null
+++ b/include/asm-mips/mips-boards/launch.h
@@ -0,0 +1,35 @@
+/*
+ *
+ */
+
+#ifndef _ASSEMBLER_
+
+struct cpulaunch {
+ unsigned long pc;
+ unsigned long gp;
+ unsigned long sp;
+ unsigned long a0;
+ unsigned long _pad[3]; /* pad to cache line size to avoid thrashing */
+ unsigned long flags;
+};
+
+#else
+
+#define LOG2CPULAUNCH 5
+#define LAUNCH_PC 0
+#define LAUNCH_GP 4
+#define LAUNCH_SP 8
+#define LAUNCH_A0 12
+#define LAUNCH_FLAGS 28
+
+#endif
+
+#define LAUNCH_FREADY 1
+#define LAUNCH_FGO 2
+#define LAUNCH_FGONE 4
+
+#define CPULAUNCH 0x00000f00
+#define NCPULAUNCH 8
+
+/* Polling period in count cycles for secondary CPU's */
+#define LAUNCHPERIOD 10000
diff --git a/include/asm-mips/mips-boards/malta.h b/include/asm-mips/mips-boards/malta.h
index 93bf4e51b8a4..c1891578fa65 100644
--- a/include/asm-mips/mips-boards/malta.h
+++ b/include/asm-mips/mips-boards/malta.h
@@ -52,6 +52,29 @@ static inline unsigned long get_msc_port_base(unsigned long reg)
}
/*
+ * GCMP Specific definitions
+ */
+#define GCMP_BASE_ADDR 0x1fbf8000
+#define GCMP_ADDRSPACE_SZ (256 * 1024)
+
+/*
+ * GIC Specific definitions
+ */
+#define GIC_BASE_ADDR 0x1bdc0000
+#define GIC_ADDRSPACE_SZ (128 * 1024)
+
+/*
+ * MSC01 BIU Specific definitions
+ * FIXME : These should be elsewhere ?
+ */
+#define MSC01_BIU_REG_BASE 0x1bc80000
+#define MSC01_BIU_ADDRSPACE_SZ (256 * 1024)
+#define MSC01_SC_CFG_OFS 0x0110
+#define MSC01_SC_CFG_GICPRES_MSK 0x00000004
+#define MSC01_SC_CFG_GICPRES_SHF 2
+#define MSC01_SC_CFG_GICENA_SHF 3
+
+/*
* Malta RTC-device indirect register access.
*/
#define MALTA_RTC_ADR_REG 0x70
diff --git a/include/asm-mips/mips-boards/maltaint.h b/include/asm-mips/mips-boards/maltaint.h
index 7461318f1cd1..cea872fc6f5c 100644
--- a/include/asm-mips/mips-boards/maltaint.h
+++ b/include/asm-mips/mips-boards/maltaint.h
@@ -39,7 +39,9 @@
#define MIPSCPU_INT_I8259A MIPSCPU_INT_MB0
#define MIPSCPU_INT_MB1 3
#define MIPSCPU_INT_SMI MIPSCPU_INT_MB1
+#define MIPSCPU_INT_IPI0 MIPSCPU_INT_MB1 /* GIC IPI */
#define MIPSCPU_INT_MB2 4
+#define MIPSCPU_INT_IPI1 MIPSCPU_INT_MB2 /* GIC IPI */
#define MIPSCPU_INT_MB3 5
#define MIPSCPU_INT_COREHI MIPSCPU_INT_MB3
#define MIPSCPU_INT_MB4 6
@@ -76,6 +78,31 @@
#define MSC01E_INT_PERFCTR 10
#define MSC01E_INT_CPUCTR 11
+/* GIC's Nomenclature for Core Interrupt Pins on the Malta */
+#define GIC_CPU_INT0 0 /* Core Interrupt 2 */
+#define GIC_CPU_INT1 1 /* . */
+#define GIC_CPU_INT2 2 /* . */
+#define GIC_CPU_INT3 3 /* . */
+#define GIC_CPU_INT4 4 /* . */
+#define GIC_CPU_INT5 5 /* Core Interrupt 5 */
+
+#define GIC_EXT_INTR(x) x
+
+/* Dummy data */
+#define X 0xdead
+
+/* External Interrupts used for IPI */
+#define GIC_IPI_EXT_INTR_RESCHED_VPE0 16
+#define GIC_IPI_EXT_INTR_CALLFNC_VPE0 17
+#define GIC_IPI_EXT_INTR_RESCHED_VPE1 18
+#define GIC_IPI_EXT_INTR_CALLFNC_VPE1 19
+#define GIC_IPI_EXT_INTR_RESCHED_VPE2 20
+#define GIC_IPI_EXT_INTR_CALLFNC_VPE2 21
+#define GIC_IPI_EXT_INTR_RESCHED_VPE3 22
+#define GIC_IPI_EXT_INTR_CALLFNC_VPE3 23
+
+#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8)
+
#ifndef __ASSEMBLY__
extern void maltaint_init(void);
#endif
diff --git a/include/asm-mips/mips-boards/maltasmp.h b/include/asm-mips/mips-boards/maltasmp.h
new file mode 100644
index 000000000000..8d7e955d506e
--- /dev/null
+++ b/include/asm-mips/mips-boards/maltasmp.h
@@ -0,0 +1,36 @@
+/*
+ * There are several SMP models supported
+ * SMTC is mutually exclusive to other options (atm)
+ */
+#if defined(CONFIG_MIPS_MT_SMTC)
+#define malta_smtc 1
+#define malta_cmp 0
+#define malta_smvp 0
+#else
+#define malta_smtc 0
+#if defined(CONFIG_MIPS_CMP)
+extern int gcmp_present;
+#define malta_cmp gcmp_present
+#else
+#define malta_cmp 0
+#endif
+/* FIXME: should become COMFIG_MIPS_MT_SMVP */
+#if defined(CONFIG_MIPS_MT_SMP)
+#define malta_smvp 1
+#else
+#define malta_smvp 0
+#endif
+#endif
+
+#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+
+/* malta_smtc */
+#include <asm/smtc.h>
+#include <asm/smtc_ipi.h>
+
+/* malta_cmp */
+#include <asm/cmp.h>
+
+/* malta_smvp */
+#include <asm/smvp.h>
diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h
index 5a2f8a3a6a1f..c9420aa97e32 100644
--- a/include/asm-mips/mipsmtregs.h
+++ b/include/asm-mips/mipsmtregs.h
@@ -197,8 +197,8 @@ static inline void __raw_evpe(void)
" .set pop \n");
}
-/* Enable multiMT if previous suggested it should be.
- EMT_ENABLE to force */
+/* Enable virtual processor execution if previous suggested it should be.
+ EVPE_ENABLE to force */
#define EVPE_ENABLE MVPCONTROL_EVP
@@ -238,8 +238,8 @@ static inline void __raw_emt(void)
" .set reorder");
}
-/* enable multiVPE if previous suggested it should be.
- EVPE_ENABLE to force */
+/* enable multi-threaded execution if previous suggested it should be.
+ EMT_ENABLE to force */
#define EMT_ENABLE VPECONTROL_TE
diff --git a/include/asm-mips/pgtable-32.h b/include/asm-mips/pgtable-32.h
index ceefe027c761..4396e9ffd418 100644
--- a/include/asm-mips/pgtable-32.h
+++ b/include/asm-mips/pgtable-32.h
@@ -107,7 +107,7 @@ static inline void pmd_clear(pmd_t *pmdp)
pmd_val(*pmdp) = ((unsigned long) invalid_pte_table);
}
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
#define pte_page(x) pfn_to_page(pte_pfn(x))
#define pte_pfn(x) ((unsigned long)((x).pte_high >> 6))
static inline pte_t
@@ -130,7 +130,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot)
#define pte_pfn(x) ((unsigned long)((x).pte >> PAGE_SHIFT))
#define pfn_pte(pfn, prot) __pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
#endif
-#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) */
+#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */
#define __pgd_offset(address) pgd_index(address)
#define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
diff --git a/include/asm-mips/pgtable-bits.h b/include/asm-mips/pgtable-bits.h
index 7494ba91112a..60e2f9338fcd 100644
--- a/include/asm-mips/pgtable-bits.h
+++ b/include/asm-mips/pgtable-bits.h
@@ -32,14 +32,14 @@
* unpredictable things. The code (when it is written) to deal with
* this problem will be in the update_mmu_cache() code for the r4k.
*/
-#if defined(CONFIG_CPU_MIPS32_R1) && defined(CONFIG_64BIT_PHYS_ADDR)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
#define _PAGE_PRESENT (1<<6) /* implemented in software */
#define _PAGE_READ (1<<7) /* implemented in software */
#define _PAGE_WRITE (1<<8) /* implemented in software */
#define _PAGE_ACCESSED (1<<9) /* implemented in software */
#define _PAGE_MODIFIED (1<<10) /* implemented in software */
-#define _PAGE_FILE (1<<10) /* set:pagecache unset:swap */
+#define _PAGE_FILE (1<<10) /* set:pagecache unset:swap */
#define _PAGE_R4KBUG (1<<0) /* workaround for r4k bug */
#define _PAGE_GLOBAL (1<<0)
@@ -47,15 +47,9 @@
#define _PAGE_SILENT_READ (1<<1) /* synonym */
#define _PAGE_DIRTY (1<<2) /* The MIPS dirty bit */
#define _PAGE_SILENT_WRITE (1<<2)
+#define _CACHE_SHIFT 3
#define _CACHE_MASK (7<<3)
-/* MIPS32 defines only values 2 and 3. The rest are implementation
- * dependent.
- */
-#define _CACHE_UNCACHED (2<<3)
-#define _CACHE_CACHABLE_NONCOHERENT (3<<3)
-#define _CACHE_CACHABLE_COW (3<<3) /* Au1x */
-
#else
#define _PAGE_PRESENT (1<<0) /* implemented in software */
@@ -74,75 +68,72 @@
#define _PAGE_SILENT_WRITE (1<<10)
#define _CACHE_UNCACHED (1<<11)
#define _CACHE_MASK (1<<11)
-#define _CACHE_CACHABLE_NONCOHERENT 0
#else
+
#define _PAGE_R4KBUG (1<<5) /* workaround for r4k bug */
#define _PAGE_GLOBAL (1<<6)
#define _PAGE_VALID (1<<7)
#define _PAGE_SILENT_READ (1<<7) /* synonym */
#define _PAGE_DIRTY (1<<8) /* The MIPS dirty bit */
#define _PAGE_SILENT_WRITE (1<<8)
+#define _CACHE_SHIFT 9
#define _CACHE_MASK (7<<9)
-#ifdef CONFIG_CPU_SB1
+#endif
+#endif /* defined(CONFIG_64BIT_PHYS_ADDR && defined(CONFIG_CPU_MIPS32) */
+
+
+/*
+ * Cache attributes
+ */
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+
+#define _CACHE_CACHABLE_NONCOHERENT 0
+
+#elif defined(CONFIG_CPU_SB1)
/* No penalty for being coherent on the SB1, so just
use it for "noncoherent" spaces, too. Shouldn't hurt. */
-#define _CACHE_UNCACHED (2<<9)
-#define _CACHE_CACHABLE_COW (5<<9)
-#define _CACHE_CACHABLE_NONCOHERENT (5<<9)
-#define _CACHE_UNCACHED_ACCELERATED (7<<9)
+#define _CACHE_UNCACHED (2<<_CACHE_SHIFT)
+#define _CACHE_CACHABLE_COW (5<<_CACHE_SHIFT)
+#define _CACHE_CACHABLE_NONCOHERENT (5<<_CACHE_SHIFT)
+#define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT)
#elif defined(CONFIG_CPU_RM9000)
-#define _CACHE_WT (0 << 9)
-#define _CACHE_WTWA (1 << 9)
-#define _CACHE_UC_B (2 << 9)
-#define _CACHE_WB (3 << 9)
-#define _CACHE_CWBEA (4 << 9)
-#define _CACHE_CWB (5 << 9)
-#define _CACHE_UCNB (6 << 9)
-#define _CACHE_FPC (7 << 9)
+#define _CACHE_WT (0<<_CACHE_SHIFT)
+#define _CACHE_WTWA (1<<_CACHE_SHIFT)
+#define _CACHE_UC_B (2<<_CACHE_SHIFT)
+#define _CACHE_WB (3<<_CACHE_SHIFT)
+#define _CACHE_CWBEA (4<<_CACHE_SHIFT)
+#define _CACHE_CWB (5<<_CACHE_SHIFT)
+#define _CACHE_UCNB (6<<_CACHE_SHIFT)
+#define _CACHE_FPC (7<<_CACHE_SHIFT)
-#define _CACHE_UNCACHED _CACHE_UC_B
-#define _CACHE_CACHABLE_NONCOHERENT _CACHE_WB
+#define _CACHE_UNCACHED _CACHE_UC_B
+#define _CACHE_CACHABLE_NONCOHERENT _CACHE_WB
#else
-#define _CACHE_CACHABLE_NO_WA (0<<9) /* R4600 only */
-#define _CACHE_CACHABLE_WA (1<<9) /* R4600 only */
-#define _CACHE_UNCACHED (2<<9) /* R4[0246]00 */
-#define _CACHE_CACHABLE_NONCOHERENT (3<<9) /* R4[0246]00 */
-#define _CACHE_CACHABLE_CE (4<<9) /* R4[04]00MC only */
-#define _CACHE_CACHABLE_COW (5<<9) /* R4[04]00MC only */
-#define _CACHE_CACHABLE_CUW (6<<9) /* R4[04]00MC only */
-#define _CACHE_UNCACHED_ACCELERATED (7<<9) /* R10000 only */
+#define _CACHE_CACHABLE_NO_WA (0<<_CACHE_SHIFT) /* R4600 only */
+#define _CACHE_CACHABLE_WA (1<<_CACHE_SHIFT) /* R4600 only */
+#define _CACHE_UNCACHED (2<<_CACHE_SHIFT) /* R4[0246]00 */
+#define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* R4[0246]00 */
+#define _CACHE_CACHABLE_CE (4<<_CACHE_SHIFT) /* R4[04]00MC only */
+#define _CACHE_CACHABLE_COW (5<<_CACHE_SHIFT) /* R4[04]00MC only */
+#define _CACHE_CACHABLE_COHERENT (5<<_CACHE_SHIFT) /* MIPS32R2 CMP */
+#define _CACHE_CACHABLE_CUW (6<<_CACHE_SHIFT) /* R4[04]00MC only */
+#define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT) /* R10000 only */
#endif
-#endif
-#endif /* defined(CONFIG_CPU_MIPS32_R1) && defined(CONFIG_64BIT_PHYS_ADDR) */
#define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
#define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK)
-#ifdef CONFIG_MIPS_UNCACHED
-#define PAGE_CACHABLE_DEFAULT _CACHE_UNCACHED
-#elif defined(CONFIG_DMA_NONCOHERENT)
-#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_NONCOHERENT
-#elif defined(CONFIG_CPU_RM9000)
-#define PAGE_CACHABLE_DEFAULT _CACHE_CWB
-#else
-#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_COW
-#endif
-
-#if defined(CONFIG_CPU_MIPS32_R1) && defined(CONFIG_64BIT_PHYS_ADDR)
-#define CONF_CM_DEFAULT (PAGE_CACHABLE_DEFAULT >> 3)
-#else
-#define CONF_CM_DEFAULT (PAGE_CACHABLE_DEFAULT >> 9)
-#endif
+#define CONF_CM_DEFAULT (PAGE_CACHABLE_DEFAULT>>_CACHE_SHIFT)
#endif /* _ASM_PGTABLE_BITS_H */
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 17a7703a2969..2f597eea4448 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -23,15 +23,15 @@ struct vm_area_struct;
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
- PAGE_CACHABLE_DEFAULT)
+ _page_cachable_default)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | \
- PAGE_CACHABLE_DEFAULT)
+ _page_cachable_default)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | \
- PAGE_CACHABLE_DEFAULT)
+ _page_cachable_default)
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
- _PAGE_GLOBAL | PAGE_CACHABLE_DEFAULT)
+ _PAGE_GLOBAL | _page_cachable_default)
#define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
- PAGE_CACHABLE_DEFAULT)
+ _page_cachable_default)
#define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \
__WRITEABLE | _PAGE_GLOBAL | _CACHE_UNCACHED)
@@ -40,23 +40,30 @@ struct vm_area_struct;
* read. Also, write permissions imply read permissions. This is the closest
* we can get by reasonable means..
*/
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED
+
+/*
+ * Dummy values to fill the table in mmap.c
+ * The real values will be generated at runtime
+ */
+#define __P000 __pgprot(0)
+#define __P001 __pgprot(0)
+#define __P010 __pgprot(0)
+#define __P011 __pgprot(0)
+#define __P100 __pgprot(0)
+#define __P101 __pgprot(0)
+#define __P110 __pgprot(0)
+#define __P111 __pgprot(0)
+
+#define __S000 __pgprot(0)
+#define __S001 __pgprot(0)
+#define __S010 __pgprot(0)
+#define __S011 __pgprot(0)
+#define __S100 __pgprot(0)
+#define __S101 __pgprot(0)
+#define __S110 __pgprot(0)
+#define __S111 __pgprot(0)
+
+extern unsigned long _page_cachable_default;
/*
* ZERO_PAGE is a global shared page that is always zero; used
@@ -79,7 +86,7 @@ extern void paging_init(void);
#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
#define pmd_page_vaddr(pmd) pmd_val(pmd)
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
#define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL))
#define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT)
@@ -182,7 +189,7 @@ extern pgd_t swapper_pg_dir[];
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
static inline int pte_write(pte_t pte) { return pte.pte_low & _PAGE_WRITE; }
static inline int pte_dirty(pte_t pte) { return pte.pte_low & _PAGE_MODIFIED; }
static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; }
@@ -285,6 +292,8 @@ static inline pte_t pte_mkyoung(pte_t pte)
return pte;
}
#endif
+static inline int pte_special(pte_t pte) { return 0; }
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/*
* Macro to make mark a page protection value as "uncacheable". Note
@@ -309,7 +318,7 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
*/
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
-#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
pte.pte_low &= _PAGE_CHG_MASK;
diff --git a/include/asm-mips/r4k-timer.h b/include/asm-mips/r4k-timer.h
new file mode 100644
index 000000000000..a37d12b3b61c
--- /dev/null
+++ b/include/asm-mips/r4k-timer.h
@@ -0,0 +1,30 @@
+/*
+ * 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) 2008 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#ifndef __ASM_R4K_TYPES_H
+#define __ASM_R4K_TYPES_H
+
+#include <linux/compiler.h>
+
+#ifdef CONFIG_SYNC_R4K
+
+extern void synchronise_count_master(void);
+extern void synchronise_count_slave(void);
+
+#else
+
+static inline void synchronise_count_master(void)
+{
+}
+
+static inline void synchronise_count_slave(void)
+{
+}
+
+#endif
+
+#endif /* __ASM_R4K_TYPES_H */
diff --git a/include/asm-mips/smp-ops.h b/include/asm-mips/smp-ops.h
index b17fdfb5d818..43c207e72a63 100644
--- a/include/asm-mips/smp-ops.h
+++ b/include/asm-mips/smp-ops.h
@@ -51,6 +51,7 @@ static inline void register_smp_ops(struct plat_smp_ops *ops)
#endif /* !CONFIG_SMP */
extern struct plat_smp_ops up_smp_ops;
+extern struct plat_smp_ops cmp_smp_ops;
extern struct plat_smp_ops vsmp_smp_ops;
#endif /* __ASM_SMP_OPS_H */
diff --git a/include/asm-mips/smtc.h b/include/asm-mips/smtc.h
index ff3e8936b493..3639b28f80db 100644
--- a/include/asm-mips/smtc.h
+++ b/include/asm-mips/smtc.h
@@ -44,6 +44,7 @@ extern int mipsmt_build_cpu_map(int startslot);
extern void mipsmt_prepare_cpus(void);
extern void smtc_smp_finish(void);
extern void smtc_boot_secondary(int cpu, struct task_struct *t);
+extern void smtc_cpus_done(void);
/*
* Sharing the TLB between multiple VPEs means that the
diff --git a/include/asm-mips/smvp.h b/include/asm-mips/smvp.h
new file mode 100644
index 000000000000..0d0e80a39e8a
--- /dev/null
+++ b/include/asm-mips/smvp.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_SMVP_H
+#define _ASM_SMVP_H
+
+/*
+ * Definitions for SMVP multitasking on MIPS MT cores
+ */
+struct task_struct;
+
+extern void smvp_smp_setup(void);
+extern void smvp_smp_finish(void);
+extern void smvp_boot_secondary(int cpu, struct task_struct *t);
+extern void smvp_init_secondary(void);
+extern void smvp_smp_finish(void);
+extern void smvp_cpus_done(void);
+extern void smvp_prepare_cpus(unsigned int max_cpus);
+
+/* This is platform specific */
+extern void smvp_send_ipi(int cpu, unsigned int action);
+#endif /* _ASM_SMVP_H */
diff --git a/include/asm-mips/traps.h b/include/asm-mips/traps.h
index d02e019b0127..e5dbde625ec2 100644
--- a/include/asm-mips/traps.h
+++ b/include/asm-mips/traps.h
@@ -23,5 +23,7 @@ extern int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
extern void (*board_nmi_handler_setup)(void);
extern void (*board_ejtag_handler_setup)(void);
+extern void (*board_bind_eic_interrupt)(int irq, int regset);
+extern void (*board_watchpoint_handler)(struct pt_regs *regs);
#endif /* _ASM_TRAPS_H */
diff --git a/include/asm-mips/tx4938/rbtx4938.h b/include/asm-mips/tx4938/rbtx4938.h
index b180488dcdc4..dfed7beb533f 100644
--- a/include/asm-mips/tx4938/rbtx4938.h
+++ b/include/asm-mips/tx4938/rbtx4938.h
@@ -67,44 +67,26 @@
#define RBTX4938_INTF_MODEM (1 << RBTX4938_INTB_MODEM)
#define RBTX4938_INTF_SWINT (1 << RBTX4938_INTB_SWINT)
-#define rbtx4938_fpga_rev_ptr \
- ((volatile unsigned char *)RBTX4938_FPGA_REV_ADDR)
-#define rbtx4938_led_ptr \
- ((volatile unsigned char *)RBTX4938_LED_ADDR)
-#define rbtx4938_dipsw_ptr \
- ((volatile unsigned char *)RBTX4938_DIPSW_ADDR)
-#define rbtx4938_bdipsw_ptr \
- ((volatile unsigned char *)RBTX4938_BDIPSW_ADDR)
-#define rbtx4938_imask_ptr \
- ((volatile unsigned char *)RBTX4938_IMASK_ADDR)
-#define rbtx4938_imask2_ptr \
- ((volatile unsigned char *)RBTX4938_IMASK2_ADDR)
-#define rbtx4938_intpol_ptr \
- ((volatile unsigned char *)RBTX4938_INTPOL_ADDR)
-#define rbtx4938_istat_ptr \
- ((volatile unsigned char *)RBTX4938_ISTAT_ADDR)
-#define rbtx4938_istat2_ptr \
- ((volatile unsigned char *)RBTX4938_ISTAT2_ADDR)
-#define rbtx4938_imstat_ptr \
- ((volatile unsigned char *)RBTX4938_IMSTAT_ADDR)
-#define rbtx4938_imstat2_ptr \
- ((volatile unsigned char *)RBTX4938_IMSTAT2_ADDR)
-#define rbtx4938_softint_ptr \
- ((volatile unsigned char *)RBTX4938_SOFTINT_ADDR)
-#define rbtx4938_piosel_ptr \
- ((volatile unsigned char *)RBTX4938_PIOSEL_ADDR)
-#define rbtx4938_spics_ptr \
- ((volatile unsigned char *)RBTX4938_SPICS_ADDR)
-#define rbtx4938_sfpwr_ptr \
- ((volatile unsigned char *)RBTX4938_SFPWR_ADDR)
-#define rbtx4938_sfvol_ptr \
- ((volatile unsigned char *)RBTX4938_SFVOL_ADDR)
-#define rbtx4938_softreset_ptr \
- ((volatile unsigned char *)RBTX4938_SOFTRESET_ADDR)
-#define rbtx4938_softresetlock_ptr \
- ((volatile unsigned char *)RBTX4938_SOFTRESETLOCK_ADDR)
-#define rbtx4938_pcireset_ptr \
- ((volatile unsigned char *)RBTX4938_PCIRESET_ADDR)
+#define rbtx4938_fpga_rev_addr ((__u8 __iomem *)RBTX4938_FPGA_REV_ADDR)
+#define rbtx4938_led_addr ((__u8 __iomem *)RBTX4938_LED_ADDR)
+#define rbtx4938_dipsw_addr ((__u8 __iomem *)RBTX4938_DIPSW_ADDR)
+#define rbtx4938_bdipsw_addr ((__u8 __iomem *)RBTX4938_BDIPSW_ADDR)
+#define rbtx4938_imask_addr ((__u8 __iomem *)RBTX4938_IMASK_ADDR)
+#define rbtx4938_imask2_addr ((__u8 __iomem *)RBTX4938_IMASK2_ADDR)
+#define rbtx4938_intpol_addr ((__u8 __iomem *)RBTX4938_INTPOL_ADDR)
+#define rbtx4938_istat_addr ((__u8 __iomem *)RBTX4938_ISTAT_ADDR)
+#define rbtx4938_istat2_addr ((__u8 __iomem *)RBTX4938_ISTAT2_ADDR)
+#define rbtx4938_imstat_addr ((__u8 __iomem *)RBTX4938_IMSTAT_ADDR)
+#define rbtx4938_imstat2_addr ((__u8 __iomem *)RBTX4938_IMSTAT2_ADDR)
+#define rbtx4938_softint_addr ((__u8 __iomem *)RBTX4938_SOFTINT_ADDR)
+#define rbtx4938_piosel_addr ((__u8 __iomem *)RBTX4938_PIOSEL_ADDR)
+#define rbtx4938_spics_addr ((__u8 __iomem *)RBTX4938_SPICS_ADDR)
+#define rbtx4938_sfpwr_addr ((__u8 __iomem *)RBTX4938_SFPWR_ADDR)
+#define rbtx4938_sfvol_addr ((__u8 __iomem *)RBTX4938_SFVOL_ADDR)
+#define rbtx4938_softreset_addr ((__u8 __iomem *)RBTX4938_SOFTRESET_ADDR)
+#define rbtx4938_softresetlock_addr \
+ ((__u8 __iomem *)RBTX4938_SOFTRESETLOCK_ADDR)
+#define rbtx4938_pcireset_addr ((__u8 __iomem *)RBTX4938_PCIRESET_ADDR)
/*
* IRQ mappings
diff --git a/include/asm-mips/tx4938/tx4938.h b/include/asm-mips/tx4938/tx4938.h
index f7c448b90578..e8807f5c61e9 100644
--- a/include/asm-mips/tx4938/tx4938.h
+++ b/include/asm-mips/tx4938/tx4938.h
@@ -13,8 +13,6 @@
#ifndef __ASM_TX_BOARDS_TX4938_H
#define __ASM_TX_BOARDS_TX4938_H
-#include <asm/tx4938/tx4938_mips.h>
-
#define tx4938_read_nfmc(addr) (*(volatile unsigned int *)(addr))
#define tx4938_write_nfmc(b, addr) (*(volatile unsigned int *)(addr)) = (b)
@@ -54,28 +52,6 @@
#define TX4938_ACLC_REG (TX4938_REG_BASE + 0xf700)
#define TX4938_SPI_REG (TX4938_REG_BASE + 0xf800)
-#ifndef _LANGUAGE_ASSEMBLY
-#include <asm/byteorder.h>
-
-#define TX4938_MKA(x) ((u32)( ((u32)(TX4938_REG_BASE)) | ((u32)(x)) ))
-
-#define TX4938_RD08( reg ) (*(vu08*)(reg))
-#define TX4938_WR08( reg, val ) ((*(vu08*)(reg))=(val))
-
-#define TX4938_RD16( reg ) (*(vu16*)(reg))
-#define TX4938_WR16( reg, val ) ((*(vu16*)(reg))=(val))
-
-#define TX4938_RD32( reg ) (*(vu32*)(reg))
-#define TX4938_WR32( reg, val ) ((*(vu32*)(reg))=(val))
-
-#define TX4938_RD64( reg ) (*(vu64*)(reg))
-#define TX4938_WR64( reg, val ) ((*(vu64*)(reg))=(val))
-
-#define TX4938_RD( reg ) TX4938_RD32( reg )
-#define TX4938_WR( reg, val ) TX4938_WR32( reg, val )
-
-#endif /* !__ASSEMBLY__ */
-
#ifdef __ASSEMBLY__
#define _CONST64(c) c
#else
@@ -261,18 +237,6 @@ struct tx4938_sio_reg {
volatile unsigned long rfifo;
};
-struct tx4938_pio_reg {
- volatile unsigned long dout;
- volatile unsigned long din;
- volatile unsigned long dir;
- volatile unsigned long od;
- volatile unsigned long flag[2];
- volatile unsigned long pol;
- volatile unsigned long intc;
- volatile unsigned long maskcpu;
- volatile unsigned long maskext;
-};
-
struct tx4938_ndfmc_reg {
endian_def_l2(unused0, dtr);
endian_def_l2(unused1, mcr);
@@ -642,7 +606,7 @@ struct tx4938_ccfg_reg {
#define tx4938_pcic1ptr ((struct tx4938_pcic_reg *)TX4938_PCIC1_REG)
#define tx4938_ccfgptr ((struct tx4938_ccfg_reg *)TX4938_CCFG_REG)
#define tx4938_sioptr(ch) ((struct tx4938_sio_reg *)TX4938_SIO_REG(ch))
-#define tx4938_pioptr ((struct tx4938_pio_reg *)TX4938_PIO_REG)
+#define tx4938_pioptr ((struct txx9_pio_reg __iomem *)TX4938_PIO_REG)
#define tx4938_aclcptr ((struct tx4938_aclc_reg *)TX4938_ACLC_REG)
#define tx4938_spiptr ((struct tx4938_spi_reg *)TX4938_SPI_REG)
#define tx4938_sramcptr ((struct tx4938_sramc_reg *)TX4938_SRAMC_REG)
diff --git a/include/asm-mips/tx4938/tx4938_mips.h b/include/asm-mips/tx4938/tx4938_mips.h
deleted file mode 100644
index f346ff58b947..000000000000
--- a/include/asm-mips/tx4938/tx4938_mips.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * linux/include/asm-mips/tx4938/tx4938_mips.h
- * Generic bitmask definitions
- *
- * 2003-2005 (c) MontaVista Software, Inc. 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.
- *
- * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
- */
-
-#ifndef TX4938_TX4938_MIPS_H
-#define TX4938_TX4938_MIPS_H
-#ifndef __ASSEMBLY__
-
-#define reg_rd08(r) ((u8 )(*((vu8 *)(r))))
-#define reg_rd16(r) ((u16)(*((vu16*)(r))))
-#define reg_rd32(r) ((u32)(*((vu32*)(r))))
-#define reg_rd64(r) ((u64)(*((vu64*)(r))))
-
-#define reg_wr08(r, v) ((*((vu8 *)(r)))=((u8 )(v)))
-#define reg_wr16(r, v) ((*((vu16*)(r)))=((u16)(v)))
-#define reg_wr32(r, v) ((*((vu32*)(r)))=((u32)(v)))
-#define reg_wr64(r, v) ((*((vu64*)(r)))=((u64)(v)))
-
-typedef volatile __signed char vs8;
-typedef volatile unsigned char vu8;
-
-typedef volatile __signed short vs16;
-typedef volatile unsigned short vu16;
-
-typedef volatile __signed int vs32;
-typedef volatile unsigned int vu32;
-
-typedef s8 s08;
-typedef vs8 vs08;
-
-typedef u8 u08;
-typedef vu8 vu08;
-
-#if (_MIPS_SZLONG == 64)
-
-typedef volatile __signed__ long vs64;
-typedef volatile unsigned long vu64;
-
-#else
-
-typedef volatile __signed__ long long vs64;
-typedef volatile unsigned long long vu64;
-
-#endif
-#endif
-#endif
diff --git a/include/asm-mips/txx9pio.h b/include/asm-mips/txx9pio.h
new file mode 100644
index 000000000000..3d6fa9f8d513
--- /dev/null
+++ b/include/asm-mips/txx9pio.h
@@ -0,0 +1,29 @@
+/*
+ * include/asm-mips/txx9pio.h
+ * TX39/TX49 PIO controller definitions.
+ *
+ * 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.
+ */
+#ifndef __ASM_TXX9PIO_H
+#define __ASM_TXX9PIO_H
+
+#include <linux/types.h>
+
+struct txx9_pio_reg {
+ __u32 dout;
+ __u32 din;
+ __u32 dir;
+ __u32 od;
+ __u32 flag[2];
+ __u32 pol;
+ __u32 intc;
+ __u32 maskcpu;
+ __u32 maskext;
+};
+
+int txx9_gpio_init(unsigned long baseaddr,
+ unsigned int base, unsigned int num);
+
+#endif /* __ASM_TXX9PIO_H */
diff --git a/include/asm-mips/vr41xx/siu.h b/include/asm-mips/vr41xx/siu.h
index 98cdb4096485..da9f6e373409 100644
--- a/include/asm-mips/vr41xx/siu.h
+++ b/include/asm-mips/vr41xx/siu.h
@@ -1,7 +1,7 @@
/*
* Include file for NEC VR4100 series Serial Interface Unit.
*
- * Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2005-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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
@@ -49,4 +49,10 @@ typedef enum {
extern void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed);
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+extern void vr41xx_siu_early_setup(struct uart_port *port);
+#else
+static inline void vr41xx_siu_early_setup(struct uart_port *port) {}
+#endif
+
#endif /* __NEC_VR41XX_SIU_H */
diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h
index 88b492f6ea9c..22be64971cc6 100644
--- a/include/asm-mips/vr41xx/vr41xx.h
+++ b/include/asm-mips/vr41xx/vr41xx.h
@@ -7,7 +7,7 @@
* Copyright (C) 2001, 2002 Paul Mundt
* Copyright (C) 2002 MontaVista Software, Inc.
* Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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
@@ -143,4 +143,10 @@ extern void vr41xx_disable_csiint(uint16_t mask);
extern void vr41xx_enable_bcuint(void);
extern void vr41xx_disable_bcuint(void);
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
+extern void vr41xx_siu_setup(void);
+#else
+static inline void vr41xx_siu_setup(void) {}
+#endif
+
#endif /* __NEC_VR41XX_H */
diff --git a/include/asm-mn10300/pgtable.h b/include/asm-mn10300/pgtable.h
index 375c4941deda..6dc30fc827c4 100644
--- a/include/asm-mn10300/pgtable.h
+++ b/include/asm-mn10300/pgtable.h
@@ -224,6 +224,7 @@ static inline int pte_read(pte_t pte) { return pte_val(pte) & __PAGE_PROT_USER;
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & __PAGE_PROT_WRITE; }
+static inline int pte_special(pte_t pte){ return 0; }
/*
* The following only works if pte_present() is not true.
@@ -265,6 +266,8 @@ static inline pte_t pte_mkwrite(pte_t pte)
return pte;
}
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
+
#define pte_ERROR(e) \
printk(KERN_ERR "%s:%d: bad pte %08lx.\n", \
__FILE__, __LINE__, pte_val(e))
diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h
index f8eebcbad01f..7a6ea10bd231 100644
--- a/include/asm-parisc/bitops.h
+++ b/include/asm-parisc/bitops.h
@@ -210,6 +210,7 @@ static __inline__ int fls(int x)
return ret;
}
+#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index dc86adbec916..470a4b88124d 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -323,6 +323,7 @@ static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
@@ -330,6 +331,7 @@ static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_WRITE; ret
static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/*
* Conversion functions: convert a page and protection to a page entry,
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index a99a74929475..897eade3afbe 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -313,6 +313,11 @@ static __inline__ int fls(unsigned int x)
return 32 - lz;
}
+static __inline__ unsigned long __fls(unsigned long x)
+{
+ return __ilog2(x);
+}
+
/*
* 64-bit can do this using one cntlzd (count leading zeroes doubleword)
* instruction; for 32-bit we use the generic version, which does two
diff --git a/include/asm-powerpc/fixmap.h b/include/asm-powerpc/fixmap.h
new file mode 100644
index 000000000000..8428b38a3d30
--- /dev/null
+++ b/include/asm-powerpc/fixmap.h
@@ -0,0 +1,106 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * 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) 1998 Ingo Molnar
+ *
+ * Copyright 2008 Freescale Semiconductor Inc.
+ * Port to powerpc added by Kumar Gala
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+extern unsigned long FIXADDR_TOP;
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+#include <asm/page.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+enum fixed_addresses {
+ FIX_HOLE,
+#ifdef CONFIG_HIGHMEM
+ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+#endif
+ /* FIX_PCIE_MCFG, */
+ __end_of_fixed_addresses
+};
+
+extern void __set_fixmap (enum fixed_addresses idx,
+ phys_addr_t phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+
+#define clear_fixmap(idx) \
+ __set_fixmap(idx, 0, __pgprot(0))
+
+#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
+
+#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+ /*
+ * this branch gets completely eliminated after inlining,
+ * except when someone tries to use fixaddr indices in an
+ * illegal way. (such as mixing up address types or using
+ * out-of-range indices).
+ *
+ * If it doesn't get removed, the linker will complain
+ * loudly with a reasonably clear error message..
+ */
+ if (idx >= __end_of_fixed_addresses)
+ __this_fixmap_does_not_exist();
+
+ return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+ BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+ return __virt_to_fix(vaddr);
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif
diff --git a/include/asm-powerpc/highmem.h b/include/asm-powerpc/highmem.h
index f7b21ee302b4..5d99b6489d56 100644
--- a/include/asm-powerpc/highmem.h
+++ b/include/asm-powerpc/highmem.h
@@ -27,9 +27,7 @@
#include <asm/kmap_types.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
-
-/* undef for production */
-#define HIGHMEM_DEBUG 1
+#include <asm/fixmap.h>
extern pte_t *kmap_pte;
extern pgprot_t kmap_prot;
@@ -40,14 +38,12 @@ extern pte_t *pkmap_page_table;
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
*/
-#define PKMAP_BASE CONFIG_HIGHMEM_START
#define LAST_PKMAP (1 << PTE_SHIFT)
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
+#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-#define KMAP_FIX_BEGIN (PKMAP_BASE + 0x00400000UL)
-
extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
@@ -73,7 +69,7 @@ static inline void kunmap(struct page *page)
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
{
unsigned int idx;
unsigned long vaddr;
@@ -84,34 +80,39 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
- vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE;
-#ifdef HIGHMEM_DEBUG
- BUG_ON(!pte_none(*(kmap_pte+idx)));
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+ BUG_ON(!pte_none(*(kmap_pte-idx)));
#endif
- set_pte_at(&init_mm, vaddr, kmap_pte+idx, mk_pte(page, kmap_prot));
+ set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
flush_tlb_page(NULL, vaddr);
return (void*) vaddr;
}
+static inline void *kmap_atomic(struct page *page, enum km_type type)
+{
+ return kmap_atomic_prot(page, type, kmap_prot);
+}
+
static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
-#ifdef HIGHMEM_DEBUG
+#ifdef CONFIG_DEBUG_HIGHMEM
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
- unsigned int idx = type + KM_TYPE_NR*smp_processor_id();
+ enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
- if (vaddr < KMAP_FIX_BEGIN) { // FIXME
+ if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
pagefault_enable();
return;
}
- BUG_ON(vaddr != KMAP_FIX_BEGIN + idx * PAGE_SIZE);
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
/*
* force other mappings to Oops if they'll try to access
* this pte without first remap it
*/
- pte_clear(&init_mm, vaddr, kmap_pte+idx);
+ pte_clear(&init_mm, vaddr, kmap_pte-idx);
flush_tlb_page(NULL, vaddr);
#endif
pagefault_enable();
@@ -120,12 +121,14 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type)
static inline struct page *kmap_atomic_to_page(void *ptr)
{
unsigned long idx, vaddr = (unsigned long) ptr;
+ pte_t *pte;
- if (vaddr < KMAP_FIX_BEGIN)
+ if (vaddr < FIXADDR_START)
return virt_to_page(ptr);
- idx = (vaddr - KMAP_FIX_BEGIN) >> PAGE_SHIFT;
- return pte_page(kmap_pte[idx]);
+ idx = virt_to_fix(vaddr);
+ pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+ return pte_page(*pte);
}
#define flush_cache_kmaps() flush_cache_all()
diff --git a/include/asm-powerpc/hugetlb.h b/include/asm-powerpc/hugetlb.h
new file mode 100644
index 000000000000..649c6c3b87b3
--- /dev/null
+++ b/include/asm-powerpc/hugetlb.h
@@ -0,0 +1,79 @@
+#ifndef _ASM_POWERPC_HUGETLB_H
+#define _ASM_POWERPC_HUGETLB_H
+
+#include <asm/page.h>
+
+
+int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
+ unsigned long len);
+
+void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
+ unsigned long end, unsigned long floor,
+ unsigned long ceiling);
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
+{
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+ return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+#endif /* _ASM_POWERPC_HUGETLB_H */
diff --git a/include/asm-powerpc/io-defs.h b/include/asm-powerpc/io-defs.h
index 03691ab69217..44d7927aec69 100644
--- a/include/asm-powerpc/io-defs.h
+++ b/include/asm-powerpc/io-defs.h
@@ -1,59 +1,60 @@
/* This file is meant to be include multiple times by other headers */
+/* last 2 argments are used by platforms/cell/io-workarounds.[ch] */
-DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_RET(readb, u8, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_RET(readw, u16, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_RET(readl, u32, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_RET(readw_be, u16, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_RET(readl_be, u32, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_NORET(writeb, (u8 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
+DEF_PCI_AC_NORET(writew, (u16 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
+DEF_PCI_AC_NORET(writel, (u32 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
+DEF_PCI_AC_NORET(writew_be, (u16 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
+DEF_PCI_AC_NORET(writel_be, (u32 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
#ifdef __powerpc64__
-DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr))
-DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr))
-DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr))
+DEF_PCI_AC_RET(readq, u64, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_RET(readq_be, u64, (const PCI_IO_ADDR addr), (addr), mem, addr)
+DEF_PCI_AC_NORET(writeq, (u64 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
+DEF_PCI_AC_NORET(writeq_be, (u64 val, PCI_IO_ADDR addr), (val, addr), mem, addr)
#endif /* __powerpc64__ */
-DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port))
-DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port))
-DEF_PCI_AC_RET(inl, u32, (unsigned long port), (port))
-DEF_PCI_AC_NORET(outb, (u8 val, unsigned long port), (val, port))
-DEF_PCI_AC_NORET(outw, (u16 val, unsigned long port), (val, port))
-DEF_PCI_AC_NORET(outl, (u32 val, unsigned long port), (val, port))
+DEF_PCI_AC_RET(inb, u8, (unsigned long port), (port), pio, port)
+DEF_PCI_AC_RET(inw, u16, (unsigned long port), (port), pio, port)
+DEF_PCI_AC_RET(inl, u32, (unsigned long port), (port), pio, port)
+DEF_PCI_AC_NORET(outb, (u8 val, unsigned long port), (val, port), pio, port)
+DEF_PCI_AC_NORET(outw, (u16 val, unsigned long port), (val, port), pio, port)
+DEF_PCI_AC_NORET(outl, (u32 val, unsigned long port), (val, port), pio, port)
-DEF_PCI_AC_NORET(readsb, (const PCI_IO_ADDR a, void *b, unsigned long c), \
- (a, b, c))
-DEF_PCI_AC_NORET(readsw, (const PCI_IO_ADDR a, void *b, unsigned long c), \
- (a, b, c))
-DEF_PCI_AC_NORET(readsl, (const PCI_IO_ADDR a, void *b, unsigned long c), \
- (a, b, c))
-DEF_PCI_AC_NORET(writesb, (PCI_IO_ADDR a, const void *b, unsigned long c), \
- (a, b, c))
-DEF_PCI_AC_NORET(writesw, (PCI_IO_ADDR a, const void *b, unsigned long c), \
- (a, b, c))
-DEF_PCI_AC_NORET(writesl, (PCI_IO_ADDR a, const void *b, unsigned long c), \
- (a, b, c))
+DEF_PCI_AC_NORET(readsb, (const PCI_IO_ADDR a, void *b, unsigned long c),
+ (a, b, c), mem, a)
+DEF_PCI_AC_NORET(readsw, (const PCI_IO_ADDR a, void *b, unsigned long c),
+ (a, b, c), mem, a)
+DEF_PCI_AC_NORET(readsl, (const PCI_IO_ADDR a, void *b, unsigned long c),
+ (a, b, c), mem, a)
+DEF_PCI_AC_NORET(writesb, (PCI_IO_ADDR a, const void *b, unsigned long c),
+ (a, b, c), mem, a)
+DEF_PCI_AC_NORET(writesw, (PCI_IO_ADDR a, const void *b, unsigned long c),
+ (a, b, c), mem, a)
+DEF_PCI_AC_NORET(writesl, (PCI_IO_ADDR a, const void *b, unsigned long c),
+ (a, b, c), mem, a)
-DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c), \
- (p, b, c))
-DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c), \
- (p, b, c))
-DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c), \
- (p, b, c))
-DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c), \
- (p, b, c))
-DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c), \
- (p, b, c))
-DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c), \
- (p, b, c))
+DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c),
+ (p, b, c), pio, p)
+DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c),
+ (p, b, c), pio, p)
+DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c),
+ (p, b, c), pio, p)
+DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c),
+ (p, b, c), pio, p)
+DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c),
+ (p, b, c), pio, p)
+DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c),
+ (p, b, c), pio, p)
-DEF_PCI_AC_NORET(memset_io, (PCI_IO_ADDR a, int c, unsigned long n), \
- (a, c, n))
-DEF_PCI_AC_NORET(memcpy_fromio,(void *d,const PCI_IO_ADDR s,unsigned long n), \
- (d, s, n))
-DEF_PCI_AC_NORET(memcpy_toio,(PCI_IO_ADDR d,const void *s,unsigned long n), \
- (d, s, n))
+DEF_PCI_AC_NORET(memset_io, (PCI_IO_ADDR a, int c, unsigned long n),
+ (a, c, n), mem, a)
+DEF_PCI_AC_NORET(memcpy_fromio, (void *d, const PCI_IO_ADDR s, unsigned long n),
+ (d, s, n), mem, s)
+DEF_PCI_AC_NORET(memcpy_toio, (PCI_IO_ADDR d, const void *s, unsigned long n),
+ (d, s, n), mem, d)
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 7be26f615755..afae0697e8ce 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -458,8 +458,8 @@ __do_out_asm(_rec_outl, "stwbrx")
/* Structure containing all the hooks */
extern struct ppc_pci_io {
-#define DEF_PCI_AC_RET(name, ret, at, al) ret (*name) at;
-#define DEF_PCI_AC_NORET(name, at, al) void (*name) at;
+#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) ret (*name) at;
+#define DEF_PCI_AC_NORET(name, at, al, space, aa) void (*name) at;
#include <asm/io-defs.h>
@@ -469,7 +469,7 @@ extern struct ppc_pci_io {
} ppc_pci_io;
/* The inline wrappers */
-#define DEF_PCI_AC_RET(name, ret, at, al) \
+#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
static inline ret name at \
{ \
if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \
@@ -477,7 +477,7 @@ static inline ret name at \
return __do_##name al; \
}
-#define DEF_PCI_AC_NORET(name, at, al) \
+#define DEF_PCI_AC_NORET(name, at, al, space, aa) \
static inline void name at \
{ \
if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \
diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h
index 10e8eb1e6f4f..f6c93c716898 100644
--- a/include/asm-powerpc/kdump.h
+++ b/include/asm-powerpc/kdump.h
@@ -11,16 +11,11 @@
#ifdef CONFIG_CRASH_DUMP
-#define PHYSICAL_START KDUMP_KERNELBASE
#define KDUMP_TRAMPOLINE_START 0x0100
#define KDUMP_TRAMPOLINE_END 0x3000
#define KDUMP_MIN_TCE_ENTRIES 2048
-#else /* !CONFIG_CRASH_DUMP */
-
-#define PHYSICAL_START 0x0
-
#endif /* CONFIG_CRASH_DUMP */
#ifndef __ASSEMBLY__
diff --git a/include/asm-powerpc/kvm.h b/include/asm-powerpc/kvm.h
index d1b530fbf8dd..f993e4198d5c 100644
--- a/include/asm-powerpc/kvm.h
+++ b/include/asm-powerpc/kvm.h
@@ -1,6 +1,55 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
#ifndef __LINUX_KVM_POWERPC_H
#define __LINUX_KVM_POWERPC_H
-/* powerpc does not support KVM */
+#include <asm/types.h>
+
+struct kvm_regs {
+ __u64 pc;
+ __u64 cr;
+ __u64 ctr;
+ __u64 lr;
+ __u64 xer;
+ __u64 msr;
+ __u64 srr0;
+ __u64 srr1;
+ __u64 pid;
+
+ __u64 sprg0;
+ __u64 sprg1;
+ __u64 sprg2;
+ __u64 sprg3;
+ __u64 sprg4;
+ __u64 sprg5;
+ __u64 sprg6;
+ __u64 sprg7;
+
+ __u64 gpr[32];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+ __u64 fpr[32];
+};
-#endif
+#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/include/asm-powerpc/kvm_asm.h b/include/asm-powerpc/kvm_asm.h
new file mode 100644
index 000000000000..2197764796d9
--- /dev/null
+++ b/include/asm-powerpc/kvm_asm.h
@@ -0,0 +1,55 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_ASM_H__
+#define __POWERPC_KVM_ASM_H__
+
+/* IVPR must be 64KiB-aligned. */
+#define VCPU_SIZE_ORDER 4
+#define VCPU_SIZE_LOG (VCPU_SIZE_ORDER + 12)
+#define VCPU_TLB_PGSZ PPC44x_TLB_64K
+#define VCPU_SIZE_BYTES (1<<VCPU_SIZE_LOG)
+
+#define BOOKE_INTERRUPT_CRITICAL 0
+#define BOOKE_INTERRUPT_MACHINE_CHECK 1
+#define BOOKE_INTERRUPT_DATA_STORAGE 2
+#define BOOKE_INTERRUPT_INST_STORAGE 3
+#define BOOKE_INTERRUPT_EXTERNAL 4
+#define BOOKE_INTERRUPT_ALIGNMENT 5
+#define BOOKE_INTERRUPT_PROGRAM 6
+#define BOOKE_INTERRUPT_FP_UNAVAIL 7
+#define BOOKE_INTERRUPT_SYSCALL 8
+#define BOOKE_INTERRUPT_AP_UNAVAIL 9
+#define BOOKE_INTERRUPT_DECREMENTER 10
+#define BOOKE_INTERRUPT_FIT 11
+#define BOOKE_INTERRUPT_WATCHDOG 12
+#define BOOKE_INTERRUPT_DTLB_MISS 13
+#define BOOKE_INTERRUPT_ITLB_MISS 14
+#define BOOKE_INTERRUPT_DEBUG 15
+#define BOOKE_MAX_INTERRUPT 15
+
+#define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */
+#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
+
+#define RESUME_GUEST 0
+#define RESUME_GUEST_NV RESUME_FLAG_NV
+#define RESUME_HOST RESUME_FLAG_HOST
+#define RESUME_HOST_NV (RESUME_FLAG_HOST|RESUME_FLAG_NV)
+
+#endif /* __POWERPC_KVM_ASM_H__ */
diff --git a/include/asm-powerpc/kvm_host.h b/include/asm-powerpc/kvm_host.h
new file mode 100644
index 000000000000..04ffbb8e0a35
--- /dev/null
+++ b/include/asm-powerpc/kvm_host.h
@@ -0,0 +1,152 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_HOST_H__
+#define __POWERPC_KVM_HOST_H__
+
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <asm/kvm_asm.h>
+
+#define KVM_MAX_VCPUS 1
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+/* We don't currently support large pages. */
+#define KVM_PAGES_PER_HPAGE (1<<31)
+
+struct kvm;
+struct kvm_run;
+struct kvm_vcpu;
+
+struct kvm_vm_stat {
+ u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+ u32 sum_exits;
+ u32 mmio_exits;
+ u32 dcr_exits;
+ u32 signal_exits;
+ u32 light_exits;
+ /* Account for special types of light exits: */
+ u32 itlb_real_miss_exits;
+ u32 itlb_virt_miss_exits;
+ u32 dtlb_real_miss_exits;
+ u32 dtlb_virt_miss_exits;
+ u32 syscall_exits;
+ u32 isi_exits;
+ u32 dsi_exits;
+ u32 emulated_inst_exits;
+ u32 dec_exits;
+ u32 ext_intr_exits;
+};
+
+struct tlbe {
+ u32 tid; /* Only the low 8 bits are used. */
+ u32 word0;
+ u32 word1;
+ u32 word2;
+};
+
+struct kvm_arch {
+};
+
+struct kvm_vcpu_arch {
+ /* Unmodified copy of the guest's TLB. */
+ struct tlbe guest_tlb[PPC44x_TLB_SIZE];
+ /* TLB that's actually used when the guest is running. */
+ struct tlbe shadow_tlb[PPC44x_TLB_SIZE];
+ /* Pages which are referenced in the shadow TLB. */
+ struct page *shadow_pages[PPC44x_TLB_SIZE];
+ /* Copy of the host's TLB. */
+ struct tlbe host_tlb[PPC44x_TLB_SIZE];
+
+ u32 host_stack;
+ u32 host_pid;
+
+ u64 fpr[32];
+ u32 gpr[32];
+
+ u32 pc;
+ u32 cr;
+ u32 ctr;
+ u32 lr;
+ u32 xer;
+
+ u32 msr;
+ u32 mmucr;
+ u32 sprg0;
+ u32 sprg1;
+ u32 sprg2;
+ u32 sprg3;
+ u32 sprg4;
+ u32 sprg5;
+ u32 sprg6;
+ u32 sprg7;
+ u32 srr0;
+ u32 srr1;
+ u32 csrr0;
+ u32 csrr1;
+ u32 dsrr0;
+ u32 dsrr1;
+ u32 dear;
+ u32 esr;
+ u32 dec;
+ u32 decar;
+ u32 tbl;
+ u32 tbu;
+ u32 tcr;
+ u32 tsr;
+ u32 ivor[16];
+ u32 ivpr;
+ u32 pir;
+ u32 pid;
+ u32 pvr;
+ u32 ccr0;
+ u32 ccr1;
+ u32 dbcr0;
+ u32 dbcr1;
+
+ u32 last_inst;
+ u32 fault_dear;
+ u32 fault_esr;
+ gpa_t paddr_accessed;
+
+ u8 io_gpr; /* GPR used as IO source/target */
+ u8 mmio_is_bigendian;
+ u8 dcr_needed;
+ u8 dcr_is_write;
+
+ u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
+
+ struct timer_list dec_timer;
+ unsigned long pending_exceptions;
+};
+
+struct kvm_guest_debug {
+ int enabled;
+ unsigned long bp[4];
+ int singlestep;
+};
+
+#endif /* __POWERPC_KVM_HOST_H__ */
diff --git a/include/asm-powerpc/kvm_para.h b/include/asm-powerpc/kvm_para.h
new file mode 100644
index 000000000000..2d48f6a63d0b
--- /dev/null
+++ b/include/asm-powerpc/kvm_para.h
@@ -0,0 +1,37 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PARA_H__
+#define __POWERPC_KVM_PARA_H__
+
+#ifdef __KERNEL__
+
+static inline int kvm_para_available(void)
+{
+ return 0;
+}
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+ return 0;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/include/asm-powerpc/kvm_ppc.h b/include/asm-powerpc/kvm_ppc.h
new file mode 100644
index 000000000000..7ac820308a7e
--- /dev/null
+++ b/include/asm-powerpc/kvm_ppc.h
@@ -0,0 +1,88 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __POWERPC_KVM_PPC_H__
+#define __POWERPC_KVM_PPC_H__
+
+/* This file exists just so we can dereference kvm_vcpu, avoiding nested header
+ * dependencies. */
+
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+struct kvm_tlb {
+ struct tlbe guest_tlb[PPC44x_TLB_SIZE];
+ struct tlbe shadow_tlb[PPC44x_TLB_SIZE];
+};
+
+enum emulation_result {
+ EMULATE_DONE, /* no further processing */
+ EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
+ EMULATE_DO_DCR, /* kvm_run filled with DCR request */
+ EMULATE_FAIL, /* can't emulate this instruction */
+};
+
+extern const unsigned char exception_priority[];
+extern const unsigned char priority_exception[];
+
+extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
+extern char kvmppc_handlers_start[];
+extern unsigned long kvmppc_handler_len;
+
+extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
+extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ unsigned int rt, unsigned int bytes,
+ int is_bigendian);
+extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+ u32 val, unsigned int bytes, int is_bigendian);
+
+extern int kvmppc_emulate_instruction(struct kvm_run *run,
+ struct kvm_vcpu *vcpu);
+
+extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn,
+ u64 asid, u32 flags);
+extern void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid);
+extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode);
+
+extern void kvmppc_check_and_deliver_interrupts(struct kvm_vcpu *vcpu);
+
+static inline void kvmppc_queue_exception(struct kvm_vcpu *vcpu, int exception)
+{
+ unsigned int priority = exception_priority[exception];
+ set_bit(priority, &vcpu->arch.pending_exceptions);
+}
+
+static inline void kvmppc_clear_exception(struct kvm_vcpu *vcpu, int exception)
+{
+ unsigned int priority = exception_priority[exception];
+ clear_bit(priority, &vcpu->arch.pending_exceptions);
+}
+
+static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
+{
+ if ((new_msr & MSR_PR) != (vcpu->arch.msr & MSR_PR))
+ kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR);
+
+ vcpu->arch.msr = new_msr;
+}
+
+#endif /* __POWERPC_KVM_PPC_H__ */
diff --git a/include/asm-powerpc/mmu-44x.h b/include/asm-powerpc/mmu-44x.h
index c8b02d97f753..a825524c981a 100644
--- a/include/asm-powerpc/mmu-44x.h
+++ b/include/asm-powerpc/mmu-44x.h
@@ -53,6 +53,8 @@
#ifndef __ASSEMBLY__
+extern unsigned int tlb_44x_hwater;
+
typedef struct {
unsigned long id;
unsigned long vdso_base;
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index eb61b9c1edfd..7b564444ff61 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -108,6 +108,7 @@ struct paca_struct {
};
extern struct paca_struct paca[];
+extern void initialise_pacas(void);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PACA_H */
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
index 6c850609b847..cffdf0eb0df6 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -12,6 +12,7 @@
#include <asm/asm-compat.h>
#include <asm/kdump.h>
+#include <asm/types.h>
/*
* On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software
@@ -42,8 +43,23 @@
*
* The kdump dump kernel is one example where KERNELBASE != PAGE_OFFSET.
*
- * To get a physical address from a virtual one you subtract PAGE_OFFSET,
- * _not_ KERNELBASE.
+ * PAGE_OFFSET is the virtual address of the start of lowmem.
+ *
+ * PHYSICAL_START is the physical address of the start of the kernel.
+ *
+ * MEMORY_START is the physical address of the start of lowmem.
+ *
+ * KERNELBASE, PAGE_OFFSET, and PHYSICAL_START are all configurable on
+ * ppc32 and based on how they are set we determine MEMORY_START.
+ *
+ * For the linear mapping the following equation should be true:
+ * KERNELBASE - PAGE_OFFSET = PHYSICAL_START - MEMORY_START
+ *
+ * Also, KERNELBASE >= PAGE_OFFSET and PHYSICAL_START >= MEMORY_START
+ *
+ * There are two was to determine a physical address from a virtual one:
+ * va = pa + PAGE_OFFSET - MEMORY_START
+ * va = pa + KERNELBASE - PHYSICAL_START
*
* If you want to know something's offset from the start of the kernel you
* should subtract KERNELBASE.
@@ -51,20 +67,33 @@
* If you want to test if something's a kernel address, use is_kernel_addr().
*/
-#define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START)
-#define KERNELBASE (PAGE_OFFSET + PHYSICAL_START)
-#define LOAD_OFFSET PAGE_OFFSET
+#define KERNELBASE ASM_CONST(CONFIG_KERNEL_START)
+#define PAGE_OFFSET ASM_CONST(CONFIG_PAGE_OFFSET)
+#define LOAD_OFFSET ASM_CONST((CONFIG_KERNEL_START-CONFIG_PHYSICAL_START))
+
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_FLATMEM)
+#ifndef __ASSEMBLY__
+extern phys_addr_t memstart_addr;
+extern phys_addr_t kernstart_addr;
+#endif
+#define PHYSICAL_START kernstart_addr
+#define MEMORY_START memstart_addr
+#else
+#define PHYSICAL_START ASM_CONST(CONFIG_PHYSICAL_START)
+#define MEMORY_START (PHYSICAL_START + PAGE_OFFSET - KERNELBASE)
+#endif
#ifdef CONFIG_FLATMEM
-#define pfn_valid(pfn) ((pfn) < max_mapnr)
+#define ARCH_PFN_OFFSET (MEMORY_START >> PAGE_SHIFT)
+#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && (pfn) < (ARCH_PFN_OFFSET + max_mapnr))
#endif
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
-#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x) - PHYSICAL_START + KERNELBASE))
+#define __pa(x) ((unsigned long)(x) + PHYSICAL_START - KERNELBASE)
/*
* Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
index 51f8134b5939..ebfae530a379 100644
--- a/include/asm-powerpc/page_32.h
+++ b/include/asm-powerpc/page_32.h
@@ -1,6 +1,12 @@
#ifndef _ASM_POWERPC_PAGE_32_H
#define _ASM_POWERPC_PAGE_32_H
+#if defined(CONFIG_PHYSICAL_ALIGN) && (CONFIG_PHYSICAL_START != 0)
+#if (CONFIG_PHYSICAL_START % CONFIG_PHYSICAL_ALIGN) != 0
+#error "CONFIG_PHYSICAL_START must be a multiple of CONFIG_PHYSICAL_ALIGN"
+#endif
+#endif
+
#define VM_DATA_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS32
#ifdef CONFIG_NOT_COHERENT_CACHE
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h
index 67834eae5702..25af4fc8daf4 100644
--- a/include/asm-powerpc/page_64.h
+++ b/include/asm-powerpc/page_64.h
@@ -128,11 +128,6 @@ extern void slice_init_context(struct mm_struct *mm, unsigned int psize);
extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
#define slice_mm_new_context(mm) ((mm)->context.id == 0)
-#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
-extern int is_hugepage_only_range(struct mm_struct *m,
- unsigned long addr,
- unsigned long len);
-
#endif /* __ASSEMBLY__ */
#else
#define slice_init()
@@ -146,8 +141,6 @@ do { \
#ifdef CONFIG_HUGETLB_PAGE
-#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#endif /* !CONFIG_HUGETLB_PAGE */
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h
index daea7692d070..7c97b5a08d08 100644
--- a/include/asm-powerpc/pgtable-ppc32.h
+++ b/include/asm-powerpc/pgtable-ppc32.h
@@ -504,6 +504,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -521,6 +522,8 @@ static inline pte_t pte_mkdirty(pte_t pte) {
pte_val(pte) |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) {
pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+ return pte; }
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h
index dd4c26dc57d2..27f18695f7d6 100644
--- a/include/asm-powerpc/pgtable-ppc64.h
+++ b/include/asm-powerpc/pgtable-ppc64.h
@@ -239,6 +239,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+static inline int pte_special(pte_t pte) { return 0; }
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -257,6 +258,8 @@ static inline pte_t pte_mkyoung(pte_t pte) {
pte_val(pte) |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkhuge(pte_t pte) {
return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+ return pte; }
/* Atomic PTE updates */
static inline unsigned long pte_update(struct mm_struct *mm,
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index 40d5f98c44fc..d030f5ce39ad 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -80,12 +80,8 @@ struct thread_info {
#else /* THREAD_SHIFT < PAGE_SHIFT */
-#ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk) kzalloc(THREAD_SIZE, GFP_KERNEL)
-#else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
-#endif
-#define free_thread_info(ti) kfree(ti)
+extern struct thread_info *alloc_thread_info(struct task_struct *tsk);
+extern void free_thread_info(struct thread_info *ti);
#endif /* THREAD_SHIFT < PAGE_SHIFT */
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
index d46b57b589ae..d76ef098ed37 100644
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -15,10 +15,8 @@
* physical need a larger than native word size type. -Matt
*/
#ifndef CONFIG_PHYS_64BIT
-typedef unsigned long phys_addr_t;
#define PHYS_FMT "%.8lx"
#else
-typedef unsigned long long phys_addr_t;
extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t);
#define PHYS_FMT "%16Lx"
#endif
diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
index 23579d4afae7..402ba15c2e80 100644
--- a/include/asm-ppc/mpc8260.h
+++ b/include/asm-ppc/mpc8260.h
@@ -35,10 +35,6 @@
#include <platforms/tqm8260.h>
#endif
-#if defined(CONFIG_PQ2ADS) || defined (CONFIG_PQ2FADS)
-#include <platforms/pq2ads.h>
-#endif
-
#ifdef CONFIG_PCI_8260
#include <syslib/m82xx_pci.h>
#endif
diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
index d3a2f2fe230c..b9e3060b0278 100644
--- a/include/asm-ppc/mpc8xx.h
+++ b/include/asm-ppc/mpc8xx.h
@@ -63,10 +63,6 @@
#include <platforms/lantec.h>
#endif
-#if defined(CONFIG_MPC885ADS)
-#include <platforms/mpc885ads.h>
-#endif
-
/* Currently, all 8xx boards that support a processor to PCI/ISA bridge
* use the same memory map.
*/
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index 70435d32129a..55f9d38e3bf8 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -483,6 +483,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -500,6 +501,8 @@ static inline pte_t pte_mkdirty(pte_t pte) {
pte_val(pte) |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) {
pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+ return pte; }
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
diff --git a/include/asm-s390/Kbuild b/include/asm-s390/Kbuild
index e92b429d2be1..13c9805349f1 100644
--- a/include/asm-s390/Kbuild
+++ b/include/asm-s390/Kbuild
@@ -7,6 +7,7 @@ header-y += tape390.h
header-y += ucontext.h
header-y += vtoc.h
header-y += zcrypt.h
+header-y += kvm.h
unifdef-y += cmb.h
unifdef-y += debug.h
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
index 965394e69452..b4eb24ab5af9 100644
--- a/include/asm-s390/bitops.h
+++ b/include/asm-s390/bitops.h
@@ -769,6 +769,7 @@ static inline int sched_find_first_bit(unsigned long *b)
}
#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/hweight.h>
diff --git a/include/asm-s390/kvm.h b/include/asm-s390/kvm.h
index 573f2a351386..d74002f95794 100644
--- a/include/asm-s390/kvm.h
+++ b/include/asm-s390/kvm.h
@@ -1,6 +1,45 @@
#ifndef __LINUX_KVM_S390_H
#define __LINUX_KVM_S390_H
-/* s390 does not support KVM */
+/*
+ * asm-s390/kvm.h - KVM s390 specific structures and definitions
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+#include <asm/types.h>
+
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
+struct kvm_pic_state {
+ /* no PIC for s390 */
+};
+
+struct kvm_ioapic_state {
+ /* no IOAPIC for s390 */
+};
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+ /* general purpose regs for s390 */
+ __u64 gprs[16];
+};
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+ __u32 acrs[16];
+ __u64 crs[16];
+};
+
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+ __u32 fpc;
+ __u64 fprs[16];
+};
#endif
diff --git a/include/asm-s390/kvm_host.h b/include/asm-s390/kvm_host.h
new file mode 100644
index 000000000000..f8204a4f2e02
--- /dev/null
+++ b/include/asm-s390/kvm_host.h
@@ -0,0 +1,234 @@
+/*
+ * asm-s390/kvm_host.h - definition for kernel virtual machines on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Carsten Otte <cotte@de.ibm.com>
+ */
+
+
+#ifndef ASM_KVM_HOST_H
+#define ASM_KVM_HOST_H
+#include <linux/kvm_host.h>
+#include <asm/debug.h>
+
+#define KVM_MAX_VCPUS 64
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+struct kvm_guest_debug {
+};
+
+struct sca_entry {
+ atomic_t scn;
+ __u64 reserved;
+ __u64 sda;
+ __u64 reserved2[2];
+} __attribute__((packed));
+
+
+struct sca_block {
+ __u64 ipte_control;
+ __u64 reserved[5];
+ __u64 mcn;
+ __u64 reserved2;
+ struct sca_entry cpu[64];
+} __attribute__((packed));
+
+#define KVM_PAGES_PER_HPAGE 256
+
+#define CPUSTAT_HOST 0x80000000
+#define CPUSTAT_WAIT 0x10000000
+#define CPUSTAT_ECALL_PEND 0x08000000
+#define CPUSTAT_STOP_INT 0x04000000
+#define CPUSTAT_IO_INT 0x02000000
+#define CPUSTAT_EXT_INT 0x01000000
+#define CPUSTAT_RUNNING 0x00800000
+#define CPUSTAT_RETAINED 0x00400000
+#define CPUSTAT_TIMING_SUB 0x00020000
+#define CPUSTAT_SIE_SUB 0x00010000
+#define CPUSTAT_RRF 0x00008000
+#define CPUSTAT_SLSV 0x00004000
+#define CPUSTAT_SLSR 0x00002000
+#define CPUSTAT_ZARCH 0x00000800
+#define CPUSTAT_MCDS 0x00000100
+#define CPUSTAT_SM 0x00000080
+#define CPUSTAT_G 0x00000008
+#define CPUSTAT_J 0x00000002
+#define CPUSTAT_P 0x00000001
+
+struct sie_block {
+ atomic_t cpuflags; /* 0x0000 */
+ __u32 prefix; /* 0x0004 */
+ __u8 reserved8[32]; /* 0x0008 */
+ __u64 cputm; /* 0x0028 */
+ __u64 ckc; /* 0x0030 */
+ __u64 epoch; /* 0x0038 */
+ __u8 reserved40[4]; /* 0x0040 */
+#define LCTL_CR0 0x8000
+ __u16 lctl; /* 0x0044 */
+ __s16 icpua; /* 0x0046 */
+ __u32 ictl; /* 0x0048 */
+ __u32 eca; /* 0x004c */
+ __u8 icptcode; /* 0x0050 */
+ __u8 reserved51; /* 0x0051 */
+ __u16 ihcpu; /* 0x0052 */
+ __u8 reserved54[2]; /* 0x0054 */
+ __u16 ipa; /* 0x0056 */
+ __u32 ipb; /* 0x0058 */
+ __u32 scaoh; /* 0x005c */
+ __u8 reserved60; /* 0x0060 */
+ __u8 ecb; /* 0x0061 */
+ __u8 reserved62[2]; /* 0x0062 */
+ __u32 scaol; /* 0x0064 */
+ __u8 reserved68[4]; /* 0x0068 */
+ __u32 todpr; /* 0x006c */
+ __u8 reserved70[16]; /* 0x0070 */
+ __u64 gmsor; /* 0x0080 */
+ __u64 gmslm; /* 0x0088 */
+ psw_t gpsw; /* 0x0090 */
+ __u64 gg14; /* 0x00a0 */
+ __u64 gg15; /* 0x00a8 */
+ __u8 reservedb0[30]; /* 0x00b0 */
+ __u16 iprcc; /* 0x00ce */
+ __u8 reservedd0[48]; /* 0x00d0 */
+ __u64 gcr[16]; /* 0x0100 */
+ __u64 gbea; /* 0x0180 */
+ __u8 reserved188[120]; /* 0x0188 */
+} __attribute__((packed));
+
+struct kvm_vcpu_stat {
+ u32 exit_userspace;
+ u32 exit_external_request;
+ u32 exit_external_interrupt;
+ u32 exit_stop_request;
+ u32 exit_validity;
+ u32 exit_instruction;
+ u32 instruction_lctl;
+ u32 instruction_lctg;
+ u32 exit_program_interruption;
+ u32 exit_instr_and_program;
+ u32 deliver_emergency_signal;
+ u32 deliver_service_signal;
+ u32 deliver_virtio_interrupt;
+ u32 deliver_stop_signal;
+ u32 deliver_prefix_signal;
+ u32 deliver_restart_signal;
+ u32 deliver_program_int;
+ u32 exit_wait_state;
+ u32 instruction_stidp;
+ u32 instruction_spx;
+ u32 instruction_stpx;
+ u32 instruction_stap;
+ u32 instruction_storage_key;
+ u32 instruction_stsch;
+ u32 instruction_chsc;
+ u32 instruction_stsi;
+ u32 instruction_stfl;
+ u32 instruction_sigp_sense;
+ u32 instruction_sigp_emergency;
+ u32 instruction_sigp_stop;
+ u32 instruction_sigp_arch;
+ u32 instruction_sigp_prefix;
+ u32 instruction_sigp_restart;
+ u32 diagnose_44;
+};
+
+struct io_info {
+ __u16 subchannel_id; /* 0x0b8 */
+ __u16 subchannel_nr; /* 0x0ba */
+ __u32 io_int_parm; /* 0x0bc */
+ __u32 io_int_word; /* 0x0c0 */
+};
+
+struct ext_info {
+ __u32 ext_params;
+ __u64 ext_params2;
+};
+
+#define PGM_OPERATION 0x01
+#define PGM_PRIVILEGED_OPERATION 0x02
+#define PGM_EXECUTE 0x03
+#define PGM_PROTECTION 0x04
+#define PGM_ADDRESSING 0x05
+#define PGM_SPECIFICATION 0x06
+#define PGM_DATA 0x07
+
+struct pgm_info {
+ __u16 code;
+};
+
+struct prefix_info {
+ __u32 address;
+};
+
+struct interrupt_info {
+ struct list_head list;
+ u64 type;
+ union {
+ struct io_info io;
+ struct ext_info ext;
+ struct pgm_info pgm;
+ struct prefix_info prefix;
+ };
+};
+
+/* for local_interrupt.action_flags */
+#define ACTION_STORE_ON_STOP 1
+#define ACTION_STOP_ON_STOP 2
+
+struct local_interrupt {
+ spinlock_t lock;
+ struct list_head list;
+ atomic_t active;
+ struct float_interrupt *float_int;
+ int timer_due; /* event indicator for waitqueue below */
+ wait_queue_head_t wq;
+ atomic_t *cpuflags;
+ unsigned int action_bits;
+};
+
+struct float_interrupt {
+ spinlock_t lock;
+ struct list_head list;
+ atomic_t active;
+ int next_rr_cpu;
+ unsigned long idle_mask [(64 + sizeof(long) - 1) / sizeof(long)];
+ struct local_interrupt *local_int[64];
+};
+
+
+struct kvm_vcpu_arch {
+ struct sie_block *sie_block;
+ unsigned long guest_gprs[16];
+ s390_fp_regs host_fpregs;
+ unsigned int host_acrs[NUM_ACRS];
+ s390_fp_regs guest_fpregs;
+ unsigned int guest_acrs[NUM_ACRS];
+ struct local_interrupt local_int;
+ struct timer_list ckc_timer;
+ union {
+ cpuid_t cpu_id;
+ u64 stidp_data;
+ };
+};
+
+struct kvm_vm_stat {
+ u32 remote_tlb_flush;
+};
+
+struct kvm_arch{
+ unsigned long guest_origin;
+ unsigned long guest_memsize;
+ struct sca_block *sca;
+ debug_info_t *dbf;
+ struct float_interrupt float_int;
+};
+
+extern int sie64a(struct sie_block *, __u64 *);
+#endif
diff --git a/include/asm-s390/kvm_para.h b/include/asm-s390/kvm_para.h
new file mode 100644
index 000000000000..2c503796b619
--- /dev/null
+++ b/include/asm-s390/kvm_para.h
@@ -0,0 +1,150 @@
+/*
+ * asm-s390/kvm_para.h - definition for paravirtual devices on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#ifndef __S390_KVM_PARA_H
+#define __S390_KVM_PARA_H
+
+/*
+ * Hypercalls for KVM on s390. The calling convention is similar to the
+ * s390 ABI, so we use R2-R6 for parameters 1-5. In addition we use R1
+ * as hypercall number and R7 as parameter 6. The return value is
+ * written to R2. We use the diagnose instruction as hypercall. To avoid
+ * conflicts with existing diagnoses for LPAR and z/VM, we do not use
+ * the instruction encoded number, but specify the number in R1 and
+ * use 0x500 as KVM hypercall
+ *
+ * Copyright IBM Corp. 2007,2008
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+static inline long kvm_hypercall0(unsigned long nr)
+{
+ register unsigned long __nr asm("1") = nr;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr): "memory", "cc");
+ return __rc;
+}
+
+static inline long kvm_hypercall1(unsigned long nr, unsigned long p1)
+{
+ register unsigned long __nr asm("1") = nr;
+ register unsigned long __p1 asm("2") = p1;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr), "0" (__p1) : "memory", "cc");
+ return __rc;
+}
+
+static inline long kvm_hypercall2(unsigned long nr, unsigned long p1,
+ unsigned long p2)
+{
+ register unsigned long __nr asm("1") = nr;
+ register unsigned long __p1 asm("2") = p1;
+ register unsigned long __p2 asm("3") = p2;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2)
+ : "memory", "cc");
+ return __rc;
+}
+
+static inline long kvm_hypercall3(unsigned long nr, unsigned long p1,
+ unsigned long p2, unsigned long p3)
+{
+ register unsigned long __nr asm("1") = nr;
+ register unsigned long __p1 asm("2") = p1;
+ register unsigned long __p2 asm("3") = p2;
+ register unsigned long __p3 asm("4") = p3;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2),
+ "d" (__p3) : "memory", "cc");
+ return __rc;
+}
+
+
+static inline long kvm_hypercall4(unsigned long nr, unsigned long p1,
+ unsigned long p2, unsigned long p3,
+ unsigned long p4)
+{
+ register unsigned long __nr asm("1") = nr;
+ register unsigned long __p1 asm("2") = p1;
+ register unsigned long __p2 asm("3") = p2;
+ register unsigned long __p3 asm("4") = p3;
+ register unsigned long __p4 asm("5") = p4;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2),
+ "d" (__p3), "d" (__p4) : "memory", "cc");
+ return __rc;
+}
+
+static inline long kvm_hypercall5(unsigned long nr, unsigned long p1,
+ unsigned long p2, unsigned long p3,
+ unsigned long p4, unsigned long p5)
+{
+ register unsigned long __nr asm("1") = nr;
+ register unsigned long __p1 asm("2") = p1;
+ register unsigned long __p2 asm("3") = p2;
+ register unsigned long __p3 asm("4") = p3;
+ register unsigned long __p4 asm("5") = p4;
+ register unsigned long __p5 asm("6") = p5;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2),
+ "d" (__p3), "d" (__p4), "d" (__p5) : "memory", "cc");
+ return __rc;
+}
+
+static inline long kvm_hypercall6(unsigned long nr, unsigned long p1,
+ unsigned long p2, unsigned long p3,
+ unsigned long p4, unsigned long p5,
+ unsigned long p6)
+{
+ register unsigned long __nr asm("1") = nr;
+ register unsigned long __p1 asm("2") = p1;
+ register unsigned long __p2 asm("3") = p2;
+ register unsigned long __p3 asm("4") = p3;
+ register unsigned long __p4 asm("5") = p4;
+ register unsigned long __p5 asm("6") = p5;
+ register unsigned long __p6 asm("7") = p6;
+ register long __rc asm("2");
+
+ asm volatile ("diag 2,4,0x500\n"
+ : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2),
+ "d" (__p3), "d" (__p4), "d" (__p5), "d" (__p6)
+ : "memory", "cc");
+ return __rc;
+}
+
+/* kvm on s390 is always paravirtualization enabled */
+static inline int kvm_para_available(void)
+{
+ return 1;
+}
+
+/* No feature bits are currently assigned for kvm on s390 */
+static inline unsigned int kvm_arch_para_features(void)
+{
+ return 0;
+}
+
+#endif /* __S390_KVM_PARA_H */
diff --git a/include/asm-s390/kvm_virtio.h b/include/asm-s390/kvm_virtio.h
new file mode 100644
index 000000000000..5c871a990c29
--- /dev/null
+++ b/include/asm-s390/kvm_virtio.h
@@ -0,0 +1,53 @@
+/*
+ * kvm_virtio.h - definition for virtio for kvm on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#ifndef __KVM_S390_VIRTIO_H
+#define __KVM_S390_VIRTIO_H
+
+#include <linux/types.h>
+
+struct kvm_device_desc {
+ /* The device type: console, network, disk etc. Type 0 terminates. */
+ __u8 type;
+ /* The number of virtqueues (first in config array) */
+ __u8 num_vq;
+ /*
+ * The number of bytes of feature bits. Multiply by 2: one for host
+ * features and one for guest acknowledgements.
+ */
+ __u8 feature_len;
+ /* The number of bytes of the config array after virtqueues. */
+ __u8 config_len;
+ /* A status byte, written by the Guest. */
+ __u8 status;
+ __u8 config[0];
+};
+
+/*
+ * This is how we expect the device configuration field for a virtqueue
+ * to be laid out in config space.
+ */
+struct kvm_vqconfig {
+ /* The token returned with an interrupt. Set by the guest */
+ __u64 token;
+ /* The address of the virtio ring */
+ __u64 address;
+ /* The number of entries in the virtio_ring */
+ __u16 num;
+
+};
+
+#define KVM_S390_VIRTIO_NOTIFY 0
+#define KVM_S390_VIRTIO_RESET 1
+#define KVM_S390_VIRTIO_SET_STATUS 2
+
+#endif
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 5de3efb31445..0bc51d52a899 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -381,27 +381,32 @@ struct _lowcore
/* whether the kernel died with panic() or not */
__u32 panic_magic; /* 0xe00 */
- __u8 pad13[0x1200-0xe04]; /* 0xe04 */
+ __u8 pad13[0x11b8-0xe04]; /* 0xe04 */
+
+ /* 64 bit extparam used for pfault, diag 250 etc */
+ __u64 ext_params2; /* 0x11B8 */
+
+ __u8 pad14[0x1200-0x11C0]; /* 0x11C0 */
/* System info area */
__u64 floating_pt_save_area[16]; /* 0x1200 */
__u64 gpregs_save_area[16]; /* 0x1280 */
__u32 st_status_fixed_logout[4]; /* 0x1300 */
- __u8 pad14[0x1318-0x1310]; /* 0x1310 */
+ __u8 pad15[0x1318-0x1310]; /* 0x1310 */
__u32 prefixreg_save_area; /* 0x1318 */
__u32 fpt_creg_save_area; /* 0x131c */
- __u8 pad15[0x1324-0x1320]; /* 0x1320 */
+ __u8 pad16[0x1324-0x1320]; /* 0x1320 */
__u32 tod_progreg_save_area; /* 0x1324 */
__u32 cpu_timer_save_area[2]; /* 0x1328 */
__u32 clock_comp_save_area[2]; /* 0x1330 */
- __u8 pad16[0x1340-0x1338]; /* 0x1338 */
+ __u8 pad17[0x1340-0x1338]; /* 0x1338 */
__u32 access_regs_save_area[16]; /* 0x1340 */
__u64 cregs_save_area[16]; /* 0x1380 */
/* align to the top of the prefix area */
- __u8 pad17[0x2000-0x1400]; /* 0x1400 */
+ __u8 pad18[0x2000-0x1400]; /* 0x1400 */
#endif /* !__s390x__ */
} __attribute__((packed)); /* End structure*/
diff --git a/include/asm-s390/mmu.h b/include/asm-s390/mmu.h
index 1698e29c5b20..5dd5e7b3476f 100644
--- a/include/asm-s390/mmu.h
+++ b/include/asm-s390/mmu.h
@@ -7,6 +7,7 @@ typedef struct {
unsigned long asce_bits;
unsigned long asce_limit;
int noexec;
+ int pgstes;
} mm_context_t;
#endif
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index b5a34c6f91a9..4c2fbf48c9c4 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -20,7 +20,13 @@ static inline int init_new_context(struct task_struct *tsk,
#ifdef CONFIG_64BIT
mm->context.asce_bits |= _ASCE_TYPE_REGION3;
#endif
- mm->context.noexec = s390_noexec;
+ if (current->mm->context.pgstes) {
+ mm->context.noexec = 0;
+ mm->context.pgstes = 1;
+ } else {
+ mm->context.noexec = s390_noexec;
+ mm->context.pgstes = 0;
+ }
mm->context.asce_limit = STACK_TOP_MAX;
crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
return 0;
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 65154dc9a9e5..f8347ce9c5a1 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -30,6 +30,7 @@
*/
#ifndef __ASSEMBLY__
#include <linux/mm_types.h>
+#include <asm/bitops.h>
#include <asm/bug.h>
#include <asm/processor.h>
@@ -219,6 +220,8 @@ extern char empty_zero_page[PAGE_SIZE];
/* Software bits in the page table entry */
#define _PAGE_SWT 0x001 /* SW pte type bit t */
#define _PAGE_SWX 0x002 /* SW pte type bit x */
+#define _PAGE_SPECIAL 0x004 /* SW associated with special page */
+#define __HAVE_ARCH_PTE_SPECIAL
/* Six different types of pages. */
#define _PAGE_TYPE_EMPTY 0x400
@@ -258,6 +261,13 @@ extern char empty_zero_page[PAGE_SIZE];
* swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
*/
+/* Page status table bits for virtualization */
+#define RCP_PCL_BIT 55
+#define RCP_HR_BIT 54
+#define RCP_HC_BIT 53
+#define RCP_GR_BIT 50
+#define RCP_GC_BIT 49
+
#ifndef __s390x__
/* Bits in the segment table address-space-control-element */
@@ -510,9 +520,56 @@ static inline int pte_file(pte_t pte)
return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
}
+static inline int pte_special(pte_t pte)
+{
+ return (pte_val(pte) & _PAGE_SPECIAL);
+}
+
#define __HAVE_ARCH_PTE_SAME
#define pte_same(a,b) (pte_val(a) == pte_val(b))
+static inline void rcp_lock(pte_t *ptep)
+{
+#ifdef CONFIG_PGSTE
+ unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+ preempt_disable();
+ while (test_and_set_bit(RCP_PCL_BIT, pgste))
+ ;
+#endif
+}
+
+static inline void rcp_unlock(pte_t *ptep)
+{
+#ifdef CONFIG_PGSTE
+ unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+ clear_bit(RCP_PCL_BIT, pgste);
+ preempt_enable();
+#endif
+}
+
+/* forward declaration for SetPageUptodate in page-flags.h*/
+static inline void page_clear_dirty(struct page *page);
+#include <linux/page-flags.h>
+
+static inline void ptep_rcp_copy(pte_t *ptep)
+{
+#ifdef CONFIG_PGSTE
+ struct page *page = virt_to_page(pte_val(*ptep));
+ unsigned int skey;
+ unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+
+ skey = page_get_storage_key(page_to_phys(page));
+ if (skey & _PAGE_CHANGED)
+ set_bit_simple(RCP_GC_BIT, pgste);
+ if (skey & _PAGE_REFERENCED)
+ set_bit_simple(RCP_GR_BIT, pgste);
+ if (test_and_clear_bit_simple(RCP_HC_BIT, pgste))
+ SetPageDirty(page);
+ if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
+ SetPageReferenced(page);
+#endif
+}
+
/*
* query functions pte_write/pte_dirty/pte_young only work if
* pte_present() is true. Undefined behaviour if not..
@@ -599,6 +656,8 @@ static inline void pmd_clear(pmd_t *pmd)
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
+ if (mm->context.pgstes)
+ ptep_rcp_copy(ptep);
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
if (mm->context.noexec)
pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY;
@@ -663,10 +722,34 @@ static inline pte_t pte_mkyoung(pte_t pte)
return pte;
}
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_SPECIAL;
+ return pte;
+}
+
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
+#ifdef CONFIG_PGSTE
+ unsigned long physpage;
+ int young;
+ unsigned long *pgste;
+
+ if (!vma->vm_mm->context.pgstes)
+ return 0;
+ physpage = pte_val(*ptep) & PAGE_MASK;
+ pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+
+ young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0);
+ rcp_lock(ptep);
+ if (young)
+ set_bit_simple(RCP_GR_BIT, pgste);
+ young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste);
+ rcp_unlock(ptep);
+ return young;
+#endif
return 0;
}
@@ -674,7 +757,13 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
- /* No need to flush TLB; bits are in storage key */
+ /* No need to flush TLB
+ * On s390 reference bits are in storage key and never in TLB
+ * With virtualization we handle the reference bit, without we
+ * we can simply return */
+#ifdef CONFIG_PGSTE
+ return ptep_test_and_clear_young(vma, address, ptep);
+#endif
return 0;
}
@@ -693,15 +782,25 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
: "=m" (*ptep) : "m" (*ptep),
"a" (pto), "a" (address));
}
- pte_val(*ptep) = _PAGE_TYPE_EMPTY;
}
static inline void ptep_invalidate(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
+ if (mm->context.pgstes) {
+ rcp_lock(ptep);
+ __ptep_ipte(address, ptep);
+ ptep_rcp_copy(ptep);
+ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+ rcp_unlock(ptep);
+ return;
+ }
__ptep_ipte(address, ptep);
- if (mm->context.noexec)
+ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+ if (mm->context.noexec) {
__ptep_ipte(address, ptep + PTRS_PER_PTE);
+ pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY;
+ }
}
/*
@@ -966,6 +1065,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
extern int add_shared_memory(unsigned long start, unsigned long size);
extern int remove_shared_memory(unsigned long start, unsigned long size);
+extern int s390_enable_sie(void);
/*
* No page table caches to initialise
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index a76a6b8fd887..aaf4b518b940 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -62,6 +62,7 @@ extern unsigned long machine_flags;
#define MACHINE_IS_VM (machine_flags & 1)
#define MACHINE_IS_P390 (machine_flags & 4)
#define MACHINE_HAS_MVPG (machine_flags & 16)
+#define MACHINE_IS_KVM (machine_flags & 64)
#define MACHINE_HAS_IDTE (machine_flags & 128)
#define MACHINE_HAS_DIAG9C (machine_flags & 256)
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
index b6ba5a60dec2..d7d382f63ee5 100644
--- a/include/asm-sh/bitops.h
+++ b/include/asm-sh/bitops.h
@@ -95,6 +95,7 @@ static inline unsigned long ffz(unsigned long word)
#include <asm-generic/bitops/ext2-atomic.h>
#include <asm-generic/bitops/minix.h>
#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/hugetlb.h b/include/asm-sh/hugetlb.h
new file mode 100644
index 000000000000..02402303d89b
--- /dev/null
+++ b/include/asm-sh/hugetlb.h
@@ -0,0 +1,91 @@
+#ifndef _ASM_SH_HUGETLB_H
+#define _ASM_SH_HUGETLB_H
+
+#include <asm/page.h>
+
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr,
+ unsigned long len) {
+ return 0;
+}
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) {
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather **tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ set_pte_at(mm, addr, ptep, pte);
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+ return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+#endif /* _ASM_SH_HUGETLB_H */
diff --git a/include/asm-sh/pgtable_32.h b/include/asm-sh/pgtable_32.h
index 3e3557c53c55..cbc731d35c25 100644
--- a/include/asm-sh/pgtable_32.h
+++ b/include/asm-sh/pgtable_32.h
@@ -326,6 +326,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
#define pte_dirty(pte) ((pte).pte_low & _PAGE_DIRTY)
#define pte_young(pte) ((pte).pte_low & _PAGE_ACCESSED)
#define pte_file(pte) ((pte).pte_low & _PAGE_FILE)
+#define pte_special(pte) (0)
#ifdef CONFIG_X2TLB
#define pte_write(pte) ((pte).pte_high & _PAGE_EXT_USER_WRITE)
@@ -356,6 +357,8 @@ PTE_BIT_FUNC(low, mkdirty, |= _PAGE_DIRTY);
PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED);
PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
+
/*
* Macro and implementation to make a page protection as uncachable.
*/
diff --git a/include/asm-sh/pgtable_64.h b/include/asm-sh/pgtable_64.h
index f9dd9d311441..c78990cda557 100644
--- a/include/asm-sh/pgtable_64.h
+++ b/include/asm-sh/pgtable_64.h
@@ -254,10 +254,11 @@ extern void __handle_bad_pmd_kernel(pmd_t * pmd);
/*
* The following have defined behavior only work if pte_present() is true.
*/
-static inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; }
-static inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
-static inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_WRITE; }
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
+static inline int pte_special(pte_t pte){ return 0; }
static inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
static inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -266,6 +267,7 @@ static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) |
static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/*
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index 2cc235b74d94..d84af6d95f5c 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -219,6 +219,11 @@ static inline int pte_file(pte_t pte)
return pte_val(pte) & BTFIXUP_HALF(pte_filei);
}
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
+
/*
*/
BTFIXUPDEF_HALF(pte_wrprotecti)
@@ -251,6 +256,8 @@ BTFIXUPDEF_CALL_CONST(pte_t, pte_mkyoung, pte_t)
#define pte_mkdirty(pte) BTFIXUP_CALL(pte_mkdirty)(pte)
#define pte_mkyoung(pte) BTFIXUP_CALL(pte_mkyoung)(pte)
+#define pte_mkspecial(pte) (pte)
+
#define pfn_pte(pfn, prot) mk_pte(pfn_to_page(pfn), prot)
BTFIXUPDEF_CALL(unsigned long, pte_pfn, pte_t)
diff --git a/include/asm-sparc/processor.h b/include/asm-sparc/processor.h
index e3006979709b..8898efbbbe07 100644
--- a/include/asm-sparc/processor.h
+++ b/include/asm-sparc/processor.h
@@ -1,5 +1,4 @@
-/* $Id: processor.h,v 1.83 2001/10/08 09:32:13 davem Exp $
- * include/asm-sparc/processor.h
+/* include/asm-sparc/processor.h
*
* Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
*/
@@ -65,7 +64,6 @@ struct thread_struct {
struct fpq fpqueue[16];
unsigned long flags;
mm_segment_t current_ds;
- int new_signal;
};
#define SPARC_FLAG_KTHREAD 0x1 /* task is a kernel thread */
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index 982ce8992b91..11f9d8146cdf 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -34,6 +34,7 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
#include <asm-generic/bitops/ffz.h>
#include <asm-generic/bitops/__ffs.h>
#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#ifdef __KERNEL__
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index c47f58d6c15c..ca19f80a9b7d 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -293,7 +293,6 @@ static int sun_fd_eject(int drive)
#ifdef CONFIG_PCI
#include <asm/ebus.h>
-#include <asm/isa.h>
#include <asm/ns87303.h>
static struct ebus_dma_info sun_pci_fd_ebus_dma;
@@ -558,82 +557,6 @@ static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
}
#endif
-#ifdef CONFIG_PCI
-#undef ISA_FLOPPY_WORKS
-
-#ifdef ISA_FLOPPY_WORKS
-static unsigned long __init isa_floppy_init(void)
-{
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev = NULL;
-
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- if (!strcmp(isa_dev->prom_node->name, "dma")) {
- struct sparc_isa_device *child =
- isa_dev->child;
-
- while (child) {
- if (!strcmp(child->prom_node->name,
- "floppy")) {
- isa_dev = child;
- goto isa_done;
- }
- child = child->next;
- }
- }
- }
- }
-isa_done:
- if (!isa_dev)
- return 0;
-
- /* We could use DMA on devices behind the ISA bridge, but...
- *
- * There is a slight problem. Normally on x86 kit the x86 processor
- * delays I/O port instructions when the ISA bus "dma in progress"
- * signal is active. Well, sparc64 systems do not monitor this
- * signal thus we would need to block all I/O port accesses in software
- * when a dma transfer is active for some device.
- */
-
- sun_fdc = (struct sun_flpy_controller *)isa_dev->resource.start;
- FLOPPY_IRQ = isa_dev->irq;
-
- sun_fdops.fd_inb = sun_pci_fd_inb;
- sun_fdops.fd_outb = sun_pci_fd_outb;
-
- can_use_virtual_dma = use_virtual_dma = 1;
- sun_fdops.fd_enable_dma = sun_fd_enable_dma;
- sun_fdops.fd_disable_dma = sun_fd_disable_dma;
- sun_fdops.fd_set_dma_mode = sun_fd_set_dma_mode;
- sun_fdops.fd_set_dma_addr = sun_fd_set_dma_addr;
- sun_fdops.fd_set_dma_count = sun_fd_set_dma_count;
- sun_fdops.get_dma_residue = sun_get_dma_residue;
-
- sun_fdops.fd_request_irq = sun_fd_request_irq;
- sun_fdops.fd_free_irq = sun_fd_free_irq;
-
- /* Floppy eject is manual. Actually, could determine this
- * via presence of 'manual' property in OBP node.
- */
- sun_fdops.fd_eject = sun_pci_fd_eject;
-
- fdc_status = (unsigned long) &sun_fdc->status_82077;
-
- allowed_drive_mask = 0;
- sun_floppy_types[0] = 0;
- sun_floppy_types[1] = 4;
-
- sun_pci_broken_drive = 1;
- sun_fdops.fd_outb = sun_pci_fd_broken_outb;
-
- return sun_floppy_types[0];
-}
-#endif /* ISA_FLOPPY_WORKS */
-
-#endif
-
static unsigned long __init sun_floppy_init(void)
{
char state[128];
@@ -667,13 +590,8 @@ static unsigned long __init sun_floppy_init(void)
}
}
ebus_done:
- if (!edev) {
-#ifdef ISA_FLOPPY_WORKS
- return isa_floppy_init();
-#else
+ if (!edev)
return 0;
-#endif
- }
state_prop = of_get_property(edev->prom_node, "status", NULL);
if (state_prop && !strncmp(state_prop, "disabled", 8))
diff --git a/include/asm-sparc64/hugetlb.h b/include/asm-sparc64/hugetlb.h
new file mode 100644
index 000000000000..412af58926a0
--- /dev/null
+++ b/include/asm-sparc64/hugetlb.h
@@ -0,0 +1,84 @@
+#ifndef _ASM_SPARC64_HUGETLB_H
+#define _ASM_SPARC64_HUGETLB_H
+
+#include <asm/page.h>
+
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+
+void hugetlb_prefault_arch_hook(struct mm_struct *mm);
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr,
+ unsigned long len) {
+ return 0;
+}
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather **tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+ return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+#endif /* _ASM_SPARC64_HUGETLB_H */
diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h
deleted file mode 100644
index ecd9290f78d4..000000000000
--- a/include/asm-sparc64/isa.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* $Id: isa.h,v 1.1 2001/05/11 04:31:55 davem Exp $
- * isa.h: Sparc64 layer for PCI to ISA bridge devices.
- *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
- */
-
-#ifndef __SPARC64_ISA_H
-#define __SPARC64_ISA_H
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-
-struct sparc_isa_bridge;
-
-struct sparc_isa_device {
- struct of_device ofdev;
- struct sparc_isa_device *next;
- struct sparc_isa_device *child;
- struct sparc_isa_bridge *bus;
- struct device_node *prom_node;
- struct resource resource;
- unsigned int irq;
-};
-#define to_isa_device(d) container_of(d, struct sparc_isa_device, ofdev.dev)
-
-struct sparc_isa_bridge {
- struct of_device ofdev;
- struct sparc_isa_bridge *next;
- struct sparc_isa_device *devices;
- struct pci_dev *self;
- int index;
- struct device_node *prom_node;
-};
-#define to_isa_bridge(d) container_of(d, struct sparc_isa_bridge, ofdev.dev)
-
-extern struct sparc_isa_bridge *isa_chain;
-
-extern void isa_init(void);
-
-#define for_each_isa(bus) \
- for((bus) = isa_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_isadev(dev, bus) \
- for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#endif /* !(__SPARC64_ISA_H) */
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index e93a482aa24a..618117def0dc 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -39,8 +39,6 @@
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1UL))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
-#define ARCH_HAS_HUGETLB_PREFAULT_HOOK
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#endif
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 549e45266b68..0e200e7acec7 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -506,6 +506,11 @@ static inline pte_t pte_mkyoung(pte_t pte)
return __pte(pte_val(pte) | mask);
}
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return pte;
+}
+
static inline unsigned long pte_young(pte_t pte)
{
unsigned long mask;
@@ -608,6 +613,11 @@ static inline unsigned long pte_present(pte_t pte)
return val;
}
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
+
#define pmd_set(pmdp, ptep) \
(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
#define pud_set(pudp, pmdp) \
diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h
index b4b951d570bb..714b81956f32 100644
--- a/include/asm-sparc64/ptrace.h
+++ b/include/asm-sparc64/ptrace.h
@@ -1,4 +1,3 @@
-/* $Id: ptrace.h,v 1.14 2002/02/09 19:49:32 davem Exp $ */
#ifndef _SPARC64_PTRACE_H
#define _SPARC64_PTRACE_H
@@ -8,10 +7,15 @@
* stack during a system call and basically all traps.
*/
+/* This magic value must have the low 9 bits clear,
+ * as that is where we encode the %tt value, see below.
+ */
#define PT_REGS_MAGIC 0x57ac6c00
#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
struct pt_regs {
unsigned long u_regs[16]; /* globals and ins */
unsigned long tstate;
@@ -33,6 +37,23 @@ struct pt_regs {
unsigned int magic;
};
+static inline int pt_regs_trap_type(struct pt_regs *regs)
+{
+ return regs->magic & 0x1ff;
+}
+
+static inline int pt_regs_clear_trap_type(struct pt_regs *regs)
+{
+ return regs->magic &= ~0x1ff;
+}
+
+static inline bool pt_regs_is_syscall(struct pt_regs *regs)
+{
+ int tt = pt_regs_trap_type(regs);
+
+ return (tt == 0x110 || tt == 0x111 || tt == 0x16d);
+}
+
struct pt_regs32 {
unsigned int psr;
unsigned int pc;
diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h
index 98252cd44dd6..71e42d1a80d9 100644
--- a/include/asm-sparc64/thread_info.h
+++ b/include/asm-sparc64/thread_info.h
@@ -1,5 +1,4 @@
-/* $Id: thread_info.h,v 1.1 2002/02/10 00:00:58 davem Exp $
- * thread_info.h: sparc64 low-level thread information
+/* thread_info.h: sparc64 low-level thread information
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
@@ -223,7 +222,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_PERFCTR 4 /* performance counters active */
#define TIF_UNALIGNED 5 /* allowed to do unaligned accesses */
-#define TIF_NEWSIGNALS 6 /* wants new-style signals */
+/* flag bit 6 is available */
#define TIF_32BIT 7 /* 32-bit binary */
/* flag bit 8 is available */
#define TIF_SECCOMP 9 /* secure computing */
@@ -242,7 +241,6 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_PERFCTR (1<<TIF_PERFCTR)
#define _TIF_UNALIGNED (1<<TIF_UNALIGNED)
-#define _TIF_NEWSIGNALS (1<<TIF_NEWSIGNALS)
#define _TIF_32BIT (1<<TIF_32BIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 4102b443e925..02db81b7b86e 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -173,6 +173,11 @@ static inline int pte_newprot(pte_t pte)
return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT)));
}
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
+
/*
* =================================
* Flags setting section.
@@ -241,6 +246,11 @@ static inline pte_t pte_mknewpage(pte_t pte)
return(pte);
}
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return(pte);
+}
+
static inline void set_pte(pte_t *pteptr, pte_t pteval)
{
pte_copy(*pteptr, pteval);
diff --git a/include/asm-x86/bios_ebda.h b/include/asm-x86/bios_ebda.h
index 9cbd9a668af8..b4a46b7be794 100644
--- a/include/asm-x86/bios_ebda.h
+++ b/include/asm-x86/bios_ebda.h
@@ -1,6 +1,8 @@
#ifndef _MACH_BIOS_EBDA_H
#define _MACH_BIOS_EBDA_H
+#include <asm/io.h>
+
/*
* there is a real-mode segmented pointer pointing to the
* 4K EBDA area at 0x40E.
diff --git a/include/asm-x86/bitops.h b/include/asm-x86/bitops.h
index 1ae7b270a1ef..b81a4d4d3337 100644
--- a/include/asm-x86/bitops.h
+++ b/include/asm-x86/bitops.h
@@ -62,12 +62,9 @@ static inline void set_bit(int nr, volatile void *addr)
*/
static inline void __set_bit(int nr, volatile void *addr)
{
- asm volatile("bts %1,%0"
- : ADDR
- : "Ir" (nr) : "memory");
+ asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
}
-
/**
* clear_bit - Clears a bit in memory
* @nr: Bit to clear
@@ -297,19 +294,145 @@ static inline int variable_test_bit(int nr, volatile const void *addr)
static int test_bit(int nr, const volatile unsigned long *addr);
#endif
-#define test_bit(nr,addr) \
- (__builtin_constant_p(nr) ? \
- constant_test_bit((nr),(addr)) : \
- variable_test_bit((nr),(addr)))
+#define test_bit(nr, addr) \
+ (__builtin_constant_p((nr)) \
+ ? constant_test_bit((nr), (addr)) \
+ : variable_test_bit((nr), (addr)))
+
+/**
+ * __ffs - find first set bit in word
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+ asm("bsf %1,%0"
+ : "=r" (word)
+ : "rm" (word));
+ return word;
+}
+
+/**
+ * ffz - find first zero bit in word
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+ asm("bsf %1,%0"
+ : "=r" (word)
+ : "r" (~word));
+ return word;
+}
+
+/*
+ * __fls: find last set bit in word
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long __fls(unsigned long word)
+{
+ asm("bsr %1,%0"
+ : "=r" (word)
+ : "rm" (word));
+ return word;
+}
+
+#ifdef __KERNEL__
+/**
+ * ffs - find first set bit in word
+ * @x: the word to search
+ *
+ * This is defined the same way as the libc and compiler builtin ffs
+ * routines, therefore differs in spirit from the other bitops.
+ *
+ * ffs(value) returns 0 if value is 0 or the position of the first
+ * set bit if value is nonzero. The first (least significant) bit
+ * is at position 1.
+ */
+static inline int ffs(int x)
+{
+ int r;
+#ifdef CONFIG_X86_CMOV
+ asm("bsfl %1,%0\n\t"
+ "cmovzl %2,%0"
+ : "=r" (r) : "rm" (x), "r" (-1));
+#else
+ asm("bsfl %1,%0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1,%0\n"
+ "1:" : "=r" (r) : "rm" (x));
+#endif
+ return r + 1;
+}
+
+/**
+ * fls - find last set bit in word
+ * @x: the word to search
+ *
+ * This is defined in a similar way as the libc and compiler builtin
+ * ffs, but returns the position of the most significant set bit.
+ *
+ * fls(value) returns 0 if value is 0 or the position of the last
+ * set bit if value is nonzero. The last (most significant) bit is
+ * at position 32.
+ */
+static inline int fls(int x)
+{
+ int r;
+#ifdef CONFIG_X86_CMOV
+ asm("bsrl %1,%0\n\t"
+ "cmovzl %2,%0"
+ : "=&r" (r) : "rm" (x), "rm" (-1));
+#else
+ asm("bsrl %1,%0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1,%0\n"
+ "1:" : "=r" (r) : "rm" (x));
+#endif
+ return r + 1;
+}
+#endif /* __KERNEL__ */
#undef BASE_ADDR
#undef BIT_ADDR
#undef ADDR
-#ifdef CONFIG_X86_32
-# include "bitops_32.h"
-#else
-# include "bitops_64.h"
-#endif
+static inline void set_bit_string(unsigned long *bitmap,
+ unsigned long i, int len)
+{
+ unsigned long end = i + len;
+ while (i < end) {
+ __set_bit(i, bitmap);
+ i++;
+ }
+}
+
+#ifdef __KERNEL__
+
+#include <asm-generic/bitops/sched.h>
+
+#define ARCH_HAS_FAST_MULTIPLIER 1
+
+#include <asm-generic/bitops/hweight.h>
+
+#endif /* __KERNEL__ */
+
+#include <asm-generic/bitops/fls64.h>
+
+#ifdef __KERNEL__
+
+#include <asm-generic/bitops/ext2-non-atomic.h>
+
+#define ext2_set_bit_atomic(lock, nr, addr) \
+ test_and_set_bit((nr), (unsigned long *)(addr))
+#define ext2_clear_bit_atomic(lock, nr, addr) \
+ test_and_clear_bit((nr), (unsigned long *)(addr))
+
+#include <asm-generic/bitops/minix.h>
+#endif /* __KERNEL__ */
#endif /* _ASM_X86_BITOPS_H */
diff --git a/include/asm-x86/bitops_32.h b/include/asm-x86/bitops_32.h
deleted file mode 100644
index 2513a81f82aa..000000000000
--- a/include/asm-x86/bitops_32.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef _I386_BITOPS_H
-#define _I386_BITOPS_H
-
-/*
- * Copyright 1992, Linus Torvalds.
- */
-
-/**
- * find_first_zero_bit - find the first zero bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit number of the first zero bit, not the number of the byte
- * containing a bit.
- */
-static inline int find_first_zero_bit(const unsigned long *addr, unsigned size)
-{
- int d0, d1, d2;
- int res;
-
- if (!size)
- return 0;
- /* This looks at memory.
- * Mark it volatile to tell gcc not to move it around
- */
- asm volatile("movl $-1,%%eax\n\t"
- "xorl %%edx,%%edx\n\t"
- "repe; scasl\n\t"
- "je 1f\n\t"
- "xorl -4(%%edi),%%eax\n\t"
- "subl $4,%%edi\n\t"
- "bsfl %%eax,%%edx\n"
- "1:\tsubl %%ebx,%%edi\n\t"
- "shll $3,%%edi\n\t"
- "addl %%edi,%%edx"
- : "=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
- : "1" ((size + 31) >> 5), "2" (addr),
- "b" (addr) : "memory");
- return res;
-}
-
-/**
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bit number to start searching at
- * @size: The maximum size to search
- */
-int find_next_zero_bit(const unsigned long *addr, int size, int offset);
-
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline unsigned long __ffs(unsigned long word)
-{
- __asm__("bsfl %1,%0"
- :"=r" (word)
- :"rm" (word));
- return word;
-}
-
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit number of the first set bit, not the number of the byte
- * containing a bit.
- */
-static inline unsigned find_first_bit(const unsigned long *addr, unsigned size)
-{
- unsigned x = 0;
-
- while (x < size) {
- unsigned long val = *addr++;
- if (val)
- return __ffs(val) + x;
- x += sizeof(*addr) << 3;
- }
- return x;
-}
-
-/**
- * find_next_bit - find the first set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bit number to start searching at
- * @size: The maximum size to search
- */
-int find_next_bit(const unsigned long *addr, int size, int offset);
-
-/**
- * ffz - find first zero in word.
- * @word: The word to search
- *
- * Undefined if no zero exists, so code should check against ~0UL first.
- */
-static inline unsigned long ffz(unsigned long word)
-{
- __asm__("bsfl %1,%0"
- :"=r" (word)
- :"r" (~word));
- return word;
-}
-
-#ifdef __KERNEL__
-
-#include <asm-generic/bitops/sched.h>
-
-/**
- * ffs - find first bit set
- * @x: the word to search
- *
- * This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz() (man ffs).
- */
-static inline int ffs(int x)
-{
- int r;
-
- __asm__("bsfl %1,%0\n\t"
- "jnz 1f\n\t"
- "movl $-1,%0\n"
- "1:" : "=r" (r) : "rm" (x));
- return r+1;
-}
-
-/**
- * fls - find last bit set
- * @x: the word to search
- *
- * This is defined the same way as ffs().
- */
-static inline int fls(int x)
-{
- int r;
-
- __asm__("bsrl %1,%0\n\t"
- "jnz 1f\n\t"
- "movl $-1,%0\n"
- "1:" : "=r" (r) : "rm" (x));
- return r+1;
-}
-
-#include <asm-generic/bitops/hweight.h>
-
-#endif /* __KERNEL__ */
-
-#include <asm-generic/bitops/fls64.h>
-
-#ifdef __KERNEL__
-
-#include <asm-generic/bitops/ext2-non-atomic.h>
-
-#define ext2_set_bit_atomic(lock, nr, addr) \
- test_and_set_bit((nr), (unsigned long *)(addr))
-#define ext2_clear_bit_atomic(lock, nr, addr) \
- test_and_clear_bit((nr), (unsigned long *)(addr))
-
-#include <asm-generic/bitops/minix.h>
-
-#endif /* __KERNEL__ */
-
-#endif /* _I386_BITOPS_H */
diff --git a/include/asm-x86/bitops_64.h b/include/asm-x86/bitops_64.h
deleted file mode 100644
index 365f8207ea59..000000000000
--- a/include/asm-x86/bitops_64.h
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef _X86_64_BITOPS_H
-#define _X86_64_BITOPS_H
-
-/*
- * Copyright 1992, Linus Torvalds.
- */
-
-extern long find_first_zero_bit(const unsigned long *addr, unsigned long size);
-extern long find_next_zero_bit(const unsigned long *addr, long size, long offset);
-extern long find_first_bit(const unsigned long *addr, unsigned long size);
-extern long find_next_bit(const unsigned long *addr, long size, long offset);
-
-/* return index of first bet set in val or max when no bit is set */
-static inline long __scanbit(unsigned long val, unsigned long max)
-{
- asm("bsfq %1,%0 ; cmovz %2,%0" : "=&r" (val) : "r" (val), "r" (max));
- return val;
-}
-
-#define find_next_bit(addr,size,off) \
-((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ? \
- ((off) + (__scanbit((*(unsigned long *)addr) >> (off),(size)-(off)))) : \
- find_next_bit(addr,size,off)))
-
-#define find_next_zero_bit(addr,size,off) \
-((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ? \
- ((off)+(__scanbit(~(((*(unsigned long *)addr)) >> (off)),(size)-(off)))) : \
- find_next_zero_bit(addr,size,off)))
-
-#define find_first_bit(addr, size) \
- ((__builtin_constant_p((size)) && (size) <= BITS_PER_LONG \
- ? (__scanbit(*(unsigned long *)(addr), (size))) \
- : find_first_bit((addr), (size))))
-
-#define find_first_zero_bit(addr, size) \
- ((__builtin_constant_p((size)) && (size) <= BITS_PER_LONG \
- ? (__scanbit(~*(unsigned long *)(addr), (size))) \
- : find_first_zero_bit((addr), (size))))
-
-static inline void set_bit_string(unsigned long *bitmap, unsigned long i,
- int len)
-{
- unsigned long end = i + len;
- while (i < end) {
- __set_bit(i, bitmap);
- i++;
- }
-}
-
-/**
- * ffz - find first zero in word.
- * @word: The word to search
- *
- * Undefined if no zero exists, so code should check against ~0UL first.
- */
-static inline unsigned long ffz(unsigned long word)
-{
- __asm__("bsfq %1,%0"
- :"=r" (word)
- :"r" (~word));
- return word;
-}
-
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline unsigned long __ffs(unsigned long word)
-{
- __asm__("bsfq %1,%0"
- :"=r" (word)
- :"rm" (word));
- return word;
-}
-
-/*
- * __fls: find last bit set.
- * @word: The word to search
- *
- * Undefined if no zero exists, so code should check against ~0UL first.
- */
-static inline unsigned long __fls(unsigned long word)
-{
- __asm__("bsrq %1,%0"
- :"=r" (word)
- :"rm" (word));
- return word;
-}
-
-#ifdef __KERNEL__
-
-#include <asm-generic/bitops/sched.h>
-
-/**
- * ffs - find first bit set
- * @x: the word to search
- *
- * This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
- */
-static inline int ffs(int x)
-{
- int r;
-
- __asm__("bsfl %1,%0\n\t"
- "cmovzl %2,%0"
- : "=r" (r) : "rm" (x), "r" (-1));
- return r+1;
-}
-
-/**
- * fls64 - find last bit set in 64 bit word
- * @x: the word to search
- *
- * This is defined the same way as fls.
- */
-static inline int fls64(__u64 x)
-{
- if (x == 0)
- return 0;
- return __fls(x) + 1;
-}
-
-/**
- * fls - find last bit set
- * @x: the word to search
- *
- * This is defined the same way as ffs.
- */
-static inline int fls(int x)
-{
- int r;
-
- __asm__("bsrl %1,%0\n\t"
- "cmovzl %2,%0"
- : "=&r" (r) : "rm" (x), "rm" (-1));
- return r+1;
-}
-
-#define ARCH_HAS_FAST_MULTIPLIER 1
-
-#include <asm-generic/bitops/hweight.h>
-
-#endif /* __KERNEL__ */
-
-#ifdef __KERNEL__
-
-#include <asm-generic/bitops/ext2-non-atomic.h>
-
-#define ext2_set_bit_atomic(lock, nr, addr) \
- test_and_set_bit((nr), (unsigned long *)(addr))
-#define ext2_clear_bit_atomic(lock, nr, addr) \
- test_and_clear_bit((nr), (unsigned long *)(addr))
-
-#include <asm-generic/bitops/minix.h>
-
-#endif /* __KERNEL__ */
-
-#endif /* _X86_64_BITOPS_H */
diff --git a/include/asm-x86/bootparam.h b/include/asm-x86/bootparam.h
index 51151356840f..e8659909e5f6 100644
--- a/include/asm-x86/bootparam.h
+++ b/include/asm-x86/bootparam.h
@@ -9,6 +9,17 @@
#include <asm/ist.h>
#include <video/edid.h>
+/* setup data types */
+#define SETUP_NONE 0
+
+/* extensible setup data list node */
+struct setup_data {
+ u64 next;
+ u32 type;
+ u32 len;
+ u8 data[0];
+};
+
struct setup_header {
__u8 setup_sects;
__u16 root_flags;
@@ -46,6 +57,9 @@ struct setup_header {
__u32 cmdline_size;
__u32 hardware_subarch;
__u64 hardware_subarch_data;
+ __u32 payload_offset;
+ __u32 payload_length;
+ __u64 setup_data;
} __attribute__((packed));
struct sys_desc_table {
diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h
index f478c57eb060..71c4d685d30d 100644
--- a/include/asm-x86/e820_64.h
+++ b/include/asm-x86/e820_64.h
@@ -48,7 +48,8 @@ extern struct e820map e820;
extern void update_e820(void);
extern void reserve_early(unsigned long start, unsigned long end, char *name);
-extern void early_res_to_bootmem(void);
+extern void free_early(unsigned long start, unsigned long end);
+extern void early_res_to_bootmem(unsigned long start, unsigned long end);
#endif/*!__ASSEMBLY__*/
diff --git a/include/asm-x86/fixmap.h b/include/asm-x86/fixmap.h
index 382eb271a892..5bd206973dca 100644
--- a/include/asm-x86/fixmap.h
+++ b/include/asm-x86/fixmap.h
@@ -1,5 +1,13 @@
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
#ifdef CONFIG_X86_32
# include "fixmap_32.h"
#else
# include "fixmap_64.h"
#endif
+
+#define clear_fixmap(idx) \
+ __set_fixmap(idx, 0, __pgprot(0))
+
+#endif
diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h
index eb1665125c44..4b96148e90c1 100644
--- a/include/asm-x86/fixmap_32.h
+++ b/include/asm-x86/fixmap_32.h
@@ -10,8 +10,8 @@
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
*/
-#ifndef _ASM_FIXMAP_H
-#define _ASM_FIXMAP_H
+#ifndef _ASM_FIXMAP_32_H
+#define _ASM_FIXMAP_32_H
/* used by vmalloc.c, vsyscall.lds.S.
@@ -121,9 +121,6 @@ extern void reserve_top_address(unsigned long reserve);
#define set_fixmap_nocache(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
-#define clear_fixmap(idx) \
- __set_fixmap(idx, 0, __pgprot(0))
-
#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
diff --git a/include/asm-x86/fixmap_64.h b/include/asm-x86/fixmap_64.h
index f3d76858c0e6..355d26a75a82 100644
--- a/include/asm-x86/fixmap_64.h
+++ b/include/asm-x86/fixmap_64.h
@@ -8,8 +8,8 @@
* Copyright (C) 1998 Ingo Molnar
*/
-#ifndef _ASM_FIXMAP_H
-#define _ASM_FIXMAP_H
+#ifndef _ASM_FIXMAP_64_H
+#define _ASM_FIXMAP_64_H
#include <linux/kernel.h>
#include <asm/apicdef.h>
diff --git a/include/asm-x86/geode.h b/include/asm-x86/geode.h
index 9870cc1f2f8f..7154dc4de951 100644
--- a/include/asm-x86/geode.h
+++ b/include/asm-x86/geode.h
@@ -30,7 +30,13 @@ extern int geode_get_dev_base(unsigned int dev);
/* MSRS */
-#define GX_GLCP_SYS_RSTPLL 0x4C000014
+#define MSR_GLIU_P2D_RO0 0x10000029
+
+#define MSR_LX_GLD_MSR_CONFIG 0x48002001
+#define MSR_LX_MSR_PADSEL 0x48002011 /* NOT 0x48000011; the data
+ * sheet has the wrong value */
+#define MSR_GLCP_SYS_RSTPLL 0x4C000014
+#define MSR_GLCP_DOTPLL 0x4C000015
#define MSR_LBAR_SMB 0x5140000B
#define MSR_LBAR_GPIO 0x5140000C
@@ -45,8 +51,14 @@ extern int geode_get_dev_base(unsigned int dev);
#define MSR_PIC_ZSEL_LOW 0x51400022
#define MSR_PIC_ZSEL_HIGH 0x51400023
-#define MFGPT_IRQ_MSR 0x51400028
-#define MFGPT_NR_MSR 0x51400029
+#define MSR_MFGPT_IRQ 0x51400028
+#define MSR_MFGPT_NR 0x51400029
+#define MSR_MFGPT_SETUP 0x5140002B
+
+#define MSR_LX_SPARE_MSR 0x80000011 /* DC-specific */
+
+#define MSR_GX_GLD_MSR_CONFIG 0xC0002001
+#define MSR_GX_MSR_PADSEL 0xC0002011
/* Resource Sizes */
@@ -93,6 +105,15 @@ extern int geode_get_dev_base(unsigned int dev);
#define PM_AWKD 0x50
#define PM_SSC 0x54
+/* VSA2 magic values */
+
+#define VSA_VRC_INDEX 0xAC1C
+#define VSA_VRC_DATA 0xAC1E
+#define VSA_VR_UNLOCK 0xFC53 /* unlock virtual register */
+#define VSA_VR_SIGNATURE 0x0003
+#define VSA_VR_MEM_SIZE 0x0200
+#define VSA_SIG 0x4132 /* signature is ascii 'VSA2' */
+
/* GPIO */
#define GPIO_OUTPUT_VAL 0x00
@@ -164,6 +185,17 @@ static inline int is_geode(void)
return (is_geode_gx() || is_geode_lx());
}
+/*
+ * The VSA has virtual registers that we can query for a signature.
+ */
+static inline int geode_has_vsa2(void)
+{
+ outw(VSA_VR_UNLOCK, VSA_VRC_INDEX);
+ outw(VSA_VR_SIGNATURE, VSA_VRC_INDEX);
+
+ return (inw(VSA_VRC_DATA) == VSA_SIG);
+}
+
/* MFGPTs */
#define MFGPT_MAX_TIMERS 8
diff --git a/include/asm-x86/hugetlb.h b/include/asm-x86/hugetlb.h
new file mode 100644
index 000000000000..14171a4924f6
--- /dev/null
+++ b/include/asm-x86/hugetlb.h
@@ -0,0 +1,91 @@
+#ifndef _ASM_X86_HUGETLB_H
+#define _ASM_X86_HUGETLB_H
+
+#include <asm/page.h>
+
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr,
+ unsigned long len) {
+ return 0;
+}
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) {
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather **tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ set_pte_at(mm, addr, ptep, pte);
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+ return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+#endif /* _ASM_X86_HUGETLB_H */
diff --git a/include/asm-x86/io.h b/include/asm-x86/io.h
index 7b292d386713..d5b11f60dbd0 100644
--- a/include/asm-x86/io.h
+++ b/include/asm-x86/io.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_X86_IO_H
+#define _ASM_X86_IO_H
+
#define ARCH_HAS_IOREMAP_WC
#ifdef CONFIG_X86_32
@@ -5,7 +8,12 @@
#else
# include "io_64.h"
#endif
+
+extern void *xlate_dev_mem_ptr(unsigned long phys);
+extern void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
+
extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
unsigned long prot_val);
extern void __iomem *ioremap_wc(unsigned long offset, unsigned long size);
+#endif /* _ASM_X86_IO_H */
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index 509045f5fda2..6e73467a4fb1 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -49,12 +49,6 @@
#include <linux/vmalloc.h>
/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p) __va(p)
-
-/*
* Convert a virtual cached pointer to an uncached pointer
*/
#define xlate_dev_kmem_ptr(p) p
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index c2f5eef47b88..0930bedf9e4d 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -308,12 +308,6 @@ extern int iommu_bio_merge;
#define BIO_VMERGE_BOUNDARY iommu_bio_merge
/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p) __va(p)
-
-/*
* Convert a virtual cached pointer to an uncached pointer
*/
#define xlate_dev_kmem_ptr(p) p
diff --git a/include/asm-x86/io_apic.h b/include/asm-x86/io_apic.h
index 0c9e17c73e05..d593e14f0341 100644
--- a/include/asm-x86/io_apic.h
+++ b/include/asm-x86/io_apic.h
@@ -1,7 +1,7 @@
#ifndef __ASM_IO_APIC_H
#define __ASM_IO_APIC_H
-#include <asm/types.h>
+#include <linux/types.h>
#include <asm/mpspec.h>
#include <asm/apicdef.h>
@@ -110,11 +110,13 @@ extern int nr_ioapic_registers[MAX_IO_APICS];
* MP-BIOS irq configuration table structures:
*/
+#define MP_MAX_IOAPIC_PIN 127
+
struct mp_ioapic_routing {
int apic_id;
int gsi_base;
int gsi_end;
- u32 pin_programmed[4];
+ DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
};
/* I/O APIC entries */
diff --git a/include/asm-x86/kvm.h b/include/asm-x86/kvm.h
index 7a71120426a3..80eefef2cc76 100644
--- a/include/asm-x86/kvm.h
+++ b/include/asm-x86/kvm.h
@@ -188,4 +188,45 @@ struct kvm_cpuid2 {
struct kvm_cpuid_entry2 entries[0];
};
+/* for KVM_GET_PIT and KVM_SET_PIT */
+struct kvm_pit_channel_state {
+ __u32 count; /* can be 65536 */
+ __u16 latched_count;
+ __u8 count_latched;
+ __u8 status_latched;
+ __u8 status;
+ __u8 read_state;
+ __u8 write_state;
+ __u8 write_latch;
+ __u8 rw_mode;
+ __u8 mode;
+ __u8 bcd;
+ __u8 gate;
+ __s64 count_load_time;
+};
+
+struct kvm_pit_state {
+ struct kvm_pit_channel_state channels[3];
+};
+
+#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
+#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)
+#define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04)
+#define KVM_TRC_IO_READ (KVM_TRC_HANDLER + 0x05)
+#define KVM_TRC_IO_WRITE (KVM_TRC_HANDLER + 0x06)
+#define KVM_TRC_CR_READ (KVM_TRC_HANDLER + 0x07)
+#define KVM_TRC_CR_WRITE (KVM_TRC_HANDLER + 0x08)
+#define KVM_TRC_DR_READ (KVM_TRC_HANDLER + 0x09)
+#define KVM_TRC_DR_WRITE (KVM_TRC_HANDLER + 0x0A)
+#define KVM_TRC_MSR_READ (KVM_TRC_HANDLER + 0x0B)
+#define KVM_TRC_MSR_WRITE (KVM_TRC_HANDLER + 0x0C)
+#define KVM_TRC_CPUID (KVM_TRC_HANDLER + 0x0D)
+#define KVM_TRC_INTR (KVM_TRC_HANDLER + 0x0E)
+#define KVM_TRC_NMI (KVM_TRC_HANDLER + 0x0F)
+#define KVM_TRC_VMMCALL (KVM_TRC_HANDLER + 0x10)
+#define KVM_TRC_HLT (KVM_TRC_HANDLER + 0x11)
+#define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12)
+#define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13)
+#define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14)
+
#endif
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index 68ee390b2844..9d963cd6533c 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -20,6 +20,13 @@
#include <asm/desc.h>
+#define KVM_MAX_VCPUS 16
+#define KVM_MEMORY_SLOTS 32
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 4
+
+#define KVM_PIO_PAGE_OFFSET 1
+
#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS | \
@@ -39,6 +46,13 @@
#define INVALID_PAGE (~(hpa_t)0)
#define UNMAPPED_GVA (~(gpa_t)0)
+/* shadow tables are PAE even on non-PAE hosts */
+#define KVM_HPAGE_SHIFT 21
+#define KVM_HPAGE_SIZE (1UL << KVM_HPAGE_SHIFT)
+#define KVM_HPAGE_MASK (~(KVM_HPAGE_SIZE - 1))
+
+#define KVM_PAGES_PER_HPAGE (KVM_HPAGE_SIZE / PAGE_SIZE)
+
#define DE_VECTOR 0
#define UD_VECTOR 6
#define NM_VECTOR 7
@@ -48,6 +62,7 @@
#define SS_VECTOR 12
#define GP_VECTOR 13
#define PF_VECTOR 14
+#define MC_VECTOR 18
#define SELECTOR_TI_MASK (1 << 2)
#define SELECTOR_RPL_MASK 0x03
@@ -58,7 +73,8 @@
#define KVM_PERMILLE_MMU_PAGES 20
#define KVM_MIN_ALLOC_MMU_PAGES 64
-#define KVM_NUM_MMU_PAGES 1024
+#define KVM_MMU_HASH_SHIFT 10
+#define KVM_NUM_MMU_PAGES (1 << KVM_MMU_HASH_SHIFT)
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
#define KVM_MAX_CPUID_ENTRIES 40
@@ -106,6 +122,12 @@ enum {
#define KVM_NR_MEM_OBJS 40
+struct kvm_guest_debug {
+ int enabled;
+ unsigned long bp[4];
+ int singlestep;
+};
+
/*
* We don't want allocation failures within the mmu code, so we preallocate
* enough memory for a single page fault in a cache.
@@ -140,6 +162,7 @@ union kvm_mmu_page_role {
unsigned pad_for_nice_hex_output:6;
unsigned metaphysical:1;
unsigned access:3;
+ unsigned invalid:1;
};
};
@@ -204,11 +227,6 @@ struct kvm_vcpu_arch {
u64 shadow_efer;
u64 apic_base;
struct kvm_lapic *apic; /* kernel irqchip context */
-#define VCPU_MP_STATE_RUNNABLE 0
-#define VCPU_MP_STATE_UNINITIALIZED 1
-#define VCPU_MP_STATE_INIT_RECEIVED 2
-#define VCPU_MP_STATE_SIPI_RECEIVED 3
-#define VCPU_MP_STATE_HALTED 4
int mp_state;
int sipi_vector;
u64 ia32_misc_enable_msr;
@@ -226,8 +244,9 @@ struct kvm_vcpu_arch {
u64 *last_pte_updated;
struct {
- gfn_t gfn; /* presumed gfn during guest pte update */
- struct page *page; /* page corresponding to that gfn */
+ gfn_t gfn; /* presumed gfn during guest pte update */
+ pfn_t pfn; /* pfn corresponding to that gfn */
+ int largepage;
} update_pte;
struct i387_fxsave_struct host_fx_image;
@@ -261,6 +280,11 @@ struct kvm_vcpu_arch {
/* emulate context */
struct x86_emulate_ctxt emulate_ctxt;
+
+ gpa_t time;
+ struct kvm_vcpu_time_info hv_clock;
+ unsigned int time_offset;
+ struct page *time_page;
};
struct kvm_mem_alias {
@@ -283,10 +307,13 @@ struct kvm_arch{
struct list_head active_mmu_pages;
struct kvm_pic *vpic;
struct kvm_ioapic *vioapic;
+ struct kvm_pit *vpit;
int round_robin_prev_vcpu;
unsigned int tss_addr;
struct page *apic_access_page;
+
+ gpa_t wall_clock;
};
struct kvm_vm_stat {
@@ -298,6 +325,7 @@ struct kvm_vm_stat {
u32 mmu_recycled;
u32 mmu_cache_miss;
u32 remote_tlb_flush;
+ u32 lpages;
};
struct kvm_vcpu_stat {
@@ -320,6 +348,7 @@ struct kvm_vcpu_stat {
u32 fpu_reload;
u32 insn_emulation;
u32 insn_emulation_fail;
+ u32 hypercalls;
};
struct descriptor_table {
@@ -355,6 +384,7 @@ struct kvm_x86_ops {
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
void (*get_segment)(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
+ int (*get_cpl)(struct kvm_vcpu *vcpu);
void (*set_segment)(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
@@ -410,6 +440,15 @@ void kvm_mmu_zap_all(struct kvm *kvm);
unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm);
void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages);
+int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
+
+int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
+ const void *val, int bytes);
+int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
+ gpa_t addr, unsigned long *ret);
+
+extern bool tdp_enabled;
+
enum emulation_result {
EMULATE_DONE, /* no further processing */
EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
@@ -429,6 +468,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
unsigned long *rflags);
+void kvm_enable_efer_bits(u64);
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
@@ -448,12 +488,14 @@ int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr,
int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
unsigned long value);
-void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
-void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
-void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
-void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
-unsigned long get_cr8(struct kvm_vcpu *vcpu);
-void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason);
+
+void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
+void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
+void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8);
+unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu);
+void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
@@ -491,6 +533,8 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu);
int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code);
+void kvm_enable_tdp(void);
+
int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
int complete_pio(struct kvm_vcpu *vcpu);
@@ -600,6 +644,7 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)
#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4"
#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4"
#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_INVVPID ".byte 0x66, 0x0f, 0x38, 0x81, 0x08"
#define MSR_IA32_TIME_STAMP_COUNTER 0x010
@@ -610,4 +655,30 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)
#define RMODE_TSS_SIZE \
(TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
+enum {
+ TASK_SWITCH_CALL = 0,
+ TASK_SWITCH_IRET = 1,
+ TASK_SWITCH_JMP = 2,
+ TASK_SWITCH_GATE = 3,
+};
+
+#define KVMTRACE_5D(evt, vcpu, d1, d2, d3, d4, d5, name) \
+ trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+ vcpu, 5, d1, d2, d3, d4, d5)
+#define KVMTRACE_4D(evt, vcpu, d1, d2, d3, d4, name) \
+ trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+ vcpu, 4, d1, d2, d3, d4, 0)
+#define KVMTRACE_3D(evt, vcpu, d1, d2, d3, name) \
+ trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+ vcpu, 3, d1, d2, d3, 0, 0)
+#define KVMTRACE_2D(evt, vcpu, d1, d2, name) \
+ trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+ vcpu, 2, d1, d2, 0, 0, 0)
+#define KVMTRACE_1D(evt, vcpu, d1, name) \
+ trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+ vcpu, 1, d1, 0, 0, 0, 0)
+#define KVMTRACE_0D(evt, vcpu, name) \
+ trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \
+ vcpu, 0, 0, 0, 0, 0, 0)
+
#endif
diff --git a/include/asm-x86/kvm_para.h b/include/asm-x86/kvm_para.h
index c6f3fd8d8c53..509845942070 100644
--- a/include/asm-x86/kvm_para.h
+++ b/include/asm-x86/kvm_para.h
@@ -10,10 +10,65 @@
* paravirtualization, the appropriate feature bit should be checked.
*/
#define KVM_CPUID_FEATURES 0x40000001
+#define KVM_FEATURE_CLOCKSOURCE 0
+#define KVM_FEATURE_NOP_IO_DELAY 1
+#define KVM_FEATURE_MMU_OP 2
+
+#define MSR_KVM_WALL_CLOCK 0x11
+#define MSR_KVM_SYSTEM_TIME 0x12
+
+#define KVM_MAX_MMU_OP_BATCH 32
+
+/* Operations for KVM_HC_MMU_OP */
+#define KVM_MMU_OP_WRITE_PTE 1
+#define KVM_MMU_OP_FLUSH_TLB 2
+#define KVM_MMU_OP_RELEASE_PT 3
+
+/* Payload for KVM_HC_MMU_OP */
+struct kvm_mmu_op_header {
+ __u32 op;
+ __u32 pad;
+};
+
+struct kvm_mmu_op_write_pte {
+ struct kvm_mmu_op_header header;
+ __u64 pte_phys;
+ __u64 pte_val;
+};
+
+struct kvm_mmu_op_flush_tlb {
+ struct kvm_mmu_op_header header;
+};
+
+struct kvm_mmu_op_release_pt {
+ struct kvm_mmu_op_header header;
+ __u64 pt_phys;
+};
#ifdef __KERNEL__
#include <asm/processor.h>
+/* xen binary-compatible interface. See xen headers for details */
+struct kvm_vcpu_time_info {
+ uint32_t version;
+ uint32_t pad0;
+ uint64_t tsc_timestamp;
+ uint64_t system_time;
+ uint32_t tsc_to_system_mul;
+ int8_t tsc_shift;
+ int8_t pad[3];
+} __attribute__((__packed__)); /* 32 bytes */
+
+struct kvm_wall_clock {
+ uint32_t wc_version;
+ uint32_t wc_sec;
+ uint32_t wc_nsec;
+} __attribute__((__packed__));
+
+
+extern void kvmclock_init(void);
+
+
/* This instruction is vmcall. On non-VT architectures, it will generate a
* trap that we will then rewrite to the appropriate instruction.
*/
diff --git a/include/asm-x86/mach-default/smpboot_hooks.h b/include/asm-x86/mach-default/smpboot_hooks.h
index 3ff2c5bff93a..56d0e1fa0258 100644
--- a/include/asm-x86/mach-default/smpboot_hooks.h
+++ b/include/asm-x86/mach-default/smpboot_hooks.h
@@ -33,7 +33,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
*((volatile long *) phys_to_virt(0x467)) = 0;
}
-static inline void smpboot_setup_io_apic(void)
+static inline void __init smpboot_setup_io_apic(void)
{
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h
index 6724a4bc6b7a..b381f4a5a0bd 100644
--- a/include/asm-x86/page.h
+++ b/include/asm-x86/page.h
@@ -47,6 +47,7 @@
#ifndef __ASSEMBLY__
extern int page_is_ram(unsigned long pagenr);
+extern int devmem_is_allowed(unsigned long pagenr);
extern unsigned long max_pfn_mapped;
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index 3d419398499b..0f13b945e240 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -220,11 +220,13 @@ struct pv_mmu_ops {
unsigned long va);
/* Hooks for allocating/releasing pagetable pages */
- void (*alloc_pt)(struct mm_struct *mm, u32 pfn);
- void (*alloc_pd)(struct mm_struct *mm, u32 pfn);
- void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
- void (*release_pt)(u32 pfn);
- void (*release_pd)(u32 pfn);
+ void (*alloc_pte)(struct mm_struct *mm, u32 pfn);
+ void (*alloc_pmd)(struct mm_struct *mm, u32 pfn);
+ void (*alloc_pmd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
+ void (*alloc_pud)(struct mm_struct *mm, u32 pfn);
+ void (*release_pte)(u32 pfn);
+ void (*release_pmd)(u32 pfn);
+ void (*release_pud)(u32 pfn);
/* Pagetable manipulation functions */
void (*set_pte)(pte_t *ptep, pte_t pteval);
@@ -910,28 +912,37 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va);
}
-static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
+static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned pfn)
{
- PVOP_VCALL2(pv_mmu_ops.alloc_pt, mm, pfn);
+ PVOP_VCALL2(pv_mmu_ops.alloc_pte, mm, pfn);
}
-static inline void paravirt_release_pt(unsigned pfn)
+static inline void paravirt_release_pte(unsigned pfn)
{
- PVOP_VCALL1(pv_mmu_ops.release_pt, pfn);
+ PVOP_VCALL1(pv_mmu_ops.release_pte, pfn);
}
-static inline void paravirt_alloc_pd(struct mm_struct *mm, unsigned pfn)
+static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned pfn)
{
- PVOP_VCALL2(pv_mmu_ops.alloc_pd, mm, pfn);
+ PVOP_VCALL2(pv_mmu_ops.alloc_pmd, mm, pfn);
}
-static inline void paravirt_alloc_pd_clone(unsigned pfn, unsigned clonepfn,
- unsigned start, unsigned count)
+static inline void paravirt_alloc_pmd_clone(unsigned pfn, unsigned clonepfn,
+ unsigned start, unsigned count)
{
- PVOP_VCALL4(pv_mmu_ops.alloc_pd_clone, pfn, clonepfn, start, count);
+ PVOP_VCALL4(pv_mmu_ops.alloc_pmd_clone, pfn, clonepfn, start, count);
}
-static inline void paravirt_release_pd(unsigned pfn)
+static inline void paravirt_release_pmd(unsigned pfn)
{
- PVOP_VCALL1(pv_mmu_ops.release_pd, pfn);
+ PVOP_VCALL1(pv_mmu_ops.release_pmd, pfn);
+}
+
+static inline void paravirt_alloc_pud(struct mm_struct *mm, unsigned pfn)
+{
+ PVOP_VCALL2(pv_mmu_ops.alloc_pud, mm, pfn);
+}
+static inline void paravirt_release_pud(unsigned pfn)
+{
+ PVOP_VCALL1(pv_mmu_ops.release_pud, pfn);
}
#ifdef CONFIG_HIGHPTE
diff --git a/include/asm-x86/pgalloc.h b/include/asm-x86/pgalloc.h
index 5886eed05886..91e4641f3f31 100644
--- a/include/asm-x86/pgalloc.h
+++ b/include/asm-x86/pgalloc.h
@@ -1,5 +1,110 @@
-#ifdef CONFIG_X86_32
-# include "pgalloc_32.h"
+#ifndef _ASM_X86_PGALLOC_H
+#define _ASM_X86_PGALLOC_H
+
+#include <linux/threads.h>
+#include <linux/mm.h> /* for struct page */
+#include <linux/pagemap.h>
+
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
#else
-# include "pgalloc_64.h"
+static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned long pfn) {}
+static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn) {}
+static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,
+ unsigned long start, unsigned long count) {}
+static inline void paravirt_alloc_pud(struct mm_struct *mm, unsigned long pfn) {}
+static inline void paravirt_release_pte(unsigned long pfn) {}
+static inline void paravirt_release_pmd(unsigned long pfn) {}
+static inline void paravirt_release_pud(unsigned long pfn) {}
#endif
+
+/*
+ * Allocate and free page tables.
+ */
+extern pgd_t *pgd_alloc(struct mm_struct *);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
+
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
+extern pgtable_t pte_alloc_one(struct mm_struct *, unsigned long);
+
+/* Should really implement gc for free page table pages. This could be
+ done with a reference count in struct page. */
+
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+ BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
+ free_page((unsigned long)pte);
+}
+
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
+{
+ __free_page(pte);
+}
+
+extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
+
+static inline void pmd_populate_kernel(struct mm_struct *mm,
+ pmd_t *pmd, pte_t *pte)
+{
+ paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT);
+ set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE));
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+ struct page *pte)
+{
+ unsigned long pfn = page_to_pfn(pte);
+
+ paravirt_alloc_pte(mm, pfn);
+ set_pmd(pmd, __pmd(((pteval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE));
+}
+
+#define pmd_pgtable(pmd) pmd_page(pmd)
+
+#if PAGETABLE_LEVELS > 2
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+ BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
+ free_page((unsigned long)pmd);
+}
+
+extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
+
+#ifdef CONFIG_X86_PAE
+extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
+#else /* !CONFIG_X86_PAE */
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+ paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT);
+ set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
+}
+#endif /* CONFIG_X86_PAE */
+
+#if PAGETABLE_LEVELS > 3
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
+{
+ paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT);
+ set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
+}
+
+static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
+{
+ BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
+ free_page((unsigned long)pud);
+}
+
+extern void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud);
+#endif /* PAGETABLE_LEVELS > 3 */
+#endif /* PAGETABLE_LEVELS > 2 */
+
+#endif /* _ASM_X86_PGALLOC_H */
diff --git a/include/asm-x86/pgalloc_32.h b/include/asm-x86/pgalloc_32.h
deleted file mode 100644
index 6bea6e5b5ee5..000000000000
--- a/include/asm-x86/pgalloc_32.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef _I386_PGALLOC_H
-#define _I386_PGALLOC_H
-
-#include <linux/threads.h>
-#include <linux/mm.h> /* for struct page */
-#include <linux/pagemap.h>
-#include <asm/tlb.h>
-#include <asm-generic/tlb.h>
-
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define paravirt_alloc_pt(mm, pfn) do { } while (0)
-#define paravirt_alloc_pd(mm, pfn) do { } while (0)
-#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0)
-#define paravirt_release_pt(pfn) do { } while (0)
-#define paravirt_release_pd(pfn) do { } while (0)
-#endif
-
-static inline void pmd_populate_kernel(struct mm_struct *mm,
- pmd_t *pmd, pte_t *pte)
-{
- paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT);
- set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE));
-}
-
-static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
-{
- unsigned long pfn = page_to_pfn(pte);
-
- paravirt_alloc_pt(mm, pfn);
- set_pmd(pmd, __pmd(((pteval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE));
-}
-#define pmd_pgtable(pmd) pmd_page(pmd)
-
-/*
- * Allocate and free page tables.
- */
-extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
-
-extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
-extern pgtable_t pte_alloc_one(struct mm_struct *, unsigned long);
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
- free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
- pgtable_page_dtor(pte);
- __free_page(pte);
-}
-
-
-extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
-
-#ifdef CONFIG_X86_PAE
-/*
- * In the PAE case we free the pmds as part of the pgd.
- */
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
- return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
-{
- BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
- free_page((unsigned long)pmd);
-}
-
-extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
-
-static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
-{
- paravirt_alloc_pd(mm, __pa(pmd) >> PAGE_SHIFT);
-
- /* Note: almost everything apart from _PAGE_PRESENT is
- reserved at the pmd (PDPT) level. */
- set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
-
- /*
- * According to Intel App note "TLBs, Paging-Structure Caches,
- * and Their Invalidation", April 2007, document 317080-001,
- * section 8.1: in PAE mode we explicitly have to flush the
- * TLB via cr3 if the top-level pgd is changed...
- */
- if (mm == current->active_mm)
- write_cr3(read_cr3());
-}
-#endif /* CONFIG_X86_PAE */
-
-#endif /* _I386_PGALLOC_H */
diff --git a/include/asm-x86/pgalloc_64.h b/include/asm-x86/pgalloc_64.h
deleted file mode 100644
index 8d6722320dcc..000000000000
--- a/include/asm-x86/pgalloc_64.h
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef _X86_64_PGALLOC_H
-#define _X86_64_PGALLOC_H
-
-#include <asm/pda.h>
-#include <linux/threads.h>
-#include <linux/mm.h>
-
-#define pmd_populate_kernel(mm, pmd, pte) \
- set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
-#define pud_populate(mm, pud, pmd) \
- set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)))
-#define pgd_populate(mm, pgd, pud) \
- set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)))
-
-#define pmd_pgtable(pmd) pmd_page(pmd)
-
-static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
-{
- set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
-}
-
-static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
-{
- BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
- free_page((unsigned long)pmd);
-}
-
-static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
-{
- return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
- return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline void pud_free(struct mm_struct *mm, pud_t *pud)
-{
- BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
- free_page((unsigned long)pud);
-}
-
-static inline void pgd_list_add(pgd_t *pgd)
-{
- struct page *page = virt_to_page(pgd);
- unsigned long flags;
-
- spin_lock_irqsave(&pgd_lock, flags);
- list_add(&page->lru, &pgd_list);
- spin_unlock_irqrestore(&pgd_lock, flags);
-}
-
-static inline void pgd_list_del(pgd_t *pgd)
-{
- struct page *page = virt_to_page(pgd);
- unsigned long flags;
-
- spin_lock_irqsave(&pgd_lock, flags);
- list_del(&page->lru);
- spin_unlock_irqrestore(&pgd_lock, flags);
-}
-
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
- unsigned boundary;
- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
- if (!pgd)
- return NULL;
- pgd_list_add(pgd);
- /*
- * Copy kernel pointers in from init.
- * Could keep a freelist or slab cache of those because the kernel
- * part never changes.
- */
- boundary = pgd_index(__PAGE_OFFSET);
- memset(pgd, 0, boundary * sizeof(pgd_t));
- memcpy(pgd + boundary,
- init_level4_pgt + boundary,
- (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
- return pgd;
-}
-
-static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
-{
- BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
- pgd_list_del(pgd);
- free_page((unsigned long)pgd);
-}
-
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
- return (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- struct page *page;
- void *p;
-
- p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
- if (!p)
- return NULL;
- page = virt_to_page(p);
- pgtable_page_ctor(page);
- return page;
-}
-
-/* Should really implement gc for free page table pages. This could be
- done with a reference count in struct page. */
-
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
-{
- BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
- free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
-{
- pgtable_page_dtor(pte);
- __free_page(pte);
-}
-
-#define __pte_free_tlb(tlb,pte) \
-do { \
- pgtable_page_dtor((pte)); \
- tlb_remove_page((tlb), (pte)); \
-} while (0)
-
-#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
-#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
-
-#endif /* _X86_64_PGALLOC_H */
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h
index f1d9f4a03f6f..801b31f71452 100644
--- a/include/asm-x86/pgtable.h
+++ b/include/asm-x86/pgtable.h
@@ -1,7 +1,6 @@
#ifndef _ASM_X86_PGTABLE_H
#define _ASM_X86_PGTABLE_H
-#define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1)
#define FIRST_USER_ADDRESS 0
#define _PAGE_BIT_PRESENT 0 /* is present */
@@ -196,6 +195,11 @@ static inline int pte_exec(pte_t pte)
return !(pte_val(pte) & _PAGE_NX);
}
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
+
static inline int pmd_large(pmd_t pte)
{
return (pmd_val(pte) & (_PAGE_PSE | _PAGE_PRESENT)) ==
@@ -257,6 +261,11 @@ static inline pte_t pte_clrglobal(pte_t pte)
return __pte(pte_val(pte) & ~(pteval_t)_PAGE_GLOBAL);
}
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return pte;
+}
+
extern pteval_t __supported_pte_mask;
static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
@@ -289,6 +298,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask)
+#ifndef __ASSEMBLY__
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+struct file;
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
+int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t *vma_prot);
+#endif
+
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else /* !CONFIG_PARAVIRT */
@@ -330,6 +348,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
# include "pgtable_64.h"
#endif
+#define KERNEL_PGD_BOUNDARY pgd_index(PAGE_OFFSET)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_BOUNDARY)
+
#ifndef __ASSEMBLY__
enum {
@@ -389,37 +410,17 @@ static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
* bit at the same time.
*/
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \
-({ \
- int __changed = !pte_same(*(ptep), entry); \
- if (__changed && dirty) { \
- *ptep = entry; \
- pte_update_defer((vma)->vm_mm, (address), (ptep)); \
- flush_tlb_page(vma, address); \
- } \
- __changed; \
-})
+extern int ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty);
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define ptep_test_and_clear_young(vma, addr, ptep) ({ \
- int __ret = 0; \
- if (pte_young(*(ptep))) \
- __ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, \
- &(ptep)->pte); \
- if (__ret) \
- pte_update((vma)->vm_mm, addr, ptep); \
- __ret; \
-})
+extern int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep);
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
-#define ptep_clear_flush_young(vma, address, ptep) \
-({ \
- int __young; \
- __young = ptep_test_and_clear_young((vma), (address), (ptep)); \
- if (__young) \
- flush_tlb_page(vma, address); \
- __young; \
-})
+extern int ptep_clear_flush_young(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep);
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
@@ -456,6 +457,22 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm,
pte_update(mm, addr, ptep);
}
+/*
+ * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
+ *
+ * dst - pointer to pgd range anwhere on a pgd page
+ * src - ""
+ * count - the number of pgds to copy.
+ *
+ * dst and src can be on the same page, but the range must not overlap,
+ * and must not cross a page boundary.
+ */
+static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
+{
+ memcpy(dst, src, count * sizeof(pgd_t));
+}
+
+
#include <asm-generic/pgtable.h>
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h
index c4a643674458..577ab79c4c27 100644
--- a/include/asm-x86/pgtable_32.h
+++ b/include/asm-x86/pgtable_32.h
@@ -48,9 +48,6 @@ void paging_init(void);
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE - 1))
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. That means that
@@ -109,21 +106,6 @@ extern int pmd_bad(pmd_t pmd);
#endif
/*
- * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
- *
- * dst - pointer to pgd range anwhere on a pgd page
- * src - ""
- * count - the number of pgds to copy.
- *
- * dst and src can be on the same page, but the range must not overlap,
- * and must not cross a page boundary.
- */
-static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
-{
- memcpy(dst, src, count * sizeof(pgd_t));
-}
-
-/*
* Macro to mark a page protection value as "uncacheable".
* On processors which do not support it, this is a no-op.
*/
@@ -216,16 +198,16 @@ do { \
*/
#define update_mmu_cache(vma, address, pte) do { } while (0)
-void native_pagetable_setup_start(pgd_t *base);
-void native_pagetable_setup_done(pgd_t *base);
+extern void native_pagetable_setup_start(pgd_t *base);
+extern void native_pagetable_setup_done(pgd_t *base);
#ifndef CONFIG_PARAVIRT
-static inline void paravirt_pagetable_setup_start(pgd_t *base)
+static inline void __init paravirt_pagetable_setup_start(pgd_t *base)
{
native_pagetable_setup_start(base);
}
-static inline void paravirt_pagetable_setup_done(pgd_t *base)
+static inline void __init paravirt_pagetable_setup_done(pgd_t *base)
{
native_pagetable_setup_done(base);
}
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index 9fd87d0b6477..a3bbf8766c1d 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -24,7 +24,7 @@ extern void paging_init(void);
#endif /* !__ASSEMBLY__ */
-#define SHARED_KERNEL_PMD 1
+#define SHARED_KERNEL_PMD 0
/*
* PGDIR_SHIFT determines what a top-level page table entry can map
diff --git a/include/asm-x86/posix_types.h b/include/asm-x86/posix_types.h
index fe312a5ba204..bb7133dc155d 100644
--- a/include/asm-x86/posix_types.h
+++ b/include/asm-x86/posix_types.h
@@ -1,5 +1,11 @@
#ifdef __KERNEL__
-# if defined(CONFIG_X86_32) || defined(__i386__)
+# ifdef CONFIG_X86_32
+# include "posix_types_32.h"
+# else
+# include "posix_types_64.h"
+# endif
+#else
+# ifdef __i386__
# include "posix_types_32.h"
# else
# include "posix_types_64.h"
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index e6bf92ddeb21..2e7974ec77ec 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -118,7 +118,6 @@ struct cpuinfo_x86 {
#define X86_VENDOR_CYRIX 1
#define X86_VENDOR_AMD 2
#define X86_VENDOR_UMC 3
-#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
@@ -723,6 +722,7 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
static inline void __sti_mwait(unsigned long eax, unsigned long ecx)
{
+ trace_hardirqs_on();
/* "mwait %eax, %ecx;" */
asm volatile("sti; .byte 0x0f, 0x01, 0xc9;"
:: "a" (eax), "c" (ecx));
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index 24ec061566c5..9f922b0b95d6 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -231,6 +231,8 @@ extern int do_get_thread_area(struct task_struct *p, int idx,
extern int do_set_thread_area(struct task_struct *p, int idx,
struct user_desc __user *info, int can_allocate);
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+
#endif /* __KERNEL__ */
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-x86/reboot.h b/include/asm-x86/reboot.h
index 6b5233b4f84b..e63741f19392 100644
--- a/include/asm-x86/reboot.h
+++ b/include/asm-x86/reboot.h
@@ -15,5 +15,7 @@ struct machine_ops {
extern struct machine_ops machine_ops;
void machine_real_restart(unsigned char *code, int length);
+void native_machine_crash_shutdown(struct pt_regs *regs);
+void native_machine_shutdown(void);
#endif /* _ASM_REBOOT_H */
diff --git a/include/asm-x86/rio.h b/include/asm-x86/rio.h
index 3451c576e6af..c9448bd8968f 100644
--- a/include/asm-x86/rio.h
+++ b/include/asm-x86/rio.h
@@ -60,15 +60,4 @@ enum {
ALT_CALGARY = 5, /* Second Planar Calgary */
};
-/*
- * there is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E.
- */
-static inline unsigned long get_bios_ebda(void)
-{
- unsigned long address = *(unsigned short *)phys_to_virt(0x40EUL);
- address <<= 4;
- return address;
-}
-
#endif /* __ASM_RIO_H */
diff --git a/include/asm-x86/unistd.h b/include/asm-x86/unistd.h
index effc7ad8e12f..2a58ed3e51d8 100644
--- a/include/asm-x86/unistd.h
+++ b/include/asm-x86/unistd.h
@@ -1,5 +1,11 @@
#ifdef __KERNEL__
-# if defined(CONFIG_X86_32) || defined(__i386__)
+# ifdef CONFIG_X86_32
+# include "unistd_32.h"
+# else
+# include "unistd_64.h"
+# endif
+#else
+# ifdef __i386__
# include "unistd_32.h"
# else
# include "unistd_64.h"
diff --git a/include/asm-x86/xen/events.h b/include/asm-x86/xen/events.h
new file mode 100644
index 000000000000..596312a7bfc9
--- /dev/null
+++ b/include/asm-x86/xen/events.h
@@ -0,0 +1,22 @@
+#ifndef __XEN_EVENTS_H
+#define __XEN_EVENTS_H
+
+enum ipi_vector {
+ XEN_RESCHEDULE_VECTOR,
+ XEN_CALL_FUNCTION_VECTOR,
+
+ XEN_NR_IPIS,
+};
+
+static inline int xen_irqs_disabled(struct pt_regs *regs)
+{
+ return raw_irqs_disabled_flags(regs->flags);
+}
+
+static inline void xen_do_IRQ(int irq, struct pt_regs *regs)
+{
+ regs->orig_ax = ~irq;
+ do_IRQ(regs);
+}
+
+#endif /* __XEN_EVENTS_H */
diff --git a/include/asm-x86/xen/grant_table.h b/include/asm-x86/xen/grant_table.h
new file mode 100644
index 000000000000..2444d4593a3b
--- /dev/null
+++ b/include/asm-x86/xen/grant_table.h
@@ -0,0 +1,7 @@
+#ifndef __XEN_GRANT_TABLE_H
+#define __XEN_GRANT_TABLE_H
+
+#define xen_alloc_vm_area(size) alloc_vm_area(size)
+#define xen_free_vm_area(area) free_vm_area(area)
+
+#endif /* __XEN_GRANT_TABLE_H */
diff --git a/include/asm-x86/xen/hypercall.h b/include/asm-x86/xen/hypercall.h
index bc0ee7d961ca..c2ccd997ed35 100644
--- a/include/asm-x86/xen/hypercall.h
+++ b/include/asm-x86/xen/hypercall.h
@@ -164,6 +164,12 @@ HYPERVISOR_set_callbacks(unsigned long event_selector,
}
static inline int
+HYPERVISOR_callback_op(int cmd, void *arg)
+{
+ return _hypercall2(int, callback_op, cmd, arg);
+}
+
+static inline int
HYPERVISOR_fpu_taskswitch(int set)
{
return _hypercall1(int, fpu_taskswitch, set);
diff --git a/include/asm-x86/xen/interface.h b/include/asm-x86/xen/interface.h
index 165c3968e138..6227000a1e84 100644
--- a/include/asm-x86/xen/interface.h
+++ b/include/asm-x86/xen/interface.h
@@ -22,6 +22,30 @@
#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
#define GUEST_HANDLE(name) __guest_handle_ ## name
+#ifdef __XEN__
+#if defined(__i386__)
+#define set_xen_guest_handle(hnd, val) \
+ do { \
+ if (sizeof(hnd) == 8) \
+ *(uint64_t *)&(hnd) = 0; \
+ (hnd).p = val; \
+ } while (0)
+#elif defined(__x86_64__)
+#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0)
+#endif
+#else
+#if defined(__i386__)
+#define set_xen_guest_handle(hnd, val) \
+ do { \
+ if (sizeof(hnd) == 8) \
+ *(uint64_t *)&(hnd) = 0; \
+ (hnd) = val; \
+ } while (0)
+#elif defined(__x86_64__)
+#define set_xen_guest_handle(hnd, val) do { (hnd) = val; } while (0)
+#endif
+#endif
+
#ifndef __ASSEMBLY__
/* Guest handles for primitive C types. */
__DEFINE_GUEST_HANDLE(uchar, unsigned char);
@@ -171,6 +195,10 @@ struct arch_vcpu_info {
unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */
};
+struct xen_callback {
+ unsigned long cs;
+ unsigned long eip;
+};
#endif /* !__ASSEMBLY__ */
/*
diff --git a/include/asm-x86/xen/page.h b/include/asm-x86/xen/page.h
new file mode 100644
index 000000000000..01799305f02a
--- /dev/null
+++ b/include/asm-x86/xen/page.h
@@ -0,0 +1,168 @@
+#ifndef __XEN_PAGE_H
+#define __XEN_PAGE_H
+
+#include <linux/pfn.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+#include <xen/features.h>
+
+/* Xen machine address */
+typedef struct xmaddr {
+ phys_addr_t maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+ phys_addr_t paddr;
+} xpaddr_t;
+
+#define XMADDR(x) ((xmaddr_t) { .maddr = (x) })
+#define XPADDR(x) ((xpaddr_t) { .paddr = (x) })
+
+/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
+#define INVALID_P2M_ENTRY (~0UL)
+#define FOREIGN_FRAME_BIT (1UL<<31)
+#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
+
+extern unsigned long *phys_to_machine_mapping;
+
+static inline unsigned long pfn_to_mfn(unsigned long pfn)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return pfn;
+
+ return phys_to_machine_mapping[(unsigned int)(pfn)] &
+ ~FOREIGN_FRAME_BIT;
+}
+
+static inline int phys_to_machine_mapping_valid(unsigned long pfn)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return 1;
+
+ return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
+}
+
+static inline unsigned long mfn_to_pfn(unsigned long mfn)
+{
+ unsigned long pfn;
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return mfn;
+
+#if 0
+ if (unlikely((mfn >> machine_to_phys_order) != 0))
+ return max_mapnr;
+#endif
+
+ pfn = 0;
+ /*
+ * The array access can fail (e.g., device space beyond end of RAM).
+ * In such cases it doesn't matter what we return (we return garbage),
+ * but we must handle the fault without crashing!
+ */
+ __get_user(pfn, &machine_to_phys_mapping[mfn]);
+
+ return pfn;
+}
+
+static inline xmaddr_t phys_to_machine(xpaddr_t phys)
+{
+ unsigned offset = phys.paddr & ~PAGE_MASK;
+ return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
+}
+
+static inline xpaddr_t machine_to_phys(xmaddr_t machine)
+{
+ unsigned offset = machine.maddr & ~PAGE_MASK;
+ return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
+}
+
+/*
+ * We detect special mappings in one of two ways:
+ * 1. If the MFN is an I/O page then Xen will set the m2p entry
+ * to be outside our maximum possible pseudophys range.
+ * 2. If the MFN belongs to a different domain then we will certainly
+ * not have MFN in our p2m table. Conversely, if the page is ours,
+ * then we'll have p2m(m2p(MFN))==MFN.
+ * If we detect a special mapping then it doesn't have a 'struct page'.
+ * We force !pfn_valid() by returning an out-of-range pointer.
+ *
+ * NB. These checks require that, for any MFN that is not in our reservation,
+ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
+ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
+ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
+ *
+ * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
+ * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
+ * require. In all the cases we care about, the FOREIGN_FRAME bit is
+ * masked (e.g., pfn_to_mfn()) so behaviour there is correct.
+ */
+static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
+{
+ extern unsigned long max_mapnr;
+ unsigned long pfn = mfn_to_pfn(mfn);
+ if ((pfn < max_mapnr)
+ && !xen_feature(XENFEAT_auto_translated_physmap)
+ && (phys_to_machine_mapping[pfn] != mfn))
+ return max_mapnr; /* force !pfn_valid() */
+ return pfn;
+}
+
+static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+ if (xen_feature(XENFEAT_auto_translated_physmap)) {
+ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+ return;
+ }
+ phys_to_machine_mapping[pfn] = mfn;
+}
+
+/* VIRT <-> MACHINE conversion */
+#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
+#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
+#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
+
+static inline unsigned long pte_mfn(pte_t pte)
+{
+ return (pte.pte & ~_PAGE_NX) >> PAGE_SHIFT;
+}
+
+static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot)
+{
+ pte_t pte;
+
+ pte.pte = ((phys_addr_t)page_nr << PAGE_SHIFT) |
+ (pgprot_val(pgprot) & __supported_pte_mask);
+
+ return pte;
+}
+
+static inline pteval_t pte_val_ma(pte_t pte)
+{
+ return pte.pte;
+}
+
+static inline pte_t __pte_ma(pteval_t x)
+{
+ return (pte_t) { .pte = x };
+}
+
+#ifdef CONFIG_X86_PAE
+#define pmd_val_ma(v) ((v).pmd)
+#define pud_val_ma(v) ((v).pgd.pgd)
+#define __pmd_ma(x) ((pmd_t) { (x) } )
+#else /* !X86_PAE */
+#define pmd_val_ma(v) ((v).pud.pgd.pgd)
+#endif /* CONFIG_X86_PAE */
+
+#define pgd_val_ma(x) ((x).pgd)
+
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address);
+void make_lowmem_page_readonly(void *vaddr);
+void make_lowmem_page_readwrite(void *vaddr);
+
+#endif /* __XEN_PAGE_H */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index c8b024a48b4d..8014d96b21f1 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -210,6 +210,8 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
+
static inline pte_t pte_wrprotect(pte_t pte)
{ pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; }
static inline pte_t pte_mkclean(pte_t pte)
@@ -222,6 +224,8 @@ static inline pte_t pte_mkyoung(pte_t pte)
{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte)
{ pte_val(pte) |= _PAGE_WRITABLE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)
+ { return pte; }
/*
* Conversion functions: convert a page and protection to a page entry,
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index cbb5ccb27de3..bda6f04791d4 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -210,7 +210,6 @@ unifdef-y += hayesesp.h
unifdef-y += hdlcdrv.h
unifdef-y += hdlc.h
unifdef-y += hdreg.h
-unifdef-y += hdsmart.h
unifdef-y += hid.h
unifdef-y += hiddev.h
unifdef-y += hidraw.h
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 1dbe074f1c64..43b406def35f 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -46,6 +46,8 @@
* bitmap_shift_left(dst, src, n, nbits) *dst = *src << n
* bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
* bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
+ * bitmap_onto(dst, orig, relmap, nbits) *dst = orig relative to relmap
+ * bitmap_fold(dst, orig, sz, nbits) dst bits = orig bits mod sz
* bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf
* bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf
* bitmap_parse_user(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf
@@ -121,6 +123,10 @@ extern void bitmap_remap(unsigned long *dst, const unsigned long *src,
const unsigned long *old, const unsigned long *new, int bits);
extern int bitmap_bitremap(int oldbit,
const unsigned long *old, const unsigned long *new, int bits);
+extern void bitmap_onto(unsigned long *dst, const unsigned long *orig,
+ const unsigned long *relmap, int bits);
+extern void bitmap_fold(unsigned long *dst, const unsigned long *orig,
+ int sz, int bits);
extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 40d54731de7e..48bde600a2db 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -112,4 +112,144 @@ static inline unsigned fls_long(unsigned long l)
return fls64(l);
}
+#ifdef __KERNEL__
+#ifdef CONFIG_GENERIC_FIND_FIRST_BIT
+extern unsigned long __find_first_bit(const unsigned long *addr,
+ unsigned long size);
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit.
+ */
+static __always_inline unsigned long
+find_first_bit(const unsigned long *addr, unsigned long size)
+{
+ /* Avoid a function call if the bitmap size is a constant */
+ /* and not bigger than BITS_PER_LONG. */
+
+ /* insert a sentinel so that __ffs returns size if there */
+ /* are no set bits in the bitmap */
+ if (__builtin_constant_p(size) && (size < BITS_PER_LONG))
+ return __ffs((*addr) | (1ul << size));
+
+ /* the result of __ffs(0) is undefined, so it needs to be */
+ /* handled separately */
+ if (__builtin_constant_p(size) && (size == BITS_PER_LONG))
+ return ((*addr) == 0) ? BITS_PER_LONG : __ffs(*addr);
+
+ /* size is not constant or too big */
+ return __find_first_bit(addr, size);
+}
+
+extern unsigned long __find_first_zero_bit(const unsigned long *addr,
+ unsigned long size);
+
+/**
+ * find_first_zero_bit - find the first cleared bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first cleared bit.
+ */
+static __always_inline unsigned long
+find_first_zero_bit(const unsigned long *addr, unsigned long size)
+{
+ /* Avoid a function call if the bitmap size is a constant */
+ /* and not bigger than BITS_PER_LONG. */
+
+ /* insert a sentinel so that __ffs returns size if there */
+ /* are no set bits in the bitmap */
+ if (__builtin_constant_p(size) && (size < BITS_PER_LONG)) {
+ return __ffs(~(*addr) | (1ul << size));
+ }
+
+ /* the result of __ffs(0) is undefined, so it needs to be */
+ /* handled separately */
+ if (__builtin_constant_p(size) && (size == BITS_PER_LONG))
+ return (~(*addr) == 0) ? BITS_PER_LONG : __ffs(~(*addr));
+
+ /* size is not constant or too big */
+ return __find_first_zero_bit(addr, size);
+}
+#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
+
+#ifdef CONFIG_GENERIC_FIND_NEXT_BIT
+extern unsigned long __find_next_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset);
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+static __always_inline unsigned long
+find_next_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ unsigned long value;
+
+ /* Avoid a function call if the bitmap size is a constant */
+ /* and not bigger than BITS_PER_LONG. */
+
+ /* insert a sentinel so that __ffs returns size if there */
+ /* are no set bits in the bitmap */
+ if (__builtin_constant_p(size) && (size < BITS_PER_LONG)) {
+ value = (*addr) & ((~0ul) << offset);
+ value |= (1ul << size);
+ return __ffs(value);
+ }
+
+ /* the result of __ffs(0) is undefined, so it needs to be */
+ /* handled separately */
+ if (__builtin_constant_p(size) && (size == BITS_PER_LONG)) {
+ value = (*addr) & ((~0ul) << offset);
+ return (value == 0) ? BITS_PER_LONG : __ffs(value);
+ }
+
+ /* size is not constant or too big */
+ return __find_next_bit(addr, size, offset);
+}
+
+extern unsigned long __find_next_zero_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset);
+
+/**
+ * find_next_zero_bit - find the next cleared bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+static __always_inline unsigned long
+find_next_zero_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ unsigned long value;
+
+ /* Avoid a function call if the bitmap size is a constant */
+ /* and not bigger than BITS_PER_LONG. */
+
+ /* insert a sentinel so that __ffs returns size if there */
+ /* are no set bits in the bitmap */
+ if (__builtin_constant_p(size) && (size < BITS_PER_LONG)) {
+ value = (~(*addr)) & ((~0ul) << offset);
+ value |= (1ul << size);
+ return __ffs(value);
+ }
+
+ /* the result of __ffs(0) is undefined, so it needs to be */
+ /* handled separately */
+ if (__builtin_constant_p(size) && (size == BITS_PER_LONG)) {
+ value = (~(*addr)) & ((~0ul) << offset);
+ return (value == 0) ? BITS_PER_LONG : __ffs(value);
+ }
+
+ /* size is not constant or too big */
+ return __find_next_zero_bit(addr, size, offset);
+}
+#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */
+#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 4e4e340592fb..6a5dbdc8a7dc 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -101,6 +101,8 @@ extern void reserve_bootmem_node(pg_data_t *pgdat,
extern void free_bootmem_node(pg_data_t *pgdat,
unsigned long addr,
unsigned long size);
+extern void *alloc_bootmem_section(unsigned long size,
+ unsigned long section_nr);
#ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
#define alloc_bootmem_node(pgdat, x) \
diff --git a/include/linux/bsg.h b/include/linux/bsg.h
index e8406c55c6d3..cf0303a60611 100644
--- a/include/linux/bsg.h
+++ b/include/linux/bsg.h
@@ -56,19 +56,25 @@ struct sg_io_v4 {
#if defined(CONFIG_BLK_DEV_BSG)
struct bsg_class_device {
struct device *class_dev;
- struct device *dev;
+ struct device *parent;
int minor;
struct request_queue *queue;
+ struct kref ref;
+ void (*release)(struct device *);
};
-extern int bsg_register_queue(struct request_queue *, struct device *, const char *);
+extern int bsg_register_queue(struct request_queue *q,
+ struct device *parent, const char *name,
+ void (*release)(struct device *));
extern void bsg_unregister_queue(struct request_queue *);
#else
-static inline int bsg_register_queue(struct request_queue * rq, struct device *dev, const char *name)
+static inline int bsg_register_queue(struct request_queue *q,
+ struct device *parent, const char *name,
+ void (*release)(struct device *))
{
return 0;
}
-static inline void bsg_unregister_queue(struct request_queue *rq)
+static inline void bsg_unregister_queue(struct request_queue *q)
{
}
#endif
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 4552504c0228..97e24881c4c6 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -60,4 +60,8 @@
#endif
#endif
+#ifndef CONFIG_ARCH_HAS_CACHE_LINE_SIZE
+#define cache_line_size() L1_CACHE_BYTES
+#endif
+
#endif /* __LINUX_CACHE_H */
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 7d50ff6d269f..eaab759b1460 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -155,6 +155,7 @@ typedef struct kernel_cap_struct {
* Add any capability from current's capability bounding set
* to the current process' inheritable set
* Allow taking bits out of capability bounding set
+ * Allow modification of the securebits for a process
*/
#define CAP_SETPCAP 8
@@ -490,8 +491,6 @@ extern const kernel_cap_t __cap_init_eff_set;
int capable(int cap);
int __capable(struct task_struct *t, int cap);
-extern long cap_prctl_drop(unsigned long cap);
-
#endif /* __KERNEL__ */
#endif /* !_LINUX_CAPABILITY_H */
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index fe23792f05c1..b2fd7547b58d 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -28,9 +28,16 @@
#define __must_be_array(a) \
BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
-#define inline inline __attribute__((always_inline))
-#define __inline__ __inline__ __attribute__((always_inline))
-#define __inline __inline __attribute__((always_inline))
+/*
+ * Force always-inline if the user requests it so via the .config:
+ */
+#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
+ !defined(CONFIG_OPTIMIZE_INLINING) && (__GNUC__ >= 4)
+# define inline inline __attribute__((always_inline))
+# define __inline__ __inline__ __attribute__((always_inline))
+# define __inline __inline __attribute__((always_inline))
+#endif
+
#define __deprecated __attribute__((deprecated))
#define __packed __attribute__((packed))
#define __weak __attribute__((weak))
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 259c8051155d..9650806fe2ea 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -14,6 +14,8 @@
* bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
* For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
* For details of cpus_remap(), see bitmap_remap in lib/bitmap.c.
+ * For details of cpus_onto(), see bitmap_onto in lib/bitmap.c.
+ * For details of cpus_fold(), see bitmap_fold in lib/bitmap.c.
*
* The available cpumask operations are:
*
@@ -53,7 +55,9 @@
* int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
* int cpulist_parse(buf, map) Parse ascii string as cpulist
* int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
- * int cpus_remap(dst, src, old, new) *dst = map(old, new)(src)
+ * void cpus_remap(dst, src, old, new) *dst = map(old, new)(src)
+ * void cpus_onto(dst, orig, relmap) *dst = orig relative to relmap
+ * void cpus_fold(dst, orig, sz) dst bits = orig bits mod sz
*
* for_each_cpu_mask(cpu, mask) for-loop cpu over mask
*
@@ -330,6 +334,22 @@ static inline void __cpus_remap(cpumask_t *dstp, const cpumask_t *srcp,
bitmap_remap(dstp->bits, srcp->bits, oldp->bits, newp->bits, nbits);
}
+#define cpus_onto(dst, orig, relmap) \
+ __cpus_onto(&(dst), &(orig), &(relmap), NR_CPUS)
+static inline void __cpus_onto(cpumask_t *dstp, const cpumask_t *origp,
+ const cpumask_t *relmapp, int nbits)
+{
+ bitmap_onto(dstp->bits, origp->bits, relmapp->bits, nbits);
+}
+
+#define cpus_fold(dst, orig, sz) \
+ __cpus_fold(&(dst), &(orig), sz, NR_CPUS)
+static inline void __cpus_fold(cpumask_t *dstp, const cpumask_t *origp,
+ int sz, int nbits)
+{
+ bitmap_fold(dstp->bits, origp->bits, sz, nbits);
+}
+
#if NR_CPUS > 1
#define for_each_cpu_mask(cpu, mask) \
for ((cpu) = first_cpu(mask); \
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 726761e24003..038578362b47 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -26,7 +26,7 @@ extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
#define cpuset_current_mems_allowed (current->mems_allowed)
void cpuset_init_current_mems_allowed(void);
void cpuset_update_task_memory_state(void);
-int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl);
+int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask);
extern int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask);
extern int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask);
@@ -103,7 +103,7 @@ static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
static inline void cpuset_init_current_mems_allowed(void) {}
static inline void cpuset_update_task_memory_state(void) {}
-static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
+static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask)
{
return 1;
}
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index cb784579956b..ad3b787479a4 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
*
* This file is released under the LGPL.
*/
@@ -10,6 +10,8 @@
#ifdef __KERNEL__
+#include <linux/bio.h>
+
struct dm_target;
struct dm_table;
struct dm_dev;
@@ -250,11 +252,97 @@ void dm_table_event(struct dm_table *t);
*/
int dm_swap_table(struct mapped_device *md, struct dm_table *t);
+/*-----------------------------------------------------------------
+ * Macros.
+ *---------------------------------------------------------------*/
+#define DM_NAME "device-mapper"
+
+#define DMERR(f, arg...) \
+ printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMERR_LIMIT(f, arg...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \
+ f "\n", ## arg); \
+ } while (0)
+
+#define DMWARN(f, arg...) \
+ printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMWARN_LIMIT(f, arg...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \
+ f "\n", ## arg); \
+ } while (0)
+
+#define DMINFO(f, arg...) \
+ printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMINFO_LIMIT(f, arg...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \
+ "\n", ## arg); \
+ } while (0)
+
+#ifdef CONFIG_DM_DEBUG
+# define DMDEBUG(f, arg...) \
+ printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
+# define DMDEBUG_LIMIT(f, arg...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \
+ "\n", ## arg); \
+ } while (0)
+#else
+# define DMDEBUG(f, arg...) do {} while (0)
+# define DMDEBUG_LIMIT(f, arg...) do {} while (0)
+#endif
+
+#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
+ 0 : scnprintf(result + sz, maxlen - sz, x))
+
+#define SECTOR_SHIFT 9
+
+/*
+ * Definitions of return values from target end_io function.
+ */
+#define DM_ENDIO_INCOMPLETE 1
+#define DM_ENDIO_REQUEUE 2
+
+/*
+ * Definitions of return values from target map function.
+ */
+#define DM_MAPIO_SUBMITTED 0
+#define DM_MAPIO_REMAPPED 1
+#define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE
+
+/*
+ * Ceiling(n / sz)
+ */
+#define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz))
+
+#define dm_sector_div_up(n, sz) ( \
+{ \
+ sector_t _r = ((n) + (sz) - 1); \
+ sector_div(_r, (sz)); \
+ _r; \
+} \
+)
+
/*
- * Prepare a table for a device that will error all I/O.
- * To make it active, call dm_suspend(), dm_swap_table() then dm_resume().
+ * ceiling(n / size) * size
*/
-int dm_create_error_table(struct dm_table **result, struct mapped_device *md);
+#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
+
+static inline sector_t to_sector(unsigned long n)
+{
+ return (n >> SECTOR_SHIFT);
+}
+
+static inline unsigned long to_bytes(sector_t n)
+{
+ return (n << SECTOR_SHIFT);
+}
#endif /* __KERNEL__ */
#endif /* _LINUX_DEVICE_MAPPER_H */
diff --git a/drivers/md/dm-log.h b/include/linux/dm-dirty-log.h
index 3fae87eb5963..600c5fb2daad 100644
--- a/drivers/md/dm-log.h
+++ b/include/linux/dm-dirty-log.h
@@ -1,52 +1,56 @@
/*
* Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ *
+ * Device-Mapper dirty region log.
*
* This file is released under the LGPL.
*/
-#ifndef DM_DIRTY_LOG
-#define DM_DIRTY_LOG
+#ifndef _LINUX_DM_DIRTY_LOG
+#define _LINUX_DM_DIRTY_LOG
+
+#ifdef __KERNEL__
-#include "dm.h"
+#include <linux/types.h>
+#include <linux/device-mapper.h>
typedef sector_t region_t;
-struct dirty_log_type;
+struct dm_dirty_log_type;
-struct dirty_log {
- struct dirty_log_type *type;
+struct dm_dirty_log {
+ struct dm_dirty_log_type *type;
void *context;
};
-struct dirty_log_type {
- struct list_head list;
+struct dm_dirty_log_type {
const char *name;
struct module *module;
- unsigned int use_count;
- int (*ctr)(struct dirty_log *log, struct dm_target *ti,
- unsigned int argc, char **argv);
- void (*dtr)(struct dirty_log *log);
+ int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
+ unsigned argc, char **argv);
+ void (*dtr)(struct dm_dirty_log *log);
/*
* There are times when we don't want the log to touch
* the disk.
*/
- int (*presuspend)(struct dirty_log *log);
- int (*postsuspend)(struct dirty_log *log);
- int (*resume)(struct dirty_log *log);
+ int (*presuspend)(struct dm_dirty_log *log);
+ int (*postsuspend)(struct dm_dirty_log *log);
+ int (*resume)(struct dm_dirty_log *log);
/*
* Retrieves the smallest size of region that the log can
* deal with.
*/
- uint32_t (*get_region_size)(struct dirty_log *log);
+ uint32_t (*get_region_size)(struct dm_dirty_log *log);
- /*
+ /*
* A predicate to say whether a region is clean or not.
* May block.
*/
- int (*is_clean)(struct dirty_log *log, region_t region);
+ int (*is_clean)(struct dm_dirty_log *log, region_t region);
/*
* Returns: 0, 1, -EWOULDBLOCK, < 0
@@ -59,13 +63,14 @@ struct dirty_log_type {
* passed to a daemon to deal with, since a daemon is
* allowed to block.
*/
- int (*in_sync)(struct dirty_log *log, region_t region, int can_block);
+ int (*in_sync)(struct dm_dirty_log *log, region_t region,
+ int can_block);
/*
* Flush the current log state (eg, to disk). This
* function may block.
*/
- int (*flush)(struct dirty_log *log);
+ int (*flush)(struct dm_dirty_log *log);
/*
* Mark an area as clean or dirty. These functions may
@@ -73,8 +78,8 @@ struct dirty_log_type {
* be extremely rare (eg, allocating another chunk of
* memory for some reason).
*/
- void (*mark_region)(struct dirty_log *log, region_t region);
- void (*clear_region)(struct dirty_log *log, region_t region);
+ void (*mark_region)(struct dm_dirty_log *log, region_t region);
+ void (*clear_region)(struct dm_dirty_log *log, region_t region);
/*
* Returns: <0 (error), 0 (no region), 1 (region)
@@ -88,44 +93,39 @@ struct dirty_log_type {
* tells you if an area is synchronised, the other
* assigns recovery work.
*/
- int (*get_resync_work)(struct dirty_log *log, region_t *region);
+ int (*get_resync_work)(struct dm_dirty_log *log, region_t *region);
/*
* This notifies the log that the resync status of a region
* has changed. It also clears the region from the recovering
* list (if present).
*/
- void (*set_region_sync)(struct dirty_log *log,
+ void (*set_region_sync)(struct dm_dirty_log *log,
region_t region, int in_sync);
- /*
+ /*
* Returns the number of regions that are in sync.
- */
- region_t (*get_sync_count)(struct dirty_log *log);
+ */
+ region_t (*get_sync_count)(struct dm_dirty_log *log);
/*
* Support function for mirror status requests.
*/
- int (*status)(struct dirty_log *log, status_type_t status_type,
- char *result, unsigned int maxlen);
+ int (*status)(struct dm_dirty_log *log, status_type_t status_type,
+ char *result, unsigned maxlen);
};
-int dm_register_dirty_log_type(struct dirty_log_type *type);
-int dm_unregister_dirty_log_type(struct dirty_log_type *type);
-
+int dm_dirty_log_type_register(struct dm_dirty_log_type *type);
+int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type);
/*
* Make sure you use these two functions, rather than calling
* type->constructor/destructor() directly.
*/
-struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,
- unsigned int argc, char **argv);
-void dm_destroy_dirty_log(struct dirty_log *log);
-
-/*
- * init/exit functions.
- */
-int dm_dirty_log_init(void);
-void dm_dirty_log_exit(void);
+struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
+ struct dm_target *ti,
+ unsigned argc, char **argv);
+void dm_dirty_log_destroy(struct dm_dirty_log *log);
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DM_DIRTY_LOG_H */
diff --git a/drivers/md/dm-io.h b/include/linux/dm-io.h
index f647e2cceaa6..b6bf17ee2f61 100644
--- a/drivers/md/dm-io.h
+++ b/include/linux/dm-io.h
@@ -1,15 +1,20 @@
/*
* Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved.
+ *
+ * Device-Mapper low-level I/O.
*
* This file is released under the GPL.
*/
-#ifndef _DM_IO_H
-#define _DM_IO_H
+#ifndef _LINUX_DM_IO_H
+#define _LINUX_DM_IO_H
+
+#ifdef __KERNEL__
-#include "dm.h"
+#include <linux/types.h>
-struct io_region {
+struct dm_io_region {
struct block_device *bdev;
sector_t sector;
sector_t count; /* If this is zero the region is ignored. */
@@ -74,6 +79,7 @@ void dm_io_client_destroy(struct dm_io_client *client);
* error occurred doing io to the corresponding region.
*/
int dm_io(struct dm_io_request *io_req, unsigned num_regions,
- struct io_region *region, unsigned long *sync_error_bits);
+ struct dm_io_region *region, unsigned long *sync_error_bits);
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DM_IO_H */
diff --git a/include/linux/dm-kcopyd.h b/include/linux/dm-kcopyd.h
new file mode 100644
index 000000000000..5db216311695
--- /dev/null
+++ b/include/linux/dm-kcopyd.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2001 - 2003 Sistina Software
+ * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved.
+ *
+ * kcopyd provides a simple interface for copying an area of one
+ * block-device to one or more other block-devices, either synchronous
+ * or with an asynchronous completion notification.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef _LINUX_DM_KCOPYD_H
+#define _LINUX_DM_KCOPYD_H
+
+#ifdef __KERNEL__
+
+#include <linux/dm-io.h>
+
+/* FIXME: make this configurable */
+#define DM_KCOPYD_MAX_REGIONS 8
+
+#define DM_KCOPYD_IGNORE_ERROR 1
+
+/*
+ * To use kcopyd you must first create a dm_kcopyd_client object.
+ */
+struct dm_kcopyd_client;
+int dm_kcopyd_client_create(unsigned num_pages,
+ struct dm_kcopyd_client **result);
+void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc);
+
+/*
+ * Submit a copy job to kcopyd. This is built on top of the
+ * previous three fns.
+ *
+ * read_err is a boolean,
+ * write_err is a bitset, with 1 bit for each destination region
+ */
+typedef void (*dm_kcopyd_notify_fn)(int read_err, unsigned long write_err,
+ void *context);
+
+int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
+ unsigned num_dests, struct dm_io_region *dests,
+ unsigned flags, dm_kcopyd_notify_fn fn, void *context);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DM_KCOPYD_H */
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 325acdf5c462..2a063b64133f 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -90,6 +90,7 @@ static inline int dmi_check_system(const struct dmi_system_id *list) { return 0;
static inline const char * dmi_get_system_info(int field) { return NULL; }
static inline const struct dmi_device * dmi_find_device(int type, const char *name,
const struct dmi_device *from) { return NULL; }
+static inline void dmi_scan_machine(void) { return; }
static inline int dmi_get_year(int year) { return 0; }
static inline int dmi_name_in_vendors(const char *s) { return 0; }
#define dmi_available 0
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 58c57a33e5dd..72295b099228 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -791,6 +791,17 @@ struct fb_tile_ops {
*/
#define FBINFO_MISC_ALWAYS_SETPAR 0x40000
+/*
+ * Host and GPU endianness differ.
+ */
+#define FBINFO_FOREIGN_ENDIAN 0x100000
+/*
+ * Big endian math. This is the same flags as above, but with different
+ * meaning, it is set by the fb subsystem depending FOREIGN_ENDIAN flag
+ * and host endianness. Drivers should not use this flag.
+ */
+#define FBINFO_BE_MATH 0x100000
+
struct fb_info {
int node;
int flags;
@@ -899,15 +910,11 @@ struct fb_info {
#endif
-#if defined (__BIG_ENDIAN)
-#define FB_LEFT_POS(bpp) (32 - bpp)
-#define FB_SHIFT_HIGH(val, bits) ((val) >> (bits))
-#define FB_SHIFT_LOW(val, bits) ((val) << (bits))
-#else
-#define FB_LEFT_POS(bpp) (0)
-#define FB_SHIFT_HIGH(val, bits) ((val) << (bits))
-#define FB_SHIFT_LOW(val, bits) ((val) >> (bits))
-#endif
+#define FB_LEFT_POS(p, bpp) (fb_be_math(p) ? (32 - (bpp)) : 0)
+#define FB_SHIFT_HIGH(p, val, bits) (fb_be_math(p) ? (val) >> (bits) : \
+ (val) << (bits))
+#define FB_SHIFT_LOW(p, val, bits) (fb_be_math(p) ? (val) << (bits) : \
+ (val) >> (bits))
/*
* `Generic' versions of the frame buffer device operations
@@ -970,6 +977,25 @@ extern void fb_deferred_io_cleanup(struct fb_info *info);
extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
int datasync);
+static inline bool fb_be_math(struct fb_info *info)
+{
+#ifdef CONFIG_FB_FOREIGN_ENDIAN
+#if defined(CONFIG_FB_BOTH_ENDIAN)
+ return info->flags & FBINFO_BE_MATH;
+#elif defined(CONFIG_FB_BIG_ENDIAN)
+ return true;
+#elif defined(CONFIG_FB_LITTLE_ENDIAN)
+ return false;
+#endif /* CONFIG_FB_BOTH_ENDIAN */
+#else
+#ifdef __BIG_ENDIAN
+ return true;
+#else
+ return false;
+#endif /* __BIG_ENDIAN */
+#endif /* CONFIG_FB_FOREIGN_ENDIAN */
+}
+
/* drivers/video/fbsysfs.c */
extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
extern void framebuffer_release(struct fb_info *info);
diff --git a/include/linux/file.h b/include/linux/file.h
index 653477021e4c..69baf5a4f0a5 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -117,7 +117,8 @@ struct task_struct;
struct files_struct *get_files_struct(struct task_struct *);
void put_files_struct(struct files_struct *fs);
-void reset_files_struct(struct task_struct *, struct files_struct *);
+void reset_files_struct(struct files_struct *);
+int unshare_files(struct files_struct **);
extern struct kmem_cache *files_cachep;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index cc2be2cf7d41..2c925747bc49 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -474,8 +474,8 @@ struct address_space_operations {
int (*releasepage) (struct page *, gfp_t);
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
- struct page* (*get_xip_page)(struct address_space *, sector_t,
- int);
+ int (*get_xip_mem)(struct address_space *, pgoff_t, int,
+ void **, unsigned long *);
/* migrate the contents of a page to the specified target */
int (*migratepage) (struct address_space *,
struct page *, struct page *);
@@ -973,6 +973,7 @@ extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
+extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *);
extern void posix_test_lock(struct file *, struct file_lock *);
@@ -1177,7 +1178,8 @@ struct block_device_operations {
int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
long (*compat_ioctl) (struct file *, unsigned, unsigned long);
- int (*direct_access) (struct block_device *, sector_t, unsigned long *);
+ int (*direct_access) (struct block_device *, sector_t,
+ void **, unsigned long *);
int (*media_changed) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);
int (*getgeo)(struct block_device *, struct hd_geometry *);
@@ -1308,7 +1310,7 @@ struct super_operations {
int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
- void (*umount_begin) (struct vfsmount *, int);
+ void (*umount_begin) (struct super_block *);
int (*show_options)(struct seq_file *, struct vfsmount *);
int (*show_stats)(struct seq_file *, struct vfsmount *);
@@ -2033,9 +2035,6 @@ static inline ino_t parent_ino(struct dentry *dentry)
return res;
}
-/* kernel/fork.c */
-extern int unshare_files(void);
-
/* Transaction based IO helpers */
/*
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 164be9da3c1b..c37653b6843f 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -119,35 +119,22 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
static inline enum zone_type gfp_zone(gfp_t flags)
{
- int base = 0;
-
-#ifdef CONFIG_NUMA
- if (flags & __GFP_THISNODE)
- base = MAX_NR_ZONES;
-#endif
-
#ifdef CONFIG_ZONE_DMA
if (flags & __GFP_DMA)
- return base + ZONE_DMA;
+ return ZONE_DMA;
#endif
#ifdef CONFIG_ZONE_DMA32
if (flags & __GFP_DMA32)
- return base + ZONE_DMA32;
+ return ZONE_DMA32;
#endif
if ((flags & (__GFP_HIGHMEM | __GFP_MOVABLE)) ==
(__GFP_HIGHMEM | __GFP_MOVABLE))
- return base + ZONE_MOVABLE;
+ return ZONE_MOVABLE;
#ifdef CONFIG_HIGHMEM
if (flags & __GFP_HIGHMEM)
- return base + ZONE_HIGHMEM;
+ return ZONE_HIGHMEM;
#endif
- return base + ZONE_NORMAL;
-}
-
-static inline gfp_t set_migrateflags(gfp_t gfp, gfp_t migrate_flags)
-{
- BUG_ON((gfp & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);
- return (gfp & ~(GFP_MOVABLE_MASK)) | migrate_flags;
+ return ZONE_NORMAL;
}
/*
@@ -157,13 +144,27 @@ static inline gfp_t set_migrateflags(gfp_t gfp, gfp_t migrate_flags)
* virtual kernel addresses to the allocated page(s).
*/
+static inline int gfp_zonelist(gfp_t flags)
+{
+ if (NUMA_BUILD && unlikely(flags & __GFP_THISNODE))
+ return 1;
+
+ return 0;
+}
+
/*
* We get the zone list from the current node and the gfp_mask.
* This zone list contains a maximum of MAXNODES*MAX_NR_ZONES zones.
+ * There are two zonelists per node, one for all zones with memory and
+ * one containing just zones from the node the zonelist belongs to.
*
* For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets
* optimized to &contig_page_data at compile-time.
*/
+static inline struct zonelist *node_zonelist(int nid, gfp_t flags)
+{
+ return NODE_DATA(nid)->node_zonelists + gfp_zonelist(flags);
+}
#ifndef HAVE_ARCH_FREE_PAGE
static inline void arch_free_page(struct page *page, int order) { }
@@ -174,6 +175,10 @@ static inline void arch_alloc_page(struct page *page, int order) { }
extern struct page *__alloc_pages(gfp_t, unsigned int, struct zonelist *);
+extern struct page *
+__alloc_pages_nodemask(gfp_t, unsigned int,
+ struct zonelist *, nodemask_t *nodemask);
+
static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
unsigned int order)
{
@@ -184,8 +189,7 @@ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
if (nid < 0)
nid = numa_node_id();
- return __alloc_pages(gfp_mask, order,
- NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_mask));
+ return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
}
#ifdef CONFIG_NUMA
diff --git a/include/linux/hdsmart.h b/include/linux/hdsmart.h
deleted file mode 100644
index 4f4faf9d4238..000000000000
--- a/include/linux/hdsmart.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * linux/include/linux/hdsmart.h
- *
- * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
- * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _LINUX_HDSMART_H
-#define _LINUX_HDSMART_H
-
-#ifndef __KERNEL__
-#define OFFLINE_FULL_SCAN 0
-#define SHORT_SELF_TEST 1
-#define EXTEND_SELF_TEST 2
-#define SHORT_CAPTIVE_SELF_TEST 129
-#define EXTEND_CAPTIVE_SELF_TEST 130
-
-/* smart_attribute is the vendor specific in SFF-8035 spec */
-typedef struct ata_smart_attribute_s {
- unsigned char id;
- unsigned short status_flag;
- unsigned char normalized;
- unsigned char worse_normal;
- unsigned char raw[6];
- unsigned char reserv;
-} __attribute__ ((packed)) ata_smart_attribute_t;
-
-/* smart_values is format of the read drive Atrribute command */
-typedef struct ata_smart_values_s {
- unsigned short revnumber;
- ata_smart_attribute_t vendor_attributes [30];
- unsigned char offline_data_collection_status;
- unsigned char self_test_exec_status;
- unsigned short total_time_to_complete_off_line;
- unsigned char vendor_specific_366;
- unsigned char offline_data_collection_capability;
- unsigned short smart_capability;
- unsigned char errorlog_capability;
- unsigned char vendor_specific_371;
- unsigned char short_test_completion_time;
- unsigned char extend_test_completion_time;
- unsigned char reserved_374_385 [12];
- unsigned char vendor_specific_386_509 [125];
- unsigned char chksum;
-} __attribute__ ((packed)) ata_smart_values_t;
-
-/* Smart Threshold data structures */
-/* Vendor attribute of SMART Threshold */
-typedef struct ata_smart_threshold_entry_s {
- unsigned char id;
- unsigned char normalized_threshold;
- unsigned char reserved[10];
-} __attribute__ ((packed)) ata_smart_threshold_entry_t;
-
-/* Format of Read SMART THreshold Command */
-typedef struct ata_smart_thresholds_s {
- unsigned short revnumber;
- ata_smart_threshold_entry_t thres_entries[30];
- unsigned char reserved[149];
- unsigned char chksum;
-} __attribute__ ((packed)) ata_smart_thresholds_t;
-
-typedef struct ata_smart_errorlog_command_struct_s {
- unsigned char devicecontrolreg;
- unsigned char featuresreg;
- unsigned char sector_count;
- unsigned char sector_number;
- unsigned char cylinder_low;
- unsigned char cylinder_high;
- unsigned char drive_head;
- unsigned char commandreg;
- unsigned int timestamp;
-} __attribute__ ((packed)) ata_smart_errorlog_command_struct_t;
-
-typedef struct ata_smart_errorlog_error_struct_s {
- unsigned char error_condition;
- unsigned char extended_error[14];
- unsigned char state;
- unsigned short timestamp;
-} __attribute__ ((packed)) ata_smart_errorlog_error_struct_t;
-
-typedef struct ata_smart_errorlog_struct_s {
- ata_smart_errorlog_command_struct_t commands[6];
- ata_smart_errorlog_error_struct_t error_struct;
-} __attribute__ ((packed)) ata_smart_errorlog_struct_t;
-
-typedef struct ata_smart_errorlog_s {
- unsigned char revnumber;
- unsigned char error_log_pointer;
- ata_smart_errorlog_struct_t errorlog_struct[5];
- unsigned short ata_error_count;
- unsigned short non_fatal_count;
- unsigned short drive_timeout_count;
- unsigned char reserved[53];
- unsigned char chksum;
-} __attribute__ ((packed)) ata_smart_errorlog_t;
-
-typedef struct ata_smart_selftestlog_struct_s {
- unsigned char selftestnumber;
- unsigned char selfteststatus;
- unsigned short timestamp;
- unsigned char selftestfailurecheckpoint;
- unsigned int lbafirstfailure;
- unsigned char vendorspecific[15];
-} __attribute__ ((packed)) ata_smart_selftestlog_struct_t;
-
-typedef struct ata_smart_selftestlog_s {
- unsigned short revnumber;
- ata_smart_selftestlog_struct_t selftest_struct[21];
- unsigned char vendorspecific[2];
- unsigned char mostrecenttest;
- unsigned char resevered[2];
- unsigned char chksum;
-} __attribute__ ((packed)) ata_smart_selftestlog_t;
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_HDSMART_H */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index d951ec411241..4ce3b7a979ba 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -498,13 +498,13 @@ struct hid_parser {
struct hid_class_descriptor {
__u8 bDescriptorType;
- __u16 wDescriptorLength;
+ __le16 wDescriptorLength;
} __attribute__ ((packed));
struct hid_descriptor {
__u8 bLength;
__u8 bDescriptorType;
- __u16 bcdHID;
+ __le16 bcdHID;
__u8 bCountryCode;
__u8 bNumDescriptors;
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index addca4cd4f11..a79e80b689d8 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -8,6 +8,7 @@
#include <linux/mempolicy.h>
#include <linux/shm.h>
#include <asm/tlbflush.h>
+#include <asm/hugetlb.h>
struct ctl_table;
@@ -51,51 +52,6 @@ int pmd_huge(pmd_t pmd);
void hugetlb_change_protection(struct vm_area_struct *vma,
unsigned long address, unsigned long end, pgprot_t newprot);
-#ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define is_hugepage_only_range(mm, addr, len) 0
-#endif
-
-#ifndef ARCH_HAS_HUGETLB_FREE_PGD_RANGE
-#define hugetlb_free_pgd_range free_pgd_range
-#else
-void hugetlb_free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
- unsigned long end, unsigned long floor,
- unsigned long ceiling);
-#endif
-
-#ifndef ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-/*
- * If the arch doesn't supply something else, assume that hugepage
- * size aligned regions are ok without further preparation.
- */
-static inline int prepare_hugepage_range(unsigned long addr, unsigned long len)
-{
- if (len & ~HPAGE_MASK)
- return -EINVAL;
- if (addr & ~HPAGE_MASK)
- return -EINVAL;
- return 0;
-}
-#else
-int prepare_hugepage_range(unsigned long addr, unsigned long len);
-#endif
-
-#ifndef ARCH_HAS_SETCLEAR_HUGE_PTE
-#define set_huge_pte_at(mm, addr, ptep, pte) set_pte_at(mm, addr, ptep, pte)
-#define huge_ptep_get_and_clear(mm, addr, ptep) ptep_get_and_clear(mm, addr, ptep)
-#else
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pte);
-pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep);
-#endif
-
-#ifndef ARCH_HAS_HUGETLB_PREFAULT_HOOK
-#define hugetlb_prefault_arch_hook(mm) do { } while (0)
-#else
-void hugetlb_prefault_arch_hook(struct mm_struct *mm);
-#endif
-
#else /* !CONFIG_HUGETLB_PAGE */
static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index e92170dda245..f65e58a1d925 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -613,14 +613,9 @@ struct i2o_sys_tbl {
extern struct list_head i2o_controllers;
/* Message functions */
-static inline struct i2o_message *i2o_msg_get(struct i2o_controller *);
extern struct i2o_message *i2o_msg_get_wait(struct i2o_controller *, int);
-static inline void i2o_msg_post(struct i2o_controller *, struct i2o_message *);
-static inline int i2o_msg_post_wait(struct i2o_controller *,
- struct i2o_message *, unsigned long);
extern int i2o_msg_post_wait_mem(struct i2o_controller *, struct i2o_message *,
unsigned long, struct i2o_dma *);
-static inline void i2o_flush_reply(struct i2o_controller *, u32);
/* IOP functions */
extern int i2o_status_get(struct i2o_controller *);
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 5f3e82ae901a..b0135b0c3a04 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -48,13 +48,6 @@ typedef unsigned char byte; /* used everywhere */
#define ERROR_RECAL 1 /* Recalibrate every 2nd retry */
/*
- * Tune flags
- */
-#define IDE_TUNE_NOAUTO 2
-#define IDE_TUNE_AUTO 1
-#define IDE_TUNE_DEFAULT 0
-
-/*
* state flags
*/
@@ -68,23 +61,30 @@ typedef unsigned char byte; /* used everywhere */
*/
#define IDE_NR_PORTS (10)
-#define IDE_DATA_OFFSET (0)
-#define IDE_ERROR_OFFSET (1)
-#define IDE_NSECTOR_OFFSET (2)
-#define IDE_SECTOR_OFFSET (3)
-#define IDE_LCYL_OFFSET (4)
-#define IDE_HCYL_OFFSET (5)
-#define IDE_SELECT_OFFSET (6)
-#define IDE_STATUS_OFFSET (7)
-#define IDE_CONTROL_OFFSET (8)
-#define IDE_IRQ_OFFSET (9)
-
-#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
-#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
-#define IDE_ALTSTATUS_OFFSET IDE_CONTROL_OFFSET
-#define IDE_IREASON_OFFSET IDE_NSECTOR_OFFSET
-#define IDE_BCOUNTL_OFFSET IDE_LCYL_OFFSET
-#define IDE_BCOUNTH_OFFSET IDE_HCYL_OFFSET
+struct ide_io_ports {
+ unsigned long data_addr;
+
+ union {
+ unsigned long error_addr; /* read: error */
+ unsigned long feature_addr; /* write: feature */
+ };
+
+ unsigned long nsect_addr;
+ unsigned long lbal_addr;
+ unsigned long lbam_addr;
+ unsigned long lbah_addr;
+
+ unsigned long device_addr;
+
+ union {
+ unsigned long status_addr; /*  read: status  */
+ unsigned long command_addr; /* write: command */
+ };
+
+ unsigned long ctl_addr;
+
+ unsigned long irq_addr;
+};
#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
#define BAD_R_STAT (BUSY_STAT | ERR_STAT)
@@ -163,14 +163,17 @@ typedef u8 hwif_chipset_t;
* Structure to hold all information about the location of this port
*/
typedef struct hw_regs_s {
- unsigned long io_ports[IDE_NR_PORTS]; /* task file registers */
+ union {
+ struct ide_io_ports io_ports;
+ unsigned long io_ports_array[IDE_NR_PORTS];
+ };
+
int irq; /* our irq number */
ide_ack_intr_t *ack_intr; /* acknowledge interrupt */
hwif_chipset_t chipset;
struct device *dev;
} hw_regs_t;
-struct hwif_s * ide_find_port(unsigned long);
void ide_init_port_data(struct hwif_s *, unsigned int);
void ide_init_port_hw(struct hwif_s *, hw_regs_t *);
@@ -180,10 +183,10 @@ static inline void ide_std_init_ports(hw_regs_t *hw,
{
unsigned int i;
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- hw->io_ports[i] = io_addr++;
+ for (i = 0; i <= 7; i++)
+ hw->io_ports_array[i] = io_addr++;
- hw->io_ports[IDE_CONTROL_OFFSET] = ctl_addr;
+ hw->io_ports.ctl_addr = ctl_addr;
}
#include <asm/ide.h>
@@ -329,7 +332,6 @@ typedef struct ide_drive_s {
unsigned atapi_overlap : 1; /* ATAPI overlap (not supported) */
unsigned doorlocking : 1; /* for removable only: door lock/unlock works */
unsigned nodma : 1; /* disallow DMA */
- unsigned autotune : 2; /* 0=default, 1=autotune, 2=noautotune */
unsigned remap_0_to_1 : 1; /* 0=noremap, 1=remap 0->1 (for EZDrive) */
unsigned blocked : 1; /* 1=powermanagment told us not to do anything, so sleep nicely */
unsigned vdma : 1; /* 1=doing PIO over DMA 0=doing normal DMA */
@@ -388,6 +390,45 @@ typedef struct ide_drive_s {
struct ide_port_info;
+struct ide_port_ops {
+ /* host specific initialization of devices on a port */
+ void (*port_init_devs)(struct hwif_s *);
+ /* routine to program host for PIO mode */
+ void (*set_pio_mode)(ide_drive_t *, const u8);
+ /* routine to program host for DMA mode */
+ void (*set_dma_mode)(ide_drive_t *, const u8);
+ /* tweaks hardware to select drive */
+ void (*selectproc)(ide_drive_t *);
+ /* chipset polling based on hba specifics */
+ int (*reset_poll)(ide_drive_t *);
+ /* chipset specific changes to default for device-hba resets */
+ void (*pre_reset)(ide_drive_t *);
+ /* routine to reset controller after a disk reset */
+ void (*resetproc)(ide_drive_t *);
+ /* special host masking for drive selection */
+ void (*maskproc)(ide_drive_t *, int);
+ /* check host's drive quirk list */
+ void (*quirkproc)(ide_drive_t *);
+
+ u8 (*mdma_filter)(ide_drive_t *);
+ u8 (*udma_filter)(ide_drive_t *);
+
+ u8 (*cable_detect)(struct hwif_s *);
+};
+
+struct ide_dma_ops {
+ void (*dma_host_set)(struct ide_drive_s *, int);
+ int (*dma_setup)(struct ide_drive_s *);
+ void (*dma_exec_cmd)(struct ide_drive_s *, u8);
+ void (*dma_start)(struct ide_drive_s *);
+ int (*dma_end)(struct ide_drive_s *);
+ int (*dma_test_irq)(struct ide_drive_s *);
+ void (*dma_lost_irq)(struct ide_drive_s *);
+ void (*dma_timeout)(struct ide_drive_s *);
+};
+
+struct ide_task_s;
+
typedef struct hwif_s {
struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
struct hwif_s *mate; /* other hwif from same PCI chip */
@@ -396,8 +437,8 @@ typedef struct hwif_s {
char name[6]; /* name of interface, eg. "ide0" */
- /* task file registers for pata and sata */
- unsigned long io_ports[IDE_NR_PORTS];
+ struct ide_io_ports io_ports;
+
unsigned long sata_scr[SATA_NR_PORTS];
ide_drive_t drives[MAX_DRIVES]; /* drive info */
@@ -421,65 +462,25 @@ typedef struct hwif_s {
struct device *dev;
- const struct ide_port_info *cds; /* chipset device struct */
-
ide_ack_intr_t *ack_intr;
void (*rw_disk)(ide_drive_t *, struct request *);
-#if 0
- ide_hwif_ops_t *hwifops;
-#else
- /* host specific initialization of devices on a port */
- void (*port_init_devs)(struct hwif_s *);
- /* routine to program host for PIO mode */
- void (*set_pio_mode)(ide_drive_t *, const u8);
- /* routine to program host for DMA mode */
- void (*set_dma_mode)(ide_drive_t *, const u8);
- /* tweaks hardware to select drive */
- void (*selectproc)(ide_drive_t *);
- /* chipset polling based on hba specifics */
- int (*reset_poll)(ide_drive_t *);
- /* chipset specific changes to default for device-hba resets */
- void (*pre_reset)(ide_drive_t *);
- /* routine to reset controller after a disk reset */
- void (*resetproc)(ide_drive_t *);
- /* special host masking for drive selection */
- void (*maskproc)(ide_drive_t *, int);
- /* check host's drive quirk list */
- void (*quirkproc)(ide_drive_t *);
-#endif
- u8 (*mdma_filter)(ide_drive_t *);
- u8 (*udma_filter)(ide_drive_t *);
-
- u8 (*cable_detect)(struct hwif_s *);
+ const struct ide_port_ops *port_ops;
+ const struct ide_dma_ops *dma_ops;
- void (*ata_input_data)(ide_drive_t *, void *, u32);
- void (*ata_output_data)(ide_drive_t *, void *, u32);
+ void (*tf_load)(ide_drive_t *, struct ide_task_s *);
+ void (*tf_read)(ide_drive_t *, struct ide_task_s *);
- void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
- void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+ void (*input_data)(ide_drive_t *, struct request *, void *, unsigned);
+ void (*output_data)(ide_drive_t *, struct request *, void *, unsigned);
- void (*dma_host_set)(ide_drive_t *, int);
- int (*dma_setup)(ide_drive_t *);
- void (*dma_exec_cmd)(ide_drive_t *, u8);
- void (*dma_start)(ide_drive_t *);
- int (*ide_dma_end)(ide_drive_t *drive);
- int (*ide_dma_test_irq)(ide_drive_t *drive);
void (*ide_dma_clear_irq)(ide_drive_t *drive);
- void (*dma_lost_irq)(ide_drive_t *drive);
- void (*dma_timeout)(ide_drive_t *drive);
void (*OUTB)(u8 addr, unsigned long port);
void (*OUTBSYNC)(ide_drive_t *drive, u8 addr, unsigned long port);
- void (*OUTW)(u16 addr, unsigned long port);
- void (*OUTSW)(unsigned long port, void *addr, u32 count);
- void (*OUTSL)(unsigned long port, void *addr, u32 count);
u8 (*INB)(unsigned long port);
- u16 (*INW)(unsigned long port);
- void (*INSW)(unsigned long port, void *addr, u32 count);
- void (*INSL)(unsigned long port, void *addr, u32 count);
/* dma physical region descriptor table (cpu view) */
unsigned int *dmatable_cpu;
@@ -504,10 +505,7 @@ typedef struct hwif_s {
unsigned long dma_base; /* base addr for dma ports */
unsigned long dma_command; /* dma command register */
- unsigned long dma_vendor1; /* dma vendor 1 register */
unsigned long dma_status; /* dma status register */
- unsigned long dma_vendor3; /* dma vendor 3 register */
- unsigned long dma_prdtable; /* actual prd table address */
unsigned long config_data; /* for use by chipset-specific code */
unsigned long select_data; /* for use by chipset-specific code */
@@ -515,14 +513,11 @@ typedef struct hwif_s {
unsigned long extra_base; /* extra addr for dma ports */
unsigned extra_ports; /* number of extra dma ports */
- unsigned noprobe : 1; /* don't probe for this interface */
unsigned present : 1; /* this interface exists */
unsigned serialized : 1; /* serialized all channel operation */
unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */
- unsigned reset : 1; /* reset after probe */
unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */
unsigned mmio : 1; /* host uses MMIO */
- unsigned straight8 : 1; /* Alan's straight 8 check */
struct device gendev;
struct device *portdev;
@@ -545,7 +540,7 @@ typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
typedef int (ide_expiry_t)(ide_drive_t *);
/* used by ide-cd, ide-floppy, etc. */
-typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
+typedef void (xfer_func_t)(ide_drive_t *, struct request *rq, void *, unsigned);
typedef struct hwgroup_s {
/* irq handler, if active */
@@ -703,10 +698,6 @@ void ide_add_generic_settings(ide_drive_t *);
read_proc_t proc_ide_read_capacity;
read_proc_t proc_ide_read_geometry;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-void ide_pci_create_host_proc(const char *, get_info_t *);
-#endif
-
/*
* Standard exit stuff:
*/
@@ -807,8 +798,21 @@ int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsig
#ifndef _IDE_C
extern ide_hwif_t ide_hwifs[]; /* master data repository */
#endif
+extern int ide_noacpi;
+extern int ide_acpigtf;
+extern int ide_acpionboot;
extern int noautodma;
+extern int ide_vlb_clk;
+extern int ide_pci_clk;
+
+ide_hwif_t *ide_find_port_slot(const struct ide_port_info *);
+
+static inline ide_hwif_t *ide_find_port(void)
+{
+ return ide_find_port_slot(NULL);
+}
+
extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
int uptodate, int nr_sectors);
@@ -818,6 +822,10 @@ extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigne
void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int,
ide_expiry_t *);
+void ide_execute_pkt_cmd(ide_drive_t *);
+
+void ide_pad_transfer(ide_drive_t *, int, int);
+
ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8);
ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
@@ -954,8 +962,7 @@ typedef struct ide_task_s {
void *special; /* valid_t generally */
} ide_task_t;
-void ide_tf_load(ide_drive_t *, ide_task_t *);
-void ide_tf_read(ide_drive_t *, ide_task_t *);
+void ide_tf_dump(const char *, struct ide_taskfile *);
extern void SELECT_DRIVE(ide_drive_t *);
extern void SELECT_MASK(ide_drive_t *, int);
@@ -1004,10 +1011,15 @@ void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int, u8
void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-void ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *);
+int ide_pci_set_master(struct pci_dev *, const char *);
+unsigned long ide_pci_dma_base(ide_hwif_t *, const struct ide_port_info *);
+int ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *);
#else
-static inline void ide_hwif_setup_dma(ide_hwif_t *hwif,
- const struct ide_port_info *d) { }
+static inline int ide_hwif_setup_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ return -EINVAL;
+}
#endif
extern void default_hwif_iops(ide_hwif_t *);
@@ -1027,8 +1039,8 @@ enum {
IDE_HFLAG_SINGLE = (1 << 1),
/* don't use legacy PIO blacklist */
IDE_HFLAG_PIO_NO_BLACKLIST = (1 << 2),
- /* don't use conservative PIO "downgrade" */
- IDE_HFLAG_PIO_NO_DOWNGRADE = (1 << 3),
+ /* set for the second port of QD65xx */
+ IDE_HFLAG_QD_2ND_PORT = (1 << 3),
/* use PIO8/9 for prefetch off/on */
IDE_HFLAG_ABUSE_PREFETCH = (1 << 4),
/* use PIO6/7 for fast-devsel off/on */
@@ -1050,14 +1062,14 @@ enum {
IDE_HFLAG_VDMA = (1 << 11),
/* ATAPI DMA is unsupported */
IDE_HFLAG_NO_ATAPI_DMA = (1 << 12),
- /* set if host is a "bootable" controller */
- IDE_HFLAG_BOOTABLE = (1 << 13),
+ /* set if host is a "non-bootable" controller */
+ IDE_HFLAG_NON_BOOTABLE = (1 << 13),
/* host doesn't support DMA */
IDE_HFLAG_NO_DMA = (1 << 14),
/* check if host is PCI IDE device before allowing DMA */
IDE_HFLAG_NO_AUTODMA = (1 << 15),
- /* don't autotune PIO */
- IDE_HFLAG_NO_AUTOTUNE = (1 << 16),
+ /* host uses MMIO */
+ IDE_HFLAG_MMIO = (1 << 16),
/* host is CS5510/CS5520 */
IDE_HFLAG_CS5520 = IDE_HFLAG_VDMA,
/* no LBA48 */
@@ -1079,8 +1091,8 @@ enum {
/* unmask IRQs */
IDE_HFLAG_UNMASK_IRQS = (1 << 25),
IDE_HFLAG_ABUSE_SET_DMA_MODE = (1 << 26),
- /* host is CY82C693 */
- IDE_HFLAG_CY82C693 = (1 << 27),
+ /* serialize ports if DMA is possible (for sl82c105) */
+ IDE_HFLAG_SERIALIZE_DMA = (1 << 27),
/* force host out of "simplex" mode */
IDE_HFLAG_CLEAR_SIMPLEX = (1 << 28),
/* DSC overlap is unsupported */
@@ -1092,9 +1104,9 @@ enum {
};
#ifdef CONFIG_BLK_DEV_OFFBOARD
-# define IDE_HFLAG_OFF_BOARD IDE_HFLAG_BOOTABLE
-#else
# define IDE_HFLAG_OFF_BOARD 0
+#else
+# define IDE_HFLAG_OFF_BOARD IDE_HFLAG_NON_BOOTABLE
#endif
struct ide_port_info {
@@ -1102,10 +1114,14 @@ struct ide_port_info {
unsigned int (*init_chipset)(struct pci_dev *, const char *);
void (*init_iops)(ide_hwif_t *);
void (*init_hwif)(ide_hwif_t *);
- void (*init_dma)(ide_hwif_t *, unsigned long);
+ int (*init_dma)(ide_hwif_t *,
+ const struct ide_port_info *);
+
+ const struct ide_port_ops *port_ops;
+ const struct ide_dma_ops *dma_ops;
+
ide_pci_enablebit_t enablebits[2];
hwif_chipset_t chipset;
- u8 extra;
u32 host_flags;
u8 pio_mask;
u8 swdma_mask;
@@ -1152,13 +1168,16 @@ void ide_destroy_dmatable(ide_drive_t *);
#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
extern int ide_build_dmatable(ide_drive_t *, struct request *);
-extern int ide_release_dma(ide_hwif_t *);
-extern void ide_setup_dma(ide_hwif_t *, unsigned long);
+int ide_allocate_dma_engine(ide_hwif_t *);
+void ide_release_dma_engine(ide_hwif_t *);
+void ide_setup_dma(ide_hwif_t *, unsigned long);
void ide_dma_host_set(ide_drive_t *, int);
extern int ide_dma_setup(ide_drive_t *);
+void ide_dma_exec_cmd(ide_drive_t *, u8);
extern void ide_dma_start(ide_drive_t *);
extern int __ide_dma_end(ide_drive_t *);
+int ide_dma_test_irq(ide_drive_t *);
extern void ide_dma_lost_irq(ide_drive_t *);
extern void ide_dma_timeout(ide_drive_t *);
#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
@@ -1176,7 +1195,7 @@ static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
#endif /* CONFIG_BLK_DEV_IDEDMA */
#ifndef CONFIG_BLK_DEV_IDEDMA_SFF
-static inline void ide_release_dma(ide_hwif_t *drive) {;}
+static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
#endif
#ifdef CONFIG_BLK_DEV_IDEACPI
@@ -1196,17 +1215,18 @@ static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
#endif
void ide_remove_port_from_hwgroup(ide_hwif_t *);
-extern int ide_hwif_request_regions(ide_hwif_t *hwif);
-extern void ide_hwif_release_regions(ide_hwif_t* hwif);
-void ide_unregister(unsigned int);
+void ide_unregister(ide_hwif_t *);
void ide_register_region(struct gendisk *);
void ide_unregister_region(struct gendisk *);
void ide_undecoded_slave(ide_drive_t *);
+void ide_port_apply_params(ide_hwif_t *);
+
int ide_device_add_all(u8 *idx, const struct ide_port_info *);
int ide_device_add(u8 idx[4], const struct ide_port_info *);
+int ide_legacy_device_add(const struct ide_port_info *, unsigned long);
void ide_port_unregister_devices(ide_hwif_t *);
void ide_port_scan(ide_hwif_t *);
@@ -1315,51 +1335,27 @@ static inline void ide_set_irq(ide_drive_t *drive, int on)
{
ide_hwif_t *hwif = drive->hwif;
- hwif->OUTB(drive->ctl | (on ? 0 : 2),
- hwif->io_ports[IDE_CONTROL_OFFSET]);
+ hwif->OUTB(drive->ctl | (on ? 0 : 2), hwif->io_ports.ctl_addr);
}
static inline u8 ide_read_status(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
- return hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ return hwif->INB(hwif->io_ports.status_addr);
}
static inline u8 ide_read_altstatus(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
- return hwif->INB(hwif->io_ports[IDE_CONTROL_OFFSET]);
+ return hwif->INB(hwif->io_ports.ctl_addr);
}
static inline u8 ide_read_error(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
- return hwif->INB(hwif->io_ports[IDE_ERROR_OFFSET]);
+ return hwif->INB(hwif->io_ports.error_addr);
}
-
-/*
- * Too bad. The drive wants to send us data which we are not ready to accept.
- * Just throw it away.
- */
-static inline void ide_atapi_discard_data(ide_drive_t *drive, unsigned bcount)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- /* FIXME: use ->atapi_input_bytes */
- while (bcount--)
- (void)hwif->INB(hwif->io_ports[IDE_DATA_OFFSET]);
-}
-
-static inline void ide_atapi_write_zeros(ide_drive_t *drive, unsigned bcount)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- /* FIXME: use ->atapi_output_bytes */
- while (bcount--)
- hwif->OUTB(0, hwif->io_ports[IDE_DATA_OFFSET]);
-}
-
#endif /* _IDE_H */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 37a6f5bc4a92..bf6b8a61f8db 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -9,6 +9,7 @@
#include <linux/ipc.h>
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
+#include <linux/securebits.h>
#include <net/net_namespace.h>
#define INIT_FDTABLE \
@@ -172,7 +173,7 @@ extern struct group_info init_groups;
.cap_inheritable = CAP_INIT_INH_SET, \
.cap_permitted = CAP_FULL_SET, \
.cap_bset = CAP_INIT_BSET, \
- .keep_capabilities = 0, \
+ .securebits = SECUREBITS_DEFAULT, \
.user = INIT_USER, \
.comm = "swapper", \
.thread = INIT_THREAD, \
diff --git a/include/linux/input.h b/include/linux/input.h
index cae2c35d1206..28a094fcfe20 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -1025,10 +1025,6 @@ struct ff_effect {
* @node: used to place the device onto input_dev_list
*/
struct input_dev {
- /* private: */
- void *private; /* do not use */
- /* public: */
-
const char *name;
const char *phys;
const char *uniq;
@@ -1238,12 +1234,12 @@ static inline void input_put_device(struct input_dev *dev)
static inline void *input_get_drvdata(struct input_dev *dev)
{
- return dev->private;
+ return dev_get_drvdata(&dev->dev);
}
static inline void input_set_drvdata(struct input_dev *dev, void *data)
{
- dev->private = data;
+ dev_set_drvdata(&dev->dev, data);
}
int __must_check input_register_device(struct input_dev *);
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 65c2d70853e9..a3c984d780f0 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -33,6 +33,7 @@ struct keyboard_notifier_param {
struct vc_data *vc; /* VC on which the keyboard press was done */
int down; /* Pressure of the key? */
int shift; /* Current shift mask */
+ int ledstate; /* Current led state */
unsigned int value; /* keycode, unicode value or keysym */
};
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 0f28486f6360..1036631ff4fa 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -173,6 +173,13 @@ struct kretprobe_blackpoint {
const char *name;
void *addr;
};
+
+struct kprobe_blackpoint {
+ const char *name;
+ unsigned long start_addr;
+ unsigned long range;
+};
+
extern struct kretprobe_blackpoint kretprobe_blacklist[];
static inline void kretprobe_assert(struct kretprobe_instance *ri,
@@ -227,15 +234,21 @@ static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void)
int register_kprobe(struct kprobe *p);
void unregister_kprobe(struct kprobe *p);
+int register_kprobes(struct kprobe **kps, int num);
+void unregister_kprobes(struct kprobe **kps, int num);
int setjmp_pre_handler(struct kprobe *, struct pt_regs *);
int longjmp_break_handler(struct kprobe *, struct pt_regs *);
int register_jprobe(struct jprobe *p);
void unregister_jprobe(struct jprobe *p);
+int register_jprobes(struct jprobe **jps, int num);
+void unregister_jprobes(struct jprobe **jps, int num);
void jprobe_return(void);
unsigned long arch_deref_entry_point(void *);
int register_kretprobe(struct kretprobe *rp);
void unregister_kretprobe(struct kretprobe *rp);
+int register_kretprobes(struct kretprobe **rps, int num);
+void unregister_kretprobes(struct kretprobe **rps, int num);
void kprobe_flush_task(struct task_struct *tk);
void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
@@ -254,16 +267,30 @@ static inline int register_kprobe(struct kprobe *p)
{
return -ENOSYS;
}
+static inline int register_kprobes(struct kprobe **kps, int num)
+{
+ return -ENOSYS;
+}
static inline void unregister_kprobe(struct kprobe *p)
{
}
+static inline void unregister_kprobes(struct kprobe **kps, int num)
+{
+}
static inline int register_jprobe(struct jprobe *p)
{
return -ENOSYS;
}
+static inline int register_jprobes(struct jprobe **jps, int num)
+{
+ return -ENOSYS;
+}
static inline void unregister_jprobe(struct jprobe *p)
{
}
+static inline void unregister_jprobes(struct jprobe **jps, int num)
+{
+}
static inline void jprobe_return(void)
{
}
@@ -271,9 +298,16 @@ static inline int register_kretprobe(struct kretprobe *rp)
{
return -ENOSYS;
}
+static inline int register_kretprobes(struct kretprobe **rps, int num)
+{
+ return -ENOSYS;
+}
static inline void unregister_kretprobe(struct kretprobe *rp)
{
}
+static inline void unregister_kretprobes(struct kretprobe **rps, int num)
+{
+}
static inline void kprobe_flush_task(struct task_struct *tk)
{
}
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index c1ec04fd000d..a281afeddfbb 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -8,11 +8,18 @@
*/
#include <asm/types.h>
+#include <linux/compiler.h>
#include <linux/ioctl.h>
#include <asm/kvm.h>
#define KVM_API_VERSION 12
+/* for KVM_TRACE_ENABLE */
+struct kvm_user_trace_setup {
+ __u32 buf_size; /* sub_buffer size of each per-cpu */
+ __u32 buf_nr; /* the number of sub_buffers of each per-cpu */
+};
+
/* for KVM_CREATE_MEMORY_REGION */
struct kvm_memory_region {
__u32 slot;
@@ -73,6 +80,9 @@ struct kvm_irqchip {
#define KVM_EXIT_INTR 10
#define KVM_EXIT_SET_TPR 11
#define KVM_EXIT_TPR_ACCESS 12
+#define KVM_EXIT_S390_SIEIC 13
+#define KVM_EXIT_S390_RESET 14
+#define KVM_EXIT_DCR 15
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
@@ -137,6 +147,27 @@ struct kvm_run {
__u32 is_write;
__u32 pad;
} tpr_access;
+ /* KVM_EXIT_S390_SIEIC */
+ struct {
+ __u8 icptcode;
+ __u64 mask; /* psw upper half */
+ __u64 addr; /* psw lower half */
+ __u16 ipa;
+ __u32 ipb;
+ } s390_sieic;
+ /* KVM_EXIT_S390_RESET */
+#define KVM_S390_RESET_POR 1
+#define KVM_S390_RESET_CLEAR 2
+#define KVM_S390_RESET_SUBSYSTEM 4
+#define KVM_S390_RESET_CPU_INIT 8
+#define KVM_S390_RESET_IPL 16
+ __u64 s390_reset_flags;
+ /* KVM_EXIT_DCR */
+ struct {
+ __u32 dcrn;
+ __u32 data;
+ __u8 is_write;
+ } dcr;
/* Fix the size of the union. */
char padding[256];
};
@@ -204,6 +235,74 @@ struct kvm_vapic_addr {
__u64 vapic_addr;
};
+/* for KVM_SET_MPSTATE */
+
+#define KVM_MP_STATE_RUNNABLE 0
+#define KVM_MP_STATE_UNINITIALIZED 1
+#define KVM_MP_STATE_INIT_RECEIVED 2
+#define KVM_MP_STATE_HALTED 3
+#define KVM_MP_STATE_SIPI_RECEIVED 4
+
+struct kvm_mp_state {
+ __u32 mp_state;
+};
+
+struct kvm_s390_psw {
+ __u64 mask;
+ __u64 addr;
+};
+
+/* valid values for type in kvm_s390_interrupt */
+#define KVM_S390_SIGP_STOP 0xfffe0000u
+#define KVM_S390_PROGRAM_INT 0xfffe0001u
+#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
+#define KVM_S390_RESTART 0xfffe0003u
+#define KVM_S390_INT_VIRTIO 0xffff2603u
+#define KVM_S390_INT_SERVICE 0xffff2401u
+#define KVM_S390_INT_EMERGENCY 0xffff1201u
+
+struct kvm_s390_interrupt {
+ __u32 type;
+ __u32 parm;
+ __u64 parm64;
+};
+
+#define KVM_TRC_SHIFT 16
+/*
+ * kvm trace categories
+ */
+#define KVM_TRC_ENTRYEXIT (1 << KVM_TRC_SHIFT)
+#define KVM_TRC_HANDLER (1 << (KVM_TRC_SHIFT + 1)) /* only 12 bits */
+
+/*
+ * kvm trace action
+ */
+#define KVM_TRC_VMENTRY (KVM_TRC_ENTRYEXIT + 0x01)
+#define KVM_TRC_VMEXIT (KVM_TRC_ENTRYEXIT + 0x02)
+#define KVM_TRC_PAGE_FAULT (KVM_TRC_HANDLER + 0x01)
+
+#define KVM_TRC_HEAD_SIZE 12
+#define KVM_TRC_CYCLE_SIZE 8
+#define KVM_TRC_EXTRA_MAX 7
+
+/* This structure represents a single trace buffer record. */
+struct kvm_trace_rec {
+ __u32 event:28;
+ __u32 extra_u32:3;
+ __u32 cycle_in:1;
+ __u32 pid;
+ __u32 vcpu_id;
+ union {
+ struct {
+ __u32 cycle_lo, cycle_hi;
+ __u32 extra_u32[KVM_TRC_EXTRA_MAX];
+ } cycle;
+ struct {
+ __u32 extra_u32[KVM_TRC_EXTRA_MAX];
+ } nocycle;
+ } u;
+};
+
#define KVMIO 0xAE
/*
@@ -212,6 +311,8 @@ struct kvm_vapic_addr {
#define KVM_GET_API_VERSION _IO(KVMIO, 0x00)
#define KVM_CREATE_VM _IO(KVMIO, 0x01) /* returns a VM fd */
#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list)
+
+#define KVM_S390_ENABLE_SIE _IO(KVMIO, 0x06)
/*
* Check if a kvm extension is available. Argument is extension number,
* return is 1 (yes) or 0 (no, sorry).
@@ -222,7 +323,12 @@ struct kvm_vapic_addr {
*/
#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
#define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
-
+/*
+ * ioctls for kvm trace
+ */
+#define KVM_TRACE_ENABLE _IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
+#define KVM_TRACE_PAUSE _IO(KVMIO, 0x07)
+#define KVM_TRACE_DISABLE _IO(KVMIO, 0x08)
/*
* Extension capability list.
*/
@@ -233,6 +339,13 @@ struct kvm_vapic_addr {
#define KVM_CAP_SET_TSS_ADDR 4
#define KVM_CAP_VAPIC 6
#define KVM_CAP_EXT_CPUID 7
+#define KVM_CAP_CLOCKSOURCE 8
+#define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
+#define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */
+#define KVM_CAP_PIT 11
+#define KVM_CAP_NOP_IO_DELAY 12
+#define KVM_CAP_PV_MMU 13
+#define KVM_CAP_MP_STATE 14
/*
* ioctls for VM fds
@@ -255,6 +368,9 @@ struct kvm_vapic_addr {
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)
#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)
+#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
+#define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state)
+#define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state)
/*
* ioctls for vcpu fds
@@ -281,5 +397,17 @@ struct kvm_vapic_addr {
#define KVM_TPR_ACCESS_REPORTING _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
/* Available with KVM_CAP_VAPIC */
#define KVM_SET_VAPIC_ADDR _IOW(KVMIO, 0x93, struct kvm_vapic_addr)
+/* valid for virtual machine (for floating interrupt)_and_ vcpu */
+#define KVM_S390_INTERRUPT _IOW(KVMIO, 0x94, struct kvm_s390_interrupt)
+/* store status for s390 */
+#define KVM_S390_STORE_STATUS_NOADDR (-1ul)
+#define KVM_S390_STORE_STATUS_PREFIXED (-2ul)
+#define KVM_S390_STORE_STATUS _IOW(KVMIO, 0x95, unsigned long)
+/* initial ipl psw for s390 */
+#define KVM_S390_SET_INITIAL_PSW _IOW(KVMIO, 0x96, struct kvm_s390_psw)
+/* initial reset for s390 */
+#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
+#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
+#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
#endif
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 928b0d59e9ba..398978972b7a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/preempt.h>
+#include <linux/marker.h>
#include <asm/signal.h>
#include <linux/kvm.h>
@@ -24,29 +25,18 @@
#include <asm/kvm_host.h>
-#define KVM_MAX_VCPUS 4
-#define KVM_MEMORY_SLOTS 8
-/* memory slots that does not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS 4
-
-#define KVM_PIO_PAGE_OFFSET 1
-
/*
* vcpu->requests bit members
*/
#define KVM_REQ_TLB_FLUSH 0
#define KVM_REQ_MIGRATE_TIMER 1
#define KVM_REQ_REPORT_TPR_ACCESS 2
+#define KVM_REQ_MMU_RELOAD 3
+#define KVM_REQ_TRIPLE_FAULT 4
struct kvm_vcpu;
extern struct kmem_cache *kvm_vcpu_cache;
-struct kvm_guest_debug {
- int enabled;
- unsigned long bp[4];
- int singlestep;
-};
-
/*
* It would be nice to use something smarter than a linear search, TBD...
* Thankfully we dont expect many devices to register (famous last words :),
@@ -67,7 +57,9 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
struct kvm_vcpu {
struct kvm *kvm;
+#ifdef CONFIG_PREEMPT_NOTIFIERS
struct preempt_notifier preempt_notifier;
+#endif
int vcpu_id;
struct mutex mutex;
int cpu;
@@ -100,6 +92,10 @@ struct kvm_memory_slot {
unsigned long flags;
unsigned long *rmap;
unsigned long *dirty_bitmap;
+ struct {
+ unsigned long rmap_pde;
+ int write_count;
+ } *lpage_info;
unsigned long userspace_addr;
int user_alloc;
};
@@ -114,11 +110,11 @@ struct kvm {
KVM_PRIVATE_MEM_SLOTS];
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
struct list_head vm_list;
- struct file *filp;
struct kvm_io_bus mmio_bus;
struct kvm_io_bus pio_bus;
struct kvm_vm_stat stat;
struct kvm_arch arch;
+ atomic_t users_count;
};
/* The guest did something we don't support. */
@@ -145,14 +141,19 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
struct module *module);
void kvm_exit(void);
+void kvm_get_kvm(struct kvm *kvm);
+void kvm_put_kvm(struct kvm *kvm);
+
#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
extern struct page *bad_page;
+extern pfn_t bad_pfn;
int is_error_page(struct page *page);
+int is_error_pfn(pfn_t pfn);
int kvm_is_error_hva(unsigned long addr);
int kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
@@ -166,8 +167,19 @@ int kvm_arch_set_memory_region(struct kvm *kvm,
int user_alloc);
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
+unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
void kvm_release_page_clean(struct page *page);
void kvm_release_page_dirty(struct page *page);
+void kvm_set_page_dirty(struct page *page);
+void kvm_set_page_accessed(struct page *page);
+
+pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
+void kvm_release_pfn_dirty(pfn_t);
+void kvm_release_pfn_clean(pfn_t pfn);
+void kvm_set_pfn_dirty(pfn_t pfn);
+void kvm_set_pfn_accessed(pfn_t pfn);
+void kvm_get_pfn(pfn_t pfn);
+
int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
int len);
int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
@@ -188,6 +200,7 @@ void kvm_resched(struct kvm_vcpu *vcpu);
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_flush_remote_tlbs(struct kvm *kvm);
+void kvm_reload_remote_mmus(struct kvm *kvm);
long kvm_arch_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg);
@@ -223,6 +236,10 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs);
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs);
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state);
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state);
int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
struct kvm_debug_guest *dbg);
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
@@ -255,6 +272,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm);
int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
static inline void kvm_guest_enter(void)
@@ -296,5 +314,18 @@ struct kvm_stats_debugfs_item {
struct dentry *dentry;
};
extern struct kvm_stats_debugfs_item debugfs_entries[];
+extern struct dentry *kvm_debugfs_dir;
+
+#ifdef CONFIG_KVM_TRACE
+int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg);
+void kvm_trace_cleanup(void);
+#else
+static inline
+int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg)
+{
+ return -EINVAL;
+}
+#define kvm_trace_cleanup() ((void)0)
+#endif
#endif
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index 5497aac0d2f8..3ddce03766ca 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -11,8 +11,11 @@
/* Return values for hypercalls */
#define KVM_ENOSYS 1000
+#define KVM_EFAULT EFAULT
+#define KVM_E2BIG E2BIG
-#define KVM_HC_VAPIC_POLL_IRQ 1
+#define KVM_HC_VAPIC_POLL_IRQ 1
+#define KVM_HC_MMU_OP 2
/*
* hypercalls use architecture specific
@@ -20,6 +23,12 @@
#include <asm/kvm_para.h>
#ifdef __KERNEL__
+#ifdef CONFIG_KVM_GUEST
+void __init kvm_guest_init(void);
+#else
+#define kvm_guest_init() do { } while (0)
+#endif
+
static inline int kvm_para_has_feature(unsigned int feature)
{
if (kvm_arch_para_features() & (1UL << feature))
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index 1c4e46decb22..9b6f395c9625 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -38,6 +38,8 @@ typedef unsigned long hva_t;
typedef u64 hpa_t;
typedef unsigned long hfn_t;
+typedef hfn_t pfn_t;
+
struct kvm_pio_request {
unsigned long count;
int cur_count;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index b07e3d400bd6..519df72e939d 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -35,8 +35,11 @@ struct led_classdev {
#define LED_SUSPENDED (1 << 0)
/* Set LED brightness level */
+ /* Must not sleep, use a workqueue if needed */
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
+ /* Get LED brightness level */
+ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
/* Activate hardware accelerated blink */
int (*blink_set)(struct led_classdev *led_cdev,
@@ -126,6 +129,9 @@ struct gpio_led {
struct gpio_led_platform_data {
int num_leds;
struct gpio_led *leds;
+ int (*gpio_blink_set)(unsigned gpio,
+ unsigned long *delay_on,
+ unsigned long *delay_off);
};
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 07ed56f7a767..395a523d8c30 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -847,7 +847,6 @@ static inline int ata_port_is_dummy(struct ata_port *ap)
return ap->ops == &ata_dummy_port_ops;
}
-extern void sata_print_link_status(struct ata_link *link);
extern void ata_port_probe(struct ata_port *);
extern int sata_set_spd(struct ata_link *link);
extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
diff --git a/include/linux/list.h b/include/linux/list.h
index dac16f99c701..b4a939b6b625 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -319,6 +319,15 @@ static inline int list_empty_careful(const struct list_head *head)
return (next == head) && (next == head->prev);
}
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 94649a8da014..102d928f7206 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -194,7 +194,7 @@ void nsm_release(struct nsm_handle *);
* This is used in garbage collection and resource reclaim
* A return value != 0 means destroy the lock/block/share
*/
-typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref);
+typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
/*
* Server-side lock handling
@@ -220,6 +220,12 @@ void nlmsvc_mark_resources(void);
void nlmsvc_free_host_resources(struct nlm_host *);
void nlmsvc_invalidate_all(void);
+/*
+ * Cluster failover support
+ */
+int nlmsvc_unlock_all_by_sb(struct super_block *sb);
+int nlmsvc_unlock_all_by_ip(__be32 server_addr);
+
static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
{
return file->f_file->f_path.dentry->d_inode;
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 8fee7a45736b..73e358612eaf 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -8,8 +8,18 @@
struct page;
struct zone;
struct pglist_data;
+struct mem_section;
#ifdef CONFIG_MEMORY_HOTPLUG
+
+/*
+ * Magic number for free bootmem.
+ * The normal smallest mapcount is -1. Here is smaller value than it.
+ */
+#define SECTION_INFO 0xfffffffe
+#define MIX_INFO 0xfffffffd
+#define NODE_INFO 0xfffffffc
+
/*
* pgdat resizing functions
*/
@@ -64,9 +74,11 @@ extern int offline_pages(unsigned long, unsigned long, unsigned long);
/* reasonably generic interface to expand the physical pages in a zone */
extern int __add_pages(struct zone *zone, unsigned long start_pfn,
unsigned long nr_pages);
+extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
+ unsigned long nr_pages);
/*
- * Walk thorugh all memory which is registered as resource.
+ * Walk through all memory which is registered as resource.
* arg is (start_pfn, nr_pages, private_arg_pointer)
*/
extern int walk_memory_resource(unsigned long start_pfn,
@@ -142,6 +154,18 @@ static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
#endif /* CONFIG_NUMA */
#endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+static inline void register_page_bootmem_info_node(struct pglist_data *pgdat)
+{
+}
+static inline void put_page_bootmem(struct page *page)
+{
+}
+#else
+extern void register_page_bootmem_info_node(struct pglist_data *pgdat);
+extern void put_page_bootmem(struct page *page);
+#endif
+
#else /* ! CONFIG_MEMORY_HOTPLUG */
/*
* Stub functions for when hotplug is off
@@ -169,6 +193,10 @@ static inline int mhp_notimplemented(const char *func)
return -ENOSYS;
}
+static inline void register_page_bootmem_info_node(struct pglist_data *pgdat)
+{
+}
+
#endif /* ! CONFIG_MEMORY_HOTPLUG */
extern int add_memory(int nid, u64 start, u64 size);
@@ -176,5 +204,8 @@ extern int arch_add_memory(int nid, u64 start, u64 size);
extern int remove_memory(u64 start, u64 size);
extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
int nr_pages);
+extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms);
+extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
+ unsigned long pnum);
#endif /* __LINUX_MEMORY_HOTPLUG_H */
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 59c4865bc85f..3a39570b81b8 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -8,15 +8,32 @@
* Copyright 2003,2004 Andi Kleen SuSE Labs
*/
+/*
+ * Both the MPOL_* mempolicy mode and the MPOL_F_* optional mode flags are
+ * passed by the user to either set_mempolicy() or mbind() in an 'int' actual.
+ * The MPOL_MODE_FLAGS macro determines the legal set of optional mode flags.
+ */
+
/* Policies */
-#define MPOL_DEFAULT 0
-#define MPOL_PREFERRED 1
-#define MPOL_BIND 2
-#define MPOL_INTERLEAVE 3
+enum {
+ MPOL_DEFAULT,
+ MPOL_PREFERRED,
+ MPOL_BIND,
+ MPOL_INTERLEAVE,
+ MPOL_MAX, /* always last member of enum */
+};
-#define MPOL_MAX MPOL_INTERLEAVE
+/* Flags for set_mempolicy */
+#define MPOL_F_STATIC_NODES (1 << 15)
+#define MPOL_F_RELATIVE_NODES (1 << 14)
-/* Flags for get_mem_policy */
+/*
+ * MPOL_MODE_FLAGS is the union of all possible optional mode flags passed to
+ * either set_mempolicy() or mbind().
+ */
+#define MPOL_MODE_FLAGS (MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES)
+
+/* Flags for get_mempolicy */
#define MPOL_F_NODE (1<<0) /* return next IL mode instead of node mask */
#define MPOL_F_ADDR (1<<1) /* look up vma using address */
#define MPOL_F_MEMS_ALLOWED (1<<2) /* return allowed memories */
@@ -27,6 +44,14 @@
#define MPOL_MF_MOVE_ALL (1<<2) /* Move every page to conform to mapping */
#define MPOL_MF_INTERNAL (1<<3) /* Internal flags start here */
+/*
+ * Internal flags that share the struct mempolicy flags word with
+ * "mode flags". These flags are allocated from bit 0 up, as they
+ * are never OR'ed into the mode in mempolicy API arguments.
+ */
+#define MPOL_F_SHARED (1 << 0) /* identify shared policies */
+#define MPOL_F_LOCAL (1 << 1) /* preferred local allocation */
+
#ifdef __KERNEL__
#include <linux/mmzone.h>
@@ -35,7 +60,6 @@
#include <linux/spinlock.h>
#include <linux/nodemask.h>
-struct vm_area_struct;
struct mm_struct;
#ifdef CONFIG_NUMA
@@ -54,22 +78,27 @@ struct mm_struct;
* mmap_sem.
*
* Freeing policy:
- * When policy is MPOL_BIND v.zonelist is kmalloc'ed and must be kfree'd.
- * All other policies don't have any external state. mpol_free() handles this.
+ * Mempolicy objects are reference counted. A mempolicy will be freed when
+ * mpol_put() decrements the reference count to zero.
*
- * Copying policy objects:
- * For MPOL_BIND the zonelist must be always duplicated. mpol_clone() does this.
+ * Duplicating policy objects:
+ * mpol_dup() allocates a new mempolicy and copies the specified mempolicy
+ * to the new storage. The reference count of the new object is initialized
+ * to 1, representing the caller of mpol_dup().
*/
struct mempolicy {
atomic_t refcnt;
- short policy; /* See MPOL_* above */
+ unsigned short mode; /* See MPOL_* above */
+ unsigned short flags; /* See set_mempolicy() MPOL_F_* above */
union {
- struct zonelist *zonelist; /* bind */
short preferred_node; /* preferred */
- nodemask_t nodes; /* interleave */
+ nodemask_t nodes; /* interleave/bind */
/* undefined for default */
} v;
- nodemask_t cpuset_mems_allowed; /* mempolicy relative to these nodes */
+ union {
+ nodemask_t cpuset_mems_allowed; /* relative to these nodes */
+ nodemask_t user_nodemask; /* nodemask passed by user */
+ } w;
};
/*
@@ -77,18 +106,43 @@ struct mempolicy {
* The default fast path of a NULL MPOL_DEFAULT policy is always inlined.
*/
-extern void __mpol_free(struct mempolicy *pol);
-static inline void mpol_free(struct mempolicy *pol)
+extern void __mpol_put(struct mempolicy *pol);
+static inline void mpol_put(struct mempolicy *pol)
{
if (pol)
- __mpol_free(pol);
+ __mpol_put(pol);
}
-extern struct mempolicy *__mpol_copy(struct mempolicy *pol);
-static inline struct mempolicy *mpol_copy(struct mempolicy *pol)
+/*
+ * Does mempolicy pol need explicit unref after use?
+ * Currently only needed for shared policies.
+ */
+static inline int mpol_needs_cond_ref(struct mempolicy *pol)
+{
+ return (pol && (pol->flags & MPOL_F_SHARED));
+}
+
+static inline void mpol_cond_put(struct mempolicy *pol)
+{
+ if (mpol_needs_cond_ref(pol))
+ __mpol_put(pol);
+}
+
+extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
+ struct mempolicy *frompol);
+static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol,
+ struct mempolicy *frompol)
+{
+ if (!frompol)
+ return frompol;
+ return __mpol_cond_copy(tompol, frompol);
+}
+
+extern struct mempolicy *__mpol_dup(struct mempolicy *pol);
+static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
{
if (pol)
- pol = __mpol_copy(pol);
+ pol = __mpol_dup(pol);
return pol;
}
@@ -108,11 +162,6 @@ static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)
return 1;
return __mpol_equal(a, b);
}
-#define vma_mpol_equal(a,b) mpol_equal(vma_policy(a), vma_policy(b))
-
-/* Could later add inheritance of the process policy here. */
-
-#define mpol_set_vma_default(vma) ((vma)->vm_policy = NULL)
/*
* Tree of shared policies for a shared memory region.
@@ -133,8 +182,7 @@ struct shared_policy {
spinlock_t lock;
};
-void mpol_shared_policy_init(struct shared_policy *info, int policy,
- nodemask_t *nodes);
+void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
int mpol_set_shared_policy(struct shared_policy *info,
struct vm_area_struct *vma,
struct mempolicy *new);
@@ -149,9 +197,9 @@ extern void mpol_rebind_task(struct task_struct *tsk,
extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
extern void mpol_fix_fork_child_flag(struct task_struct *p);
-extern struct mempolicy default_policy;
extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
- unsigned long addr, gfp_t gfp_flags, struct mempolicy **mpol);
+ unsigned long addr, gfp_t gfp_flags,
+ struct mempolicy **mpol, nodemask_t **nodemask);
extern unsigned slab_node(struct mempolicy *policy);
extern enum zone_type policy_zone;
@@ -165,6 +213,13 @@ static inline void check_highest_zone(enum zone_type k)
int do_migrate_pages(struct mm_struct *mm,
const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags);
+
+#ifdef CONFIG_TMPFS
+extern int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context);
+
+extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
+ int no_context);
+#endif
#else
struct mempolicy {};
@@ -173,19 +228,26 @@ static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)
{
return 1;
}
-#define vma_mpol_equal(a,b) 1
-#define mpol_set_vma_default(vma) do {} while(0)
+static inline void mpol_put(struct mempolicy *p)
+{
+}
+
+static inline void mpol_cond_put(struct mempolicy *pol)
+{
+}
-static inline void mpol_free(struct mempolicy *p)
+static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to,
+ struct mempolicy *from)
{
+ return from;
}
static inline void mpol_get(struct mempolicy *pol)
{
}
-static inline struct mempolicy *mpol_copy(struct mempolicy *old)
+static inline struct mempolicy *mpol_dup(struct mempolicy *old)
{
return NULL;
}
@@ -199,8 +261,8 @@ static inline int mpol_set_shared_policy(struct shared_policy *info,
return -EINVAL;
}
-static inline void mpol_shared_policy_init(struct shared_policy *info,
- int policy, nodemask_t *nodes)
+static inline void mpol_shared_policy_init(struct shared_policy *sp,
+ struct mempolicy *mpol)
{
}
@@ -239,9 +301,12 @@ static inline void mpol_fix_fork_child_flag(struct task_struct *p)
}
static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
- unsigned long addr, gfp_t gfp_flags, struct mempolicy **mpol)
+ unsigned long addr, gfp_t gfp_flags,
+ struct mempolicy **mpol, nodemask_t **nodemask)
{
- return NODE_DATA(0)->node_zonelists + gfp_zone(gfp_flags);
+ *mpol = NULL;
+ *nodemask = NULL;
+ return node_zonelist(0, gfp_flags);
}
static inline int do_migrate_pages(struct mm_struct *mm,
@@ -254,6 +319,21 @@ static inline int do_migrate_pages(struct mm_struct *mm,
static inline void check_highest_zone(int k)
{
}
+
+#ifdef CONFIG_TMPFS
+static inline int mpol_parse_str(char *str, struct mempolicy **mpol,
+ int no_context)
+{
+ return 1; /* error */
+}
+
+static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
+ int no_context)
+{
+ return 0;
+}
+#endif
+
#endif /* CONFIG_NUMA */
#endif /* __KERNEL__ */
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index ff7df1a2222f..9fa1a8002ce2 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -208,6 +208,38 @@ struct mlx4_mtt {
int page_shift;
};
+enum {
+ MLX4_DB_PER_PAGE = PAGE_SIZE / 4
+};
+
+struct mlx4_db_pgdir {
+ struct list_head list;
+ DECLARE_BITMAP(order0, MLX4_DB_PER_PAGE);
+ DECLARE_BITMAP(order1, MLX4_DB_PER_PAGE / 2);
+ unsigned long *bits[2];
+ __be32 *db_page;
+ dma_addr_t db_dma;
+};
+
+struct mlx4_ib_user_db_page;
+
+struct mlx4_db {
+ __be32 *db;
+ union {
+ struct mlx4_db_pgdir *pgdir;
+ struct mlx4_ib_user_db_page *user_page;
+ } u;
+ dma_addr_t dma;
+ int index;
+ int order;
+};
+
+struct mlx4_hwq_resources {
+ struct mlx4_db db;
+ struct mlx4_mtt mtt;
+ struct mlx4_buf buf;
+};
+
struct mlx4_mr {
struct mlx4_mtt mtt;
u64 iova;
@@ -341,6 +373,14 @@ int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
struct mlx4_buf *buf);
+int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order);
+void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db);
+
+int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres,
+ int size, int max_direct);
+void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres,
+ int size);
+
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq);
void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index a5e43febee4f..7f128b266faa 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -296,6 +296,10 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
struct mlx4_qp_context *context);
+int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+ struct mlx4_qp_context *context,
+ struct mlx4_qp *qp, enum mlx4_qp_state *qp_state);
+
static inline struct mlx4_qp *__mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
{
return radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1));
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b695875d63e3..8b7f4a5d4f6a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -107,6 +107,7 @@ extern unsigned int kobjsize(const void *objp);
#define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */
#define VM_CAN_NONLINEAR 0x08000000 /* Has ->fault & does nonlinear pages */
+#define VM_MIXEDMAP 0x10000000 /* Can contain "struct page" and pure PFN pages */
#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
@@ -164,8 +165,6 @@ struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
- struct page *(*nopage)(struct vm_area_struct *area,
- unsigned long address, int *type);
unsigned long (*nopfn)(struct vm_area_struct *area,
unsigned long address);
@@ -173,7 +172,25 @@ struct vm_operations_struct {
* writable, if an error is returned it will cause a SIGBUS */
int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page);
#ifdef CONFIG_NUMA
+ /*
+ * set_policy() op must add a reference to any non-NULL @new mempolicy
+ * to hold the policy upon return. Caller should pass NULL @new to
+ * remove a policy and fall back to surrounding context--i.e. do not
+ * install a MPOL_DEFAULT policy, nor the task or system default
+ * mempolicy.
+ */
int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
+
+ /*
+ * get_policy() op must add reference [mpol_get()] to any policy at
+ * (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure
+ * in mm/mempolicy.c will do this automatically.
+ * get_policy() must NOT add a ref if the policy at (vma,addr) is not
+ * marked as MPOL_SHARED. vma policies are protected by the mmap_sem.
+ * If no [shared/vma] mempolicy exists at the addr, get_policy() op
+ * must return NULL--i.e., do not "fallback" to task or system default
+ * policy.
+ */
struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
unsigned long addr);
int (*migrate)(struct vm_area_struct *vma, const nodemask_t *from,
@@ -397,11 +414,11 @@ static inline void set_compound_order(struct page *page, unsigned long order)
* we have run out of space and have to fall back to an
* alternate (slower) way of determining the node.
*
- * No sparsemem: | NODE | ZONE | ... | FLAGS |
- * with space for node: | SECTION | NODE | ZONE | ... | FLAGS |
- * no space for node: | SECTION | ZONE | ... | FLAGS |
+ * No sparsemem or sparsemem vmemmap: | NODE | ZONE | ... | FLAGS |
+ * classic sparse with space for node:| SECTION | NODE | ZONE | ... | FLAGS |
+ * classic sparse no space for node: | SECTION | ZONE | ... | FLAGS |
*/
-#ifdef CONFIG_SPARSEMEM
+#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
#define SECTIONS_WIDTH SECTIONS_SHIFT
#else
#define SECTIONS_WIDTH 0
@@ -409,9 +426,12 @@ static inline void set_compound_order(struct page *page, unsigned long order)
#define ZONES_WIDTH ZONES_SHIFT
-#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= FLAGS_RESERVED
+#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS
#define NODES_WIDTH NODES_SHIFT
#else
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+#error "Vmemmap: No space for nodes field in page flags"
+#endif
#define NODES_WIDTH 0
#endif
@@ -454,8 +474,8 @@ static inline void set_compound_order(struct page *page, unsigned long order)
#define ZONEID_PGSHIFT (ZONEID_PGOFF * (ZONEID_SHIFT != 0))
-#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
-#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS
+#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS
#endif
#define ZONES_MASK ((1UL << ZONES_WIDTH) - 1)
@@ -504,10 +524,12 @@ static inline struct zone *page_zone(struct page *page)
return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
}
+#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
static inline unsigned long page_to_section(struct page *page)
{
return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
}
+#endif
static inline void set_page_zone(struct page *page, enum zone_type zone)
{
@@ -602,9 +624,12 @@ static inline struct address_space *page_mapping(struct page *page)
struct address_space *mapping = page->mapping;
VM_BUG_ON(PageSlab(page));
+#ifdef CONFIG_SWAP
if (unlikely(PageSwapCache(page)))
mapping = &swapper_space;
- else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
+ else
+#endif
+ if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
mapping = NULL;
return mapping;
}
@@ -649,12 +674,6 @@ static inline int page_mapped(struct page *page)
}
/*
- * Error return values for the *_nopage functions
- */
-#define NOPAGE_SIGBUS (NULL)
-#define NOPAGE_OOM ((struct page *) (-1))
-
-/*
* Error return values for the *_nopfn functions
*/
#define NOPFN_SIGBUS ((unsigned long) -1)
@@ -720,7 +739,9 @@ struct zap_details {
unsigned long truncate_count; /* Compare vm_truncate_count */
};
-struct page *vm_normal_page(struct vm_area_struct *, unsigned long, pte_t);
+struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
+ pte_t pte);
+
unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
unsigned long size, struct zap_details *);
unsigned long unmap_vmas(struct mmu_gather **tlb,
@@ -1149,6 +1170,8 @@ int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn);
+int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn);
struct page *follow_page(struct vm_area_struct *, unsigned long address,
unsigned int foll_flags);
@@ -1229,6 +1252,7 @@ void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);
int vmemmap_populate_basepages(struct page *start_page,
unsigned long pages, int node);
int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
+void vmemmap_populate_print_last(void);
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index af190ceab971..e2bae8dde35a 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -42,7 +42,10 @@ struct page {
* to show when page is mapped
* & limit reverse map searches.
*/
- unsigned int inuse; /* SLUB: Nr of objects */
+ struct { /* SLUB */
+ u16 inuse;
+ u16 objects;
+ };
};
union {
struct {
@@ -172,6 +175,7 @@ struct mm_struct {
atomic_t mm_users; /* How many users with user space? */
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
int map_count; /* number of VMAs */
+ int core_waiters;
struct rw_semaphore mmap_sem;
spinlock_t page_table_lock; /* Protects page tables and some counters */
@@ -216,11 +220,10 @@ struct mm_struct {
unsigned long flags; /* Must use atomic bitops to access the bits */
/* coredumping support */
- int core_waiters;
struct completion *core_startup_done, core_done;
/* aio bits */
- rwlock_t ioctx_list_lock;
+ rwlock_t ioctx_list_lock; /* aio lock */
struct kioctx *ioctx_list;
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
struct mem_cgroup *mem_cgroup;
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 9f274a687c7e..aad98003176f 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -3,6 +3,7 @@
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
+#ifndef __GENERATING_BOUNDS_H
#include <linux/spinlock.h>
#include <linux/list.h>
@@ -15,6 +16,7 @@
#include <linux/seqlock.h>
#include <linux/nodemask.h>
#include <linux/pageblock-flags.h>
+#include <linux/bounds.h>
#include <asm/atomic.h>
#include <asm/page.h>
@@ -129,6 +131,8 @@ struct per_cpu_pageset {
#define zone_pcp(__z, __cpu) (&(__z)->pageset[(__cpu)])
#endif
+#endif /* !__GENERATING_BOUNDS.H */
+
enum zone_type {
#ifdef CONFIG_ZONE_DMA
/*
@@ -177,9 +181,11 @@ enum zone_type {
ZONE_HIGHMEM,
#endif
ZONE_MOVABLE,
- MAX_NR_ZONES
+ __MAX_NR_ZONES
};
+#ifndef __GENERATING_BOUNDS_H
+
/*
* When a memory allocation must conform to specific limitations (such
* as being suitable for DMA) the caller will pass in hints to the
@@ -188,28 +194,15 @@ enum zone_type {
* match the requested limits. See gfp_zone() in include/linux/gfp.h
*/
-/*
- * Count the active zones. Note that the use of defined(X) outside
- * #if and family is not necessarily defined so ensure we cannot use
- * it later. Use __ZONE_COUNT to work out how many shift bits we need.
- */
-#define __ZONE_COUNT ( \
- defined(CONFIG_ZONE_DMA) \
- + defined(CONFIG_ZONE_DMA32) \
- + 1 \
- + defined(CONFIG_HIGHMEM) \
- + 1 \
-)
-#if __ZONE_COUNT < 2
+#if MAX_NR_ZONES < 2
#define ZONES_SHIFT 0
-#elif __ZONE_COUNT <= 2
+#elif MAX_NR_ZONES <= 2
#define ZONES_SHIFT 1
-#elif __ZONE_COUNT <= 4
+#elif MAX_NR_ZONES <= 4
#define ZONES_SHIFT 2
#else
#error ZONES_SHIFT -- too many zones configured adjust calculation
#endif
-#undef __ZONE_COUNT
struct zone {
/* Fields commonly accessed by the page allocator */
@@ -393,10 +386,10 @@ static inline int zone_is_oom_locked(const struct zone *zone)
* The NUMA zonelists are doubled becausse we need zonelists that restrict the
* allocations to a single node for GFP_THISNODE.
*
- * [0 .. MAX_NR_ZONES -1] : Zonelists with fallback
- * [MAZ_NR_ZONES ... MAZ_ZONELISTS -1] : No fallback (GFP_THISNODE)
+ * [0] : Zonelist with fallback
+ * [1] : No fallback (GFP_THISNODE)
*/
-#define MAX_ZONELISTS (2 * MAX_NR_ZONES)
+#define MAX_ZONELISTS 2
/*
@@ -464,11 +457,20 @@ struct zonelist_cache {
unsigned long last_full_zap; /* when last zap'd (jiffies) */
};
#else
-#define MAX_ZONELISTS MAX_NR_ZONES
+#define MAX_ZONELISTS 1
struct zonelist_cache;
#endif
/*
+ * This struct contains information about a zone in a zonelist. It is stored
+ * here to avoid dereferences into large structures and lookups of tables
+ */
+struct zoneref {
+ struct zone *zone; /* Pointer to actual zone */
+ int zone_idx; /* zone_idx(zoneref->zone) */
+};
+
+/*
* One allocation request operates on a zonelist. A zonelist
* is a list of zones, the first one is the 'goal' of the
* allocation, the other zones are fallback zones, in decreasing
@@ -476,34 +478,23 @@ struct zonelist_cache;
*
* If zlcache_ptr is not NULL, then it is just the address of zlcache,
* as explained above. If zlcache_ptr is NULL, there is no zlcache.
+ * *
+ * To speed the reading of the zonelist, the zonerefs contain the zone index
+ * of the entry being read. Helper functions to access information given
+ * a struct zoneref are
+ *
+ * zonelist_zone() - Return the struct zone * for an entry in _zonerefs
+ * zonelist_zone_idx() - Return the index of the zone for an entry
+ * zonelist_node_idx() - Return the index of the node for an entry
*/
-
struct zonelist {
struct zonelist_cache *zlcache_ptr; // NULL or &zlcache
- struct zone *zones[MAX_ZONES_PER_ZONELIST + 1]; // NULL delimited
+ struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];
#ifdef CONFIG_NUMA
struct zonelist_cache zlcache; // optional ...
#endif
};
-#ifdef CONFIG_NUMA
-/*
- * Only custom zonelists like MPOL_BIND need to be filtered as part of
- * policies. As described in the comment for struct zonelist_cache, these
- * zonelists will not have a zlcache so zlcache_ptr will not be set. Use
- * that to determine if the zonelists needs to be filtered or not.
- */
-static inline int alloc_should_filter_zonelist(struct zonelist *zonelist)
-{
- return !zonelist->zlcache_ptr;
-}
-#else
-static inline int alloc_should_filter_zonelist(struct zonelist *zonelist)
-{
- return 0;
-}
-#endif /* CONFIG_NUMA */
-
#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
struct node_active_region {
unsigned long start_pfn;
@@ -637,9 +628,10 @@ static inline int is_normal_idx(enum zone_type idx)
static inline int is_highmem(struct zone *zone)
{
#ifdef CONFIG_HIGHMEM
- int zone_idx = zone - zone->zone_pgdat->node_zones;
- return zone_idx == ZONE_HIGHMEM ||
- (zone_idx == ZONE_MOVABLE && zone_movable_is_highmem());
+ int zone_off = (char *)zone - (char *)zone->zone_pgdat->node_zones;
+ return zone_off == ZONE_HIGHMEM * sizeof(*zone) ||
+ (zone_off == ZONE_MOVABLE * sizeof(*zone) &&
+ zone_movable_is_highmem());
#else
return 0;
#endif
@@ -730,32 +722,103 @@ extern struct zone *next_zone(struct zone *zone);
zone; \
zone = next_zone(zone))
-#ifdef CONFIG_SPARSEMEM
-#include <asm/sparsemem.h>
-#endif
+static inline struct zone *zonelist_zone(struct zoneref *zoneref)
+{
+ return zoneref->zone;
+}
-#if BITS_PER_LONG == 32
-/*
- * with 32 bit page->flags field, we reserve 9 bits for node/zone info.
- * there are 4 zones (3 bits) and this leaves 9-3=6 bits for nodes.
+static inline int zonelist_zone_idx(struct zoneref *zoneref)
+{
+ return zoneref->zone_idx;
+}
+
+static inline int zonelist_node_idx(struct zoneref *zoneref)
+{
+#ifdef CONFIG_NUMA
+ /* zone_to_nid not available in this context */
+ return zoneref->zone->node;
+#else
+ return 0;
+#endif /* CONFIG_NUMA */
+}
+
+/**
+ * next_zones_zonelist - Returns the next zone at or below highest_zoneidx within the allowed nodemask using a cursor within a zonelist as a starting point
+ * @z - The cursor used as a starting point for the search
+ * @highest_zoneidx - The zone index of the highest zone to return
+ * @nodes - An optional nodemask to filter the zonelist with
+ * @zone - The first suitable zone found is returned via this parameter
+ *
+ * This function returns the next zone at or below a given zone index that is
+ * within the allowed nodemask using a cursor as the starting point for the
+ * search. The zoneref returned is a cursor that is used as the next starting
+ * point for future calls to next_zones_zonelist().
*/
-#define FLAGS_RESERVED 9
+struct zoneref *next_zones_zonelist(struct zoneref *z,
+ enum zone_type highest_zoneidx,
+ nodemask_t *nodes,
+ struct zone **zone);
-#elif BITS_PER_LONG == 64
-/*
- * with 64 bit flags field, there's plenty of room.
+/**
+ * first_zones_zonelist - Returns the first zone at or below highest_zoneidx within the allowed nodemask in a zonelist
+ * @zonelist - The zonelist to search for a suitable zone
+ * @highest_zoneidx - The zone index of the highest zone to return
+ * @nodes - An optional nodemask to filter the zonelist with
+ * @zone - The first suitable zone found is returned via this parameter
+ *
+ * This function returns the first zone at or below a given zone index that is
+ * within the allowed nodemask. The zoneref returned is a cursor that can be
+ * used to iterate the zonelist with next_zones_zonelist. The cursor should
+ * not be used by the caller as it does not match the value of the zone
+ * returned.
*/
-#define FLAGS_RESERVED 32
+static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
+ enum zone_type highest_zoneidx,
+ nodemask_t *nodes,
+ struct zone **zone)
+{
+ return next_zones_zonelist(zonelist->_zonerefs, highest_zoneidx, nodes,
+ zone);
+}
-#else
+/**
+ * for_each_zone_zonelist_nodemask - helper macro to iterate over valid zones in a zonelist at or below a given zone index and within a nodemask
+ * @zone - The current zone in the iterator
+ * @z - The current pointer within zonelist->zones being iterated
+ * @zlist - The zonelist being iterated
+ * @highidx - The zone index of the highest zone to return
+ * @nodemask - Nodemask allowed by the allocator
+ *
+ * This iterator iterates though all zones at or below a given zone index and
+ * within a given nodemask
+ */
+#define for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \
+ for (z = first_zones_zonelist(zlist, highidx, nodemask, &zone); \
+ zone; \
+ z = next_zones_zonelist(z, highidx, nodemask, &zone)) \
-#error BITS_PER_LONG not defined
+/**
+ * for_each_zone_zonelist - helper macro to iterate over valid zones in a zonelist at or below a given zone index
+ * @zone - The current zone in the iterator
+ * @z - The current pointer within zonelist->zones being iterated
+ * @zlist - The zonelist being iterated
+ * @highidx - The zone index of the highest zone to return
+ *
+ * This iterator iterates though all zones at or below a given zone index.
+ */
+#define for_each_zone_zonelist(zone, z, zlist, highidx) \
+ for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, NULL)
+#ifdef CONFIG_SPARSEMEM
+#include <asm/sparsemem.h>
#endif
#if !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) && \
!defined(CONFIG_ARCH_POPULATES_NODE_MAP)
-#define early_pfn_to_nid(nid) (0UL)
+static inline unsigned long early_pfn_to_nid(unsigned long pfn)
+{
+ return 0;
+}
#endif
#ifdef CONFIG_FLATMEM
@@ -833,6 +896,7 @@ static inline struct mem_section *__nr_to_section(unsigned long nr)
return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
}
extern int __section_nr(struct mem_section* ms);
+extern unsigned long usemap_size(void);
/*
* We use the lower bits of the mem_map pointer to store
@@ -938,6 +1002,7 @@ unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
#define pfn_valid_within(pfn) (1)
#endif
+#endif /* !__GENERATING_BOUNDS.H */
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _LINUX_MMZONE_H */
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index f950921523f5..b03b27457413 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -58,7 +58,11 @@
#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */
/* media of boot sector */
-#define FAT_VALID_MEDIA(x) ((0xF8 <= (x) && (x) <= 0xFF) || (x) == 0xF0)
+static inline int fat_valid_media(u8 media)
+{
+ return 0xf8 <= media || media == 0xf0;
+}
+
#define FAT_FIRST_ENT(s, x) ((MSDOS_SB(s)->fat_bits == 32 ? 0x0FFFFF00 : \
MSDOS_SB(s)->fat_bits == 16 ? 0xFF00 : 0xF00) | (x))
@@ -195,6 +199,7 @@ struct fat_mount_options {
char *iocharset; /* Charset used for filename input/display */
unsigned short shortname; /* flags for shortname display/create rule */
unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+ unsigned short allow_utime;/* permission for setting the [am]time */
unsigned quiet:1, /* set = fake successful chmods and chowns */
showexec:1, /* set = only set x bit for com/exe/bat */
sys_immutable:1, /* set = system files are immutable */
@@ -232,6 +237,7 @@ struct msdos_sb_info {
struct mutex fat_lock;
unsigned int prev_free; /* previously allocated cluster number */
unsigned int free_clusters; /* -1 if undefined */
+ unsigned int free_clus_valid; /* is free_clusters valid? */
struct fat_mount_options options;
struct nls_table *nls_disk; /* Codepage used on disk */
struct nls_table *nls_io; /* Charset used for input and display */
@@ -401,7 +407,7 @@ extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern const struct file_operations fat_file_operations;
extern const struct inode_operations fat_file_inode_operations;
-extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
+extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
extern void fat_truncate(struct inode *inode);
extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h
index 6977780e548f..85fd041d44ad 100644
--- a/include/linux/mtd/inftl.h
+++ b/include/linux/mtd/inftl.h
@@ -57,6 +57,11 @@ extern char inftlmountrev[];
void INFTL_dumptables(struct INFTLrecord *s);
void INFTL_dumpVUchains(struct INFTLrecord *s);
+int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+
#endif /* __KERNEL__ */
#endif /* __MTD_INFTL_H__ */
diff --git a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h
index bcf2fb3fa4a7..001eec50cac6 100644
--- a/include/linux/mtd/nftl.h
+++ b/include/linux/mtd/nftl.h
@@ -43,6 +43,11 @@ struct NFTLrecord {
int NFTL_mount(struct NFTLrecord *s);
int NFTL_formatblock(struct NFTLrecord *s, int block);
+int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
+ size_t *retlen, uint8_t *buf);
+
#ifndef NFTL_MAJOR
#define NFTL_MAJOR 93
#endif
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index fd0a260e070b..9aa2a9149b58 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -187,4 +187,7 @@ struct onenand_manufacturers {
char *name;
};
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops);
+
#endif /* __LINUX_MTD_ONENAND_H */
diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h
index 9667863bd7e3..0e37ad07bce2 100644
--- a/include/linux/mtd/plat-ram.h
+++ b/include/linux/mtd/plat-ram.h
@@ -21,8 +21,9 @@
#define PLATRAM_RW (1)
struct platdata_mtd_ram {
- char *mapname;
- char **probes;
+ const char *mapname;
+ const char **map_probes;
+ const char **probes;
struct mtd_partition *partitions;
int nr_partitions;
int bankwidth;
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index 88766e43e121..9f2d76347f19 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -204,6 +204,7 @@ void ncp_update_inode2(struct inode *, struct ncp_entry_info *);
/* linux/fs/ncpfs/dir.c */
extern const struct inode_operations ncp_dir_inode_operations;
extern const struct file_operations ncp_dir_operations;
+extern struct dentry_operations ncp_root_dentry_operations;
int ncp_conn_logged_in(struct super_block *);
int ncp_date_dos2unix(__le16 time, __le16 date);
void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date);
@@ -223,6 +224,12 @@ int ncp_disconnect(struct ncp_server *server);
void ncp_lock_server(struct ncp_server *server);
void ncp_unlock_server(struct ncp_server *server);
+/* linux/fs/ncpfs/symlink.c */
+#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
+extern const struct address_space_operations ncp_symlink_aops;
+int ncp_symlink(struct inode*, struct dentry*, const char*);
+#endif
+
/* linux/fs/ncpfs/file.c */
extern const struct inode_operations ncp_file_inode_operations;
extern const struct file_operations ncp_file_operations;
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 21ee440dd3e7..41d30c9c9de6 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -329,7 +329,7 @@ extern struct timeval nfssvc_boot;
(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL )
#define NFSD_WRITEABLE_ATTRS_WORD1 \
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
- | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
+ | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
#endif /* CONFIG_NFSD_V4 */
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 905e18f4b412..848025cd7087 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -14,6 +14,8 @@
* bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
* For details of node_remap(), see bitmap_bitremap in lib/bitmap.c.
* For details of nodes_remap(), see bitmap_remap in lib/bitmap.c.
+ * For details of nodes_onto(), see bitmap_onto in lib/bitmap.c.
+ * For details of nodes_fold(), see bitmap_fold in lib/bitmap.c.
*
* The available nodemask operations are:
*
@@ -55,7 +57,9 @@
* int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
* int nodelist_parse(buf, map) Parse ascii string as nodelist
* int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
- * int nodes_remap(dst, src, old, new) *dst = map(old, new)(dst)
+ * void nodes_remap(dst, src, old, new) *dst = map(old, new)(src)
+ * void nodes_onto(dst, orig, relmap) *dst = orig relative to relmap
+ * void nodes_fold(dst, orig, sz) dst bits = orig bits mod sz
*
* for_each_node_mask(node, mask) for-loop node over mask
*
@@ -326,6 +330,22 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,
bitmap_remap(dstp->bits, srcp->bits, oldp->bits, newp->bits, nbits);
}
+#define nodes_onto(dst, orig, relmap) \
+ __nodes_onto(&(dst), &(orig), &(relmap), MAX_NUMNODES)
+static inline void __nodes_onto(nodemask_t *dstp, const nodemask_t *origp,
+ const nodemask_t *relmapp, int nbits)
+{
+ bitmap_onto(dstp->bits, origp->bits, relmapp->bits, nbits);
+}
+
+#define nodes_fold(dst, orig, sz) \
+ __nodes_fold(&(dst), &(orig), sz, MAX_NUMNODES)
+static inline void __nodes_fold(nodemask_t *dstp, const nodemask_t *origp,
+ int sz, int nbits)
+{
+ bitmap_fold(dstp->bits, origp->bits, sz, nbits);
+}
+
#if MAX_NUMNODES > 1
#define for_each_node_mask(node, mask) \
for ((node) = first_node(mask); \
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index f4df40038f0c..20dfed590183 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -247,6 +247,7 @@ extern struct blocking_notifier_head reboot_notifier_list;
#define VT_DEALLOCATE 0x0002 /* Console will be deallocated */
#define VT_WRITE 0x0003 /* A char got output */
#define VT_UPDATE 0x0004 /* A bigger update occurred */
+#define VT_PREWRITE 0x0005 /* A char is about to be written to the console */
#endif /* __KERNEL__ */
#endif /* _LINUX_NOTIFIER_H */
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 3852436b652a..a7979baf1e39 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -23,8 +23,8 @@ enum oom_constraint {
CONSTRAINT_MEMORY_POLICY,
};
-extern int try_set_zone_oom(struct zonelist *zonelist);
-extern void clear_zonelist_oom(struct zonelist *zonelist);
+extern int try_set_zone_oom(struct zonelist *zonelist, gfp_t gfp_flags);
+extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order);
extern int register_oom_notifier(struct notifier_block *nb);
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index b5b30f1c1e59..590cff32415d 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -6,7 +6,10 @@
#define PAGE_FLAGS_H
#include <linux/types.h>
+#ifndef __GENERATING_BOUNDS_H
#include <linux/mm_types.h>
+#include <linux/bounds.h>
+#endif /* !__GENERATING_BOUNDS_H */
/*
* Various page->flags bits:
@@ -59,77 +62,138 @@
* extends from the high bits downwards.
*
* | FIELD | ... | FLAGS |
- * N-1 ^ 0
- * (N-FLAGS_RESERVED)
+ * N-1 ^ 0
+ * (NR_PAGEFLAGS)
*
- * The fields area is reserved for fields mapping zone, node and SPARSEMEM
- * section. The boundry between these two areas is defined by
- * FLAGS_RESERVED which defines the width of the fields section
- * (see linux/mmzone.h). New flags must _not_ overlap with this area.
+ * The fields area is reserved for fields mapping zone, node (for NUMA) and
+ * SPARSEMEM section (for variants of SPARSEMEM that require section ids like
+ * SPARSEMEM_EXTREME with !SPARSEMEM_VMEMMAP).
*/
-#define PG_locked 0 /* Page is locked. Don't touch. */
-#define PG_error 1
-#define PG_referenced 2
-#define PG_uptodate 3
+enum pageflags {
+ PG_locked, /* Page is locked. Don't touch. */
+ PG_error,
+ PG_referenced,
+ PG_uptodate,
+ PG_dirty,
+ PG_lru,
+ PG_active,
+ PG_slab,
+ PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/
+ PG_arch_1,
+ PG_reserved,
+ PG_private, /* If pagecache, has fs-private data */
+ PG_writeback, /* Page is under writeback */
+#ifdef CONFIG_PAGEFLAGS_EXTENDED
+ PG_head, /* A head page */
+ PG_tail, /* A tail page */
+#else
+ PG_compound, /* A compound page */
+#endif
+ PG_swapcache, /* Swap page: swp_entry_t in private */
+ PG_mappedtodisk, /* Has blocks allocated on-disk */
+ PG_reclaim, /* To be reclaimed asap */
+ PG_buddy, /* Page is free, on buddy lists */
+#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
+ PG_uncached, /* Page has been mapped as uncached */
+#endif
+ __NR_PAGEFLAGS
+};
+
+#ifndef __GENERATING_BOUNDS_H
+
+/*
+ * Macros to create function definitions for page flags
+ */
+#define TESTPAGEFLAG(uname, lname) \
+static inline int Page##uname(struct page *page) \
+ { return test_bit(PG_##lname, &page->flags); }
-#define PG_dirty 4
-#define PG_lru 5
-#define PG_active 6
-#define PG_slab 7 /* slab debug (Suparna wants this) */
+#define SETPAGEFLAG(uname, lname) \
+static inline void SetPage##uname(struct page *page) \
+ { set_bit(PG_##lname, &page->flags); }
-#define PG_owner_priv_1 8 /* Owner use. If pagecache, fs may use*/
-#define PG_arch_1 9
-#define PG_reserved 10
-#define PG_private 11 /* If pagecache, has fs-private data */
+#define CLEARPAGEFLAG(uname, lname) \
+static inline void ClearPage##uname(struct page *page) \
+ { clear_bit(PG_##lname, &page->flags); }
-#define PG_writeback 12 /* Page is under writeback */
-#define PG_compound 14 /* Part of a compound page */
-#define PG_swapcache 15 /* Swap page: swp_entry_t in private */
+#define __SETPAGEFLAG(uname, lname) \
+static inline void __SetPage##uname(struct page *page) \
+ { __set_bit(PG_##lname, &page->flags); }
-#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */
-#define PG_reclaim 17 /* To be reclaimed asap */
-#define PG_buddy 19 /* Page is free, on buddy lists */
+#define __CLEARPAGEFLAG(uname, lname) \
+static inline void __ClearPage##uname(struct page *page) \
+ { __clear_bit(PG_##lname, &page->flags); }
+
+#define TESTSETFLAG(uname, lname) \
+static inline int TestSetPage##uname(struct page *page) \
+ { return test_and_set_bit(PG_##lname, &page->flags); }
+
+#define TESTCLEARFLAG(uname, lname) \
+static inline int TestClearPage##uname(struct page *page) \
+ { return test_and_clear_bit(PG_##lname, &page->flags); }
-/* PG_readahead is only used for file reads; PG_reclaim is only for writes */
-#define PG_readahead PG_reclaim /* Reminder to do async read-ahead */
-/* PG_owner_priv_1 users should have descriptive aliases */
-#define PG_checked PG_owner_priv_1 /* Used by some filesystems */
-#define PG_pinned PG_owner_priv_1 /* Xen pinned pagetable */
+#define PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \
+ SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname)
+
+#define __PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \
+ __SETPAGEFLAG(uname, lname) __CLEARPAGEFLAG(uname, lname)
+
+#define PAGEFLAG_FALSE(uname) \
+static inline int Page##uname(struct page *page) \
+ { return 0; }
+
+#define TESTSCFLAG(uname, lname) \
+ TESTSETFLAG(uname, lname) TESTCLEARFLAG(uname, lname)
+
+struct page; /* forward declaration */
+
+PAGEFLAG(Locked, locked) TESTSCFLAG(Locked, locked)
+PAGEFLAG(Error, error)
+PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced)
+PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty)
+PAGEFLAG(LRU, lru) __CLEARPAGEFLAG(LRU, lru)
+PAGEFLAG(Active, active) __CLEARPAGEFLAG(Active, active)
+__PAGEFLAG(Slab, slab)
+PAGEFLAG(Checked, owner_priv_1) /* Used by some filesystems */
+PAGEFLAG(Pinned, owner_priv_1) TESTSCFLAG(Pinned, owner_priv_1) /* Xen */
+PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
+PAGEFLAG(Private, private) __CLEARPAGEFLAG(Private, private)
+ __SETPAGEFLAG(Private, private)
-#if (BITS_PER_LONG > 32)
/*
- * 64-bit-only flags build down from bit 31
- *
- * 32 bit -------------------------------| FIELDS | FLAGS |
- * 64 bit | FIELDS | ?????? FLAGS |
- * 63 32 0
+ * Only test-and-set exist for PG_writeback. The unconditional operators are
+ * risky: they bypass page accounting.
*/
-#define PG_uncached 31 /* Page has been mapped as uncached */
-#endif
+TESTPAGEFLAG(Writeback, writeback) TESTSCFLAG(Writeback, writeback)
+__PAGEFLAG(Buddy, buddy)
+PAGEFLAG(MappedToDisk, mappedtodisk)
+/* PG_readahead is only used for file reads; PG_reclaim is only for writes */
+PAGEFLAG(Reclaim, reclaim) TESTCLEARFLAG(Reclaim, reclaim)
+PAGEFLAG(Readahead, reclaim) /* Reminder to do async read-ahead */
+
+#ifdef CONFIG_HIGHMEM
/*
- * Manipulation of page state flags
+ * Must use a macro here due to header dependency issues. page_zone() is not
+ * available at this point.
*/
-#define PageLocked(page) \
- test_bit(PG_locked, &(page)->flags)
-#define SetPageLocked(page) \
- set_bit(PG_locked, &(page)->flags)
-#define TestSetPageLocked(page) \
- test_and_set_bit(PG_locked, &(page)->flags)
-#define ClearPageLocked(page) \
- clear_bit(PG_locked, &(page)->flags)
-#define TestClearPageLocked(page) \
- test_and_clear_bit(PG_locked, &(page)->flags)
-
-#define PageError(page) test_bit(PG_error, &(page)->flags)
-#define SetPageError(page) set_bit(PG_error, &(page)->flags)
-#define ClearPageError(page) clear_bit(PG_error, &(page)->flags)
-
-#define PageReferenced(page) test_bit(PG_referenced, &(page)->flags)
-#define SetPageReferenced(page) set_bit(PG_referenced, &(page)->flags)
-#define ClearPageReferenced(page) clear_bit(PG_referenced, &(page)->flags)
-#define TestClearPageReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags)
+#define PageHighMem(__p) is_highmem(page_zone(__p))
+#else
+PAGEFLAG_FALSE(HighMem)
+#endif
+
+#ifdef CONFIG_SWAP
+PAGEFLAG(SwapCache, swapcache)
+#else
+PAGEFLAG_FALSE(SwapCache)
+#endif
+
+#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
+PAGEFLAG(Uncached, uncached)
+#else
+PAGEFLAG_FALSE(Uncached)
+#endif
static inline int PageUptodate(struct page *page)
{
@@ -177,97 +241,59 @@ static inline void SetPageUptodate(struct page *page)
#endif
}
-#define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags)
-
-#define PageDirty(page) test_bit(PG_dirty, &(page)->flags)
-#define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags)
-#define TestSetPageDirty(page) test_and_set_bit(PG_dirty, &(page)->flags)
-#define ClearPageDirty(page) clear_bit(PG_dirty, &(page)->flags)
-#define __ClearPageDirty(page) __clear_bit(PG_dirty, &(page)->flags)
-#define TestClearPageDirty(page) test_and_clear_bit(PG_dirty, &(page)->flags)
-
-#define PageLRU(page) test_bit(PG_lru, &(page)->flags)
-#define SetPageLRU(page) set_bit(PG_lru, &(page)->flags)
-#define ClearPageLRU(page) clear_bit(PG_lru, &(page)->flags)
-#define __ClearPageLRU(page) __clear_bit(PG_lru, &(page)->flags)
-
-#define PageActive(page) test_bit(PG_active, &(page)->flags)
-#define SetPageActive(page) set_bit(PG_active, &(page)->flags)
-#define ClearPageActive(page) clear_bit(PG_active, &(page)->flags)
-#define __ClearPageActive(page) __clear_bit(PG_active, &(page)->flags)
-
-#define PageSlab(page) test_bit(PG_slab, &(page)->flags)
-#define __SetPageSlab(page) __set_bit(PG_slab, &(page)->flags)
-#define __ClearPageSlab(page) __clear_bit(PG_slab, &(page)->flags)
-
-#ifdef CONFIG_HIGHMEM
-#define PageHighMem(page) is_highmem(page_zone(page))
-#else
-#define PageHighMem(page) 0 /* needed to optimize away at compile time */
-#endif
+CLEARPAGEFLAG(Uptodate, uptodate)
-#define PageChecked(page) test_bit(PG_checked, &(page)->flags)
-#define SetPageChecked(page) set_bit(PG_checked, &(page)->flags)
-#define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags)
-
-#define PagePinned(page) test_bit(PG_pinned, &(page)->flags)
-#define SetPagePinned(page) set_bit(PG_pinned, &(page)->flags)
-#define ClearPagePinned(page) clear_bit(PG_pinned, &(page)->flags)
+extern void cancel_dirty_page(struct page *page, unsigned int account_size);
-#define PageReserved(page) test_bit(PG_reserved, &(page)->flags)
-#define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags)
-#define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags)
-#define __ClearPageReserved(page) __clear_bit(PG_reserved, &(page)->flags)
+int test_clear_page_writeback(struct page *page);
+int test_set_page_writeback(struct page *page);
-#define SetPagePrivate(page) set_bit(PG_private, &(page)->flags)
-#define ClearPagePrivate(page) clear_bit(PG_private, &(page)->flags)
-#define PagePrivate(page) test_bit(PG_private, &(page)->flags)
-#define __SetPagePrivate(page) __set_bit(PG_private, &(page)->flags)
-#define __ClearPagePrivate(page) __clear_bit(PG_private, &(page)->flags)
+static inline void set_page_writeback(struct page *page)
+{
+ test_set_page_writeback(page);
+}
+#ifdef CONFIG_PAGEFLAGS_EXTENDED
/*
- * Only test-and-set exist for PG_writeback. The unconditional operators are
- * risky: they bypass page accounting.
+ * System with lots of page flags available. This allows separate
+ * flags for PageHead() and PageTail() checks of compound pages so that bit
+ * tests can be used in performance sensitive paths. PageCompound is
+ * generally not used in hot code paths.
*/
-#define PageWriteback(page) test_bit(PG_writeback, &(page)->flags)
-#define TestSetPageWriteback(page) test_and_set_bit(PG_writeback, \
- &(page)->flags)
-#define TestClearPageWriteback(page) test_and_clear_bit(PG_writeback, \
- &(page)->flags)
+__PAGEFLAG(Head, head)
+__PAGEFLAG(Tail, tail)
-#define PageBuddy(page) test_bit(PG_buddy, &(page)->flags)
-#define __SetPageBuddy(page) __set_bit(PG_buddy, &(page)->flags)
-#define __ClearPageBuddy(page) __clear_bit(PG_buddy, &(page)->flags)
-
-#define PageMappedToDisk(page) test_bit(PG_mappedtodisk, &(page)->flags)
-#define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags)
-#define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags)
-
-#define PageReadahead(page) test_bit(PG_readahead, &(page)->flags)
-#define SetPageReadahead(page) set_bit(PG_readahead, &(page)->flags)
-#define ClearPageReadahead(page) clear_bit(PG_readahead, &(page)->flags)
-
-#define PageReclaim(page) test_bit(PG_reclaim, &(page)->flags)
-#define SetPageReclaim(page) set_bit(PG_reclaim, &(page)->flags)
-#define ClearPageReclaim(page) clear_bit(PG_reclaim, &(page)->flags)
-#define TestClearPageReclaim(page) test_and_clear_bit(PG_reclaim, &(page)->flags)
+static inline int PageCompound(struct page *page)
+{
+ return page->flags & ((1L << PG_head) | (1L << PG_tail));
-#define PageCompound(page) test_bit(PG_compound, &(page)->flags)
-#define __SetPageCompound(page) __set_bit(PG_compound, &(page)->flags)
-#define __ClearPageCompound(page) __clear_bit(PG_compound, &(page)->flags)
+}
+#else
+/*
+ * Reduce page flag use as much as possible by overlapping
+ * compound page flags with the flags used for page cache pages. Possible
+ * because PageCompound is always set for compound pages and not for
+ * pages on the LRU and/or pagecache.
+ */
+TESTPAGEFLAG(Compound, compound)
+__PAGEFLAG(Head, compound)
/*
* PG_reclaim is used in combination with PG_compound to mark the
- * head and tail of a compound page
+ * head and tail of a compound page. This saves one page flag
+ * but makes it impossible to use compound pages for the page cache.
+ * The PG_reclaim bit would have to be used for reclaim or readahead
+ * if compound pages enter the page cache.
*
* PG_compound & PG_reclaim => Tail page
* PG_compound & ~PG_reclaim => Head page
*/
-
#define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim))
-#define PageTail(page) (((page)->flags & PG_head_tail_mask) \
- == PG_head_tail_mask)
+static inline int PageTail(struct page *page)
+{
+ return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask);
+}
static inline void __SetPageTail(struct page *page)
{
@@ -279,33 +305,6 @@ static inline void __ClearPageTail(struct page *page)
page->flags &= ~PG_head_tail_mask;
}
-#define PageHead(page) (((page)->flags & PG_head_tail_mask) \
- == (1L << PG_compound))
-#define __SetPageHead(page) __SetPageCompound(page)
-#define __ClearPageHead(page) __ClearPageCompound(page)
-
-#ifdef CONFIG_SWAP
-#define PageSwapCache(page) test_bit(PG_swapcache, &(page)->flags)
-#define SetPageSwapCache(page) set_bit(PG_swapcache, &(page)->flags)
-#define ClearPageSwapCache(page) clear_bit(PG_swapcache, &(page)->flags)
-#else
-#define PageSwapCache(page) 0
-#endif
-
-#define PageUncached(page) test_bit(PG_uncached, &(page)->flags)
-#define SetPageUncached(page) set_bit(PG_uncached, &(page)->flags)
-#define ClearPageUncached(page) clear_bit(PG_uncached, &(page)->flags)
-
-struct page; /* forward declaration */
-
-extern void cancel_dirty_page(struct page *page, unsigned int account_size);
-
-int test_clear_page_writeback(struct page *page);
-int test_set_page_writeback(struct page *page);
-
-static inline void set_page_writeback(struct page *page)
-{
- test_set_page_writeback(page);
-}
-
+#endif /* !PAGEFLAGS_EXTENDED */
+#endif /* !__GENERATING_BOUNDS_H */
#endif /* PAGE_FLAGS_H */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 779cbcd65f62..02df20f085fe 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -379,6 +379,18 @@ struct phy_driver {
};
#define to_phy_driver(d) container_of(d, struct phy_driver, driver)
+#define PHY_ANY_ID "MATCH ANY PHY"
+#define PHY_ANY_UID 0xffffffff
+
+/* A Structure for boards to register fixups with the PHY Lib */
+struct phy_fixup {
+ struct list_head list;
+ char bus_id[BUS_ID_SIZE];
+ u32 phy_uid;
+ u32 phy_uid_mask;
+ int (*run)(struct phy_device *phydev);
+};
+
int phy_read(struct phy_device *phydev, u16 regnum);
int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
@@ -386,8 +398,8 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_clear_interrupt(struct phy_device *phydev);
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
struct phy_device * phy_attach(struct net_device *dev,
- const char *phy_id, u32 flags, phy_interface_t interface);
-struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
+ const char *bus_id, u32 flags, phy_interface_t interface);
+struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
void (*handler)(struct net_device *), u32 flags,
phy_interface_t interface);
void phy_disconnect(struct phy_device *phydev);
@@ -427,5 +439,13 @@ void phy_print_status(struct phy_device *phydev);
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id);
void phy_device_free(struct phy_device *phydev);
+int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
+ int (*run)(struct phy_device *));
+int phy_register_fixup_for_id(const char *bus_id,
+ int (*run)(struct phy_device *));
+int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
+ int (*run)(struct phy_device *));
+int phy_scan_fixups(struct phy_device *phydev);
+
extern struct bus_type mdio_bus_type;
#endif /* __PHY_H */
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index 5c80b1939636..5ad79198d6f9 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -16,7 +16,8 @@
# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */
# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */
-/* Get/set whether or not to drop capabilities on setuid() away from uid 0 */
+/* Get/set whether or not to drop capabilities on setuid() away from
+ * uid 0 (as per security/commoncap.c) */
#define PR_GET_KEEPCAPS 7
#define PR_SET_KEEPCAPS 8
@@ -63,7 +64,7 @@
#define PR_GET_SECCOMP 21
#define PR_SET_SECCOMP 22
-/* Get/set the capability bounding set */
+/* Get/set the capability bounding set (as per security/commoncap.c) */
#define PR_CAPBSET_READ 23
#define PR_CAPBSET_DROP 24
@@ -73,4 +74,8 @@
# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
+/* Get/set securebits (as per security/commoncap.c) */
+#define PR_GET_SECUREBITS 27
+#define PR_SET_SECUREBITS 28
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/quota.h b/include/linux/quota.h
index eb560d031acd..52e49dce6584 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -202,10 +202,14 @@ struct quota_format_type;
struct mem_dqinfo {
struct quota_format_type *dqi_format;
+ int dqi_fmt_id; /* Id of the dqi_format - used when turning
+ * quotas on after remount RW */
struct list_head dqi_dirty_list; /* List of dirty dquots */
unsigned long dqi_flags;
unsigned int dqi_bgrace;
unsigned int dqi_igrace;
+ qsize_t dqi_maxblimit;
+ qsize_t dqi_maxilimit;
union {
struct v1_mem_dqinfo v1_i;
struct v2_mem_dqinfo v2_i;
@@ -296,8 +300,8 @@ struct dquot_operations {
/* Operations handling requests from userspace */
struct quotactl_ops {
- int (*quota_on)(struct super_block *, int, int, char *);
- int (*quota_off)(struct super_block *, int);
+ int (*quota_on)(struct super_block *, int, int, char *, int);
+ int (*quota_off)(struct super_block *, int, int);
int (*quota_sync)(struct super_block *, int);
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
@@ -318,6 +322,10 @@ struct quota_format_type {
#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
+#define DQUOT_USR_SUSPENDED 0x04 /* User diskquotas are off, but
+ * we have necessary info in
+ * memory to turn them on */
+#define DQUOT_GRP_SUSPENDED 0x08 /* The same for group quotas */
struct quota_info {
unsigned int flags; /* Flags for diskquotas on this device */
@@ -329,17 +337,16 @@ struct quota_info {
struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */
};
-/* Inline would be better but we need to dereference super_block which is not defined yet */
-int mark_dquot_dirty(struct dquot *dquot);
-
-#define dquot_dirty(dquot) test_bit(DQ_MOD_B, &(dquot)->dq_flags)
-
#define sb_has_quota_enabled(sb, type) ((type)==USRQUOTA ? \
(sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) : (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED))
#define sb_any_quota_enabled(sb) (sb_has_quota_enabled(sb, USRQUOTA) | \
sb_has_quota_enabled(sb, GRPQUOTA))
+#define sb_has_quota_suspended(sb, type) \
+ ((type) == USRQUOTA ? (sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED) : \
+ (sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED))
+
int register_quota_format(struct quota_format_type *fmt);
void unregister_quota_format(struct quota_format_type *fmt);
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 5110201a4159..f86702053853 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -37,11 +37,11 @@ extern int dquot_release(struct dquot *dquot);
extern int dquot_commit_info(struct super_block *sb, int type);
extern int dquot_mark_dquot_dirty(struct dquot *dquot);
-extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path);
+extern int vfs_quota_on(struct super_block *sb, int type, int format_id,
+ char *path, int remount);
extern int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
int format_id, int type);
-extern int vfs_quota_off(struct super_block *sb, int type);
-#define vfs_quota_off_mount(sb, type) vfs_quota_off(sb, type)
+extern int vfs_quota_off(struct super_block *sb, int type, int remount);
extern int vfs_quota_sync(struct super_block *sb, int type);
extern int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
extern int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
@@ -59,7 +59,7 @@ extern struct quotactl_ops vfs_quotactl_ops;
/* It is better to call this function outside of any transaction as it might
* need a lot of space in journal for dquot structure allocation. */
-static __inline__ void DQUOT_INIT(struct inode *inode)
+static inline void DQUOT_INIT(struct inode *inode)
{
BUG_ON(!inode->i_sb);
if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode))
@@ -67,7 +67,7 @@ static __inline__ void DQUOT_INIT(struct inode *inode)
}
/* The same as with DQUOT_INIT */
-static __inline__ void DQUOT_DROP(struct inode *inode)
+static inline void DQUOT_DROP(struct inode *inode)
{
/* Here we can get arbitrary inode from clear_inode() so we have
* to be careful. OTOH we don't need locking as quota operations
@@ -90,7 +90,7 @@ static __inline__ void DQUOT_DROP(struct inode *inode)
/* The following allocation/freeing/transfer functions *must* be called inside
* a transaction (deadlocks possible otherwise) */
-static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
+static inline int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
{
if (sb_any_quota_enabled(inode->i_sb)) {
/* Used space is updated in alloc_space() */
@@ -102,7 +102,7 @@ static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t
return 0;
}
-static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
+static inline int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
{
int ret;
if (!(ret = DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr)))
@@ -110,7 +110,7 @@ static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
return ret;
}
-static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
+static inline int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
{
if (sb_any_quota_enabled(inode->i_sb)) {
/* Used space is updated in alloc_space() */
@@ -122,7 +122,7 @@ static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
return 0;
}
-static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
+static inline int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
{
int ret;
if (!(ret = DQUOT_ALLOC_SPACE_NODIRTY(inode, nr)))
@@ -130,7 +130,7 @@ static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
return ret;
}
-static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode)
+static inline int DQUOT_ALLOC_INODE(struct inode *inode)
{
if (sb_any_quota_enabled(inode->i_sb)) {
DQUOT_INIT(inode);
@@ -140,7 +140,7 @@ static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode)
return 0;
}
-static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
+static inline void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
{
if (sb_any_quota_enabled(inode->i_sb))
inode->i_sb->dq_op->free_space(inode, nr);
@@ -148,19 +148,19 @@ static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
inode_sub_bytes(inode, nr);
}
-static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
+static inline void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
{
DQUOT_FREE_SPACE_NODIRTY(inode, nr);
mark_inode_dirty(inode);
}
-static __inline__ void DQUOT_FREE_INODE(struct inode *inode)
+static inline void DQUOT_FREE_INODE(struct inode *inode)
{
if (sb_any_quota_enabled(inode->i_sb))
inode->i_sb->dq_op->free_inode(inode, 1);
}
-static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr)
+static inline int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr)
{
if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) {
DQUOT_INIT(inode);
@@ -171,14 +171,32 @@ static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr)
}
/* The following two functions cannot be called inside a transaction */
-#define DQUOT_SYNC(sb) sync_dquots(sb, -1)
+static inline void DQUOT_SYNC(struct super_block *sb)
+{
+ sync_dquots(sb, -1);
+}
-static __inline__ int DQUOT_OFF(struct super_block *sb)
+static inline int DQUOT_OFF(struct super_block *sb, int remount)
{
int ret = -ENOSYS;
- if (sb_any_quota_enabled(sb) && sb->s_qcop && sb->s_qcop->quota_off)
- ret = sb->s_qcop->quota_off(sb, -1);
+ if (sb->s_qcop && sb->s_qcop->quota_off)
+ ret = sb->s_qcop->quota_off(sb, -1, remount);
+ return ret;
+}
+
+static inline int DQUOT_ON_REMOUNT(struct super_block *sb)
+{
+ int cnt;
+ int ret = 0, err;
+
+ if (!sb->s_qcop || !sb->s_qcop->quota_on)
+ return -ENOSYS;
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+ err = sb->s_qcop->quota_on(sb, cnt, 0, NULL, 1);
+ if (err < 0 && !ret)
+ ret = err;
+ }
return ret;
}
@@ -189,13 +207,43 @@ static __inline__ int DQUOT_OFF(struct super_block *sb)
*/
#define sb_dquot_ops (NULL)
#define sb_quotactl_ops (NULL)
-#define DQUOT_INIT(inode) do { } while(0)
-#define DQUOT_DROP(inode) do { } while(0)
-#define DQUOT_ALLOC_INODE(inode) (0)
-#define DQUOT_FREE_INODE(inode) do { } while(0)
-#define DQUOT_SYNC(sb) do { } while(0)
-#define DQUOT_OFF(sb) do { } while(0)
-#define DQUOT_TRANSFER(inode, iattr) (0)
+
+static inline void DQUOT_INIT(struct inode *inode)
+{
+}
+
+static inline void DQUOT_DROP(struct inode *inode)
+{
+}
+
+static inline int DQUOT_ALLOC_INODE(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void DQUOT_FREE_INODE(struct inode *inode)
+{
+}
+
+static inline void DQUOT_SYNC(struct super_block *sb)
+{
+}
+
+static inline int DQUOT_OFF(struct super_block *sb, int remount)
+{
+ return 0;
+}
+
+static inline int DQUOT_ON_REMOUNT(struct super_block *sb)
+{
+ return 0;
+}
+
+static inline int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr)
+{
+ return 0;
+}
+
static inline int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
{
inode_add_bytes(inode, nr);
@@ -235,11 +283,38 @@ static inline void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
#endif /* CONFIG_QUOTA */
-#define DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_PREALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
-#define DQUOT_PREALLOC_BLOCK(inode, nr) DQUOT_PREALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
-#define DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_ALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
-#define DQUOT_ALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
-#define DQUOT_FREE_BLOCK_NODIRTY(inode, nr) DQUOT_FREE_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
-#define DQUOT_FREE_BLOCK(inode, nr) DQUOT_FREE_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+static inline int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, qsize_t nr)
+{
+ return DQUOT_PREALLOC_SPACE_NODIRTY(inode,
+ nr << inode->i_sb->s_blocksize_bits);
+}
+
+static inline int DQUOT_PREALLOC_BLOCK(struct inode *inode, qsize_t nr)
+{
+ return DQUOT_PREALLOC_SPACE(inode,
+ nr << inode->i_sb->s_blocksize_bits);
+}
+
+static inline int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, qsize_t nr)
+{
+ return DQUOT_ALLOC_SPACE_NODIRTY(inode,
+ nr << inode->i_sb->s_blocksize_bits);
+}
+
+static inline int DQUOT_ALLOC_BLOCK(struct inode *inode, qsize_t nr)
+{
+ return DQUOT_ALLOC_SPACE(inode,
+ nr << inode->i_sb->s_blocksize_bits);
+}
+
+static inline void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, qsize_t nr)
+{
+ DQUOT_FREE_SPACE_NODIRTY(inode, nr << inode->i_sb->s_blocksize_bits);
+}
+
+static inline void DQUOT_FREE_BLOCK(struct inode *inode, qsize_t nr)
+{
+ DQUOT_FREE_SPACE(inode, nr << inode->i_sb->s_blocksize_bits);
+}
#endif /* _LINUX_QUOTAOPS_ */
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index 93678f57ccbe..f0827d31ae6f 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -252,6 +252,8 @@ struct r6_state {
#define STRIPE_EXPANDING 9
#define STRIPE_EXPAND_SOURCE 10
#define STRIPE_EXPAND_READY 11
+#define STRIPE_IO_STARTED 12 /* do not count towards 'bypass_count' */
+#define STRIPE_FULL_WRITE 13 /* all blocks are set to be overwritten */
/*
* Operations flags (in issue order)
*/
@@ -316,12 +318,17 @@ struct raid5_private_data {
int previous_raid_disks;
struct list_head handle_list; /* stripes needing handling */
+ struct list_head hold_list; /* preread ready stripes */
struct list_head delayed_list; /* stripes that have plugged requests */
struct list_head bitmap_list; /* stripes delaying awaiting bitmap update */
struct bio *retry_read_aligned; /* currently retrying aligned bios */
struct bio *retry_read_aligned_list; /* aligned bios retry list */
atomic_t preread_active_stripes; /* stripes with scheduled io */
atomic_t active_aligned_reads;
+ atomic_t pending_full_writes; /* full write backlog */
+ int bypass_count; /* bypassed prereads */
+ int bypass_threshold; /* preread nice */
+ struct list_head *last_hold; /* detect hold_list promotions */
atomic_t reshape_stripes; /* stripes with pending writes for reshape */
/* unfortunately we need two cache names as we temporarily have
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 8e7eff2cd0ab..4aacaeecb56f 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -2176,6 +2176,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
long reiserfs_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
+int reiserfs_unpack(struct inode *inode, struct file *filp);
/* ioctl's command */
#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 311380e5fe89..024d72b47a0c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -68,7 +68,6 @@ struct sched_param {
#include <linux/smp.h>
#include <linux/sem.h>
#include <linux/signal.h>
-#include <linux/securebits.h>
#include <linux/fs_struct.h>
#include <linux/compiler.h>
#include <linux/completion.h>
@@ -1133,7 +1132,7 @@ struct task_struct {
gid_t gid,egid,sgid,fsgid;
struct group_info *group_info;
kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset;
- unsigned keep_capabilities:1;
+ unsigned securebits;
struct user_struct *user;
#ifdef CONFIG_KEYS
struct key *request_key_auth; /* assumed request_key authority */
@@ -1798,6 +1797,8 @@ extern void mmput(struct mm_struct *);
extern struct mm_struct *get_task_mm(struct task_struct *task);
/* Remove the current tasks stale references to the old mm_struct */
extern void mm_release(struct task_struct *, struct mm_struct *);
+/* Allocate a new mm structure and copy contents from tsk->mm */
+extern struct mm_struct *dup_mm(struct task_struct *tsk);
extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
extern void flush_thread(void);
@@ -1926,6 +1927,8 @@ static inline unsigned long *end_of_stack(struct task_struct *p)
#endif
+extern void thread_info_cache_init(void);
+
/* set thread flags in other task's structures
* - see asm/thread_info.h for TIF_xxxx flags available
*/
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 5b0617840fa4..c1f19dbceb05 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -3,28 +3,39 @@
#define SECUREBITS_DEFAULT 0x00000000
-extern unsigned securebits;
-
/* When set UID 0 has no special privileges. When unset, we support
inheritance of root-permissions and suid-root executable under
compatibility mode. We raise the effective and inheritable bitmasks
*of the executable file* if the effective uid of the new process is
0. If the real uid is 0, we raise the inheritable bitmask of the
executable file. */
-#define SECURE_NOROOT 0
+#define SECURE_NOROOT 0
+#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */
/* When set, setuid to/from uid 0 does not trigger capability-"fixes"
to be compatible with old programs relying on set*uid to loose
privileges. When unset, setuid doesn't change privileges. */
-#define SECURE_NO_SETUID_FIXUP 2
+#define SECURE_NO_SETUID_FIXUP 2
+#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */
+
+/* When set, a process can retain its capabilities even after
+ transitioning to a non-root user (the set-uid fixup suppressed by
+ bit 2). Bit-4 is cleared when a process calls exec(); setting both
+ bit 4 and 5 will create a barrier through exec that no exec()'d
+ child can use this feature again. */
+#define SECURE_KEEP_CAPS 4
+#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */
/* Each securesetting is implemented using two bits. One bit specify
whether the setting is on or off. The other bit specify whether the
setting is fixed or not. A setting which is fixed cannot be changed
from user-level. */
+#define issecure_mask(X) (1 << (X))
+#define issecure(X) (issecure_mask(X) & current->securebits)
-#define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ? \
- (1 << (X)) & SECUREBITS_DEFAULT : \
- (1 << (X)) & securebits )
+#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
+ issecure_mask(SECURE_NO_SETUID_FIXUP) | \
+ issecure_mask(SECURE_KEEP_CAPS))
+#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)
#endif /* !_LINUX_SECUREBITS_H */
diff --git a/include/linux/security.h b/include/linux/security.h
index 53a34539382a..d0a28fd1747a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -34,8 +34,6 @@
#include <linux/xfrm.h>
#include <net/flow.h>
-extern unsigned securebits;
-
/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10
@@ -46,25 +44,27 @@ struct audit_krule;
* These functions are in security/capability.c and are used
* as the default capabilities functions
*/
-extern int cap_capable (struct task_struct *tsk, int cap);
-extern int cap_settime (struct timespec *ts, struct timezone *tz);
-extern int cap_ptrace (struct task_struct *parent, struct task_struct *child);
-extern int cap_capget (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_bprm_set_security (struct linux_binprm *bprm);
-extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
+extern int cap_capable(struct task_struct *tsk, int cap);
+extern int cap_settime(struct timespec *ts, struct timezone *tz);
+extern int cap_ptrace(struct task_struct *parent, struct task_struct *child);
+extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+extern int cap_bprm_set_security(struct linux_binprm *bprm);
+extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags);
extern int cap_inode_removexattr(struct dentry *dentry, char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
-extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
-extern void cap_task_reparent_to_init (struct task_struct *p);
-extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp);
-extern int cap_task_setioprio (struct task_struct *p, int ioprio);
-extern int cap_task_setnice (struct task_struct *p, int nice);
-extern int cap_syslog (int type);
+extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
+extern void cap_task_reparent_to_init(struct task_struct *p);
+extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5, long *rc_p);
+extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
+extern int cap_task_setioprio(struct task_struct *p, int ioprio);
+extern int cap_task_setnice(struct task_struct *p, int nice);
+extern int cap_syslog(int type);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
struct msghdr;
@@ -128,7 +128,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
{
int i;
if (opts->mnt_opts)
- for(i = 0; i < opts->num_mnt_opts; i++)
+ for (i = 0; i < opts->num_mnt_opts; i++)
kfree(opts->mnt_opts[i]);
kfree(opts->mnt_opts);
opts->mnt_opts = NULL;
@@ -190,21 +190,21 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted.
* @bprm_check_security:
- * This hook mediates the point when a search for a binary handler will
- * begin. It allows a check the @bprm->security value which is set in
- * the preceding set_security call. The primary difference from
- * set_security is that the argv list and envp list are reliably
- * available in @bprm. This hook may be called multiple times
- * during a single execve; and in each pass set_security is called
- * first.
- * @bprm contains the linux_binprm structure.
+ * This hook mediates the point when a search for a binary handler will
+ * begin. It allows a check the @bprm->security value which is set in
+ * the preceding set_security call. The primary difference from
+ * set_security is that the argv list and envp list are reliably
+ * available in @bprm. This hook may be called multiple times
+ * during a single execve; and in each pass set_security is called
+ * first.
+ * @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted.
* @bprm_secureexec:
- * Return a boolean value (0 or 1) indicating whether a "secure exec"
- * is required. The flag is passed in the auxiliary table
- * on the initial stack to the ELF interpreter to indicate whether libc
- * should enable secure mode.
- * @bprm contains the linux_binprm structure.
+ * Return a boolean value (0 or 1) indicating whether a "secure exec"
+ * is required. The flag is passed in the auxiliary table
+ * on the initial stack to the ELF interpreter to indicate whether libc
+ * should enable secure mode.
+ * @bprm contains the linux_binprm structure.
*
* Security hooks for filesystem operations.
*
@@ -221,7 +221,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Check permission before obtaining filesystem statistics for the @mnt
* mountpoint.
* @dentry is a handle on the superblock for the filesystem.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted.
* @sb_mount:
* Check permission before an object specified by @dev_name is mounted on
* the mount point named by @nd. For an ordinary mount, @dev_name
@@ -282,12 +282,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @sb_pivotroot:
* Check permission before pivoting the root filesystem.
* @old_path contains the path for the new location of the current root (put_old).
- * @new_path contains the path for the new root (new_root).
+ * @new_path contains the path for the new root (new_root).
* Return 0 if permission is granted.
* @sb_post_pivotroot:
* Update module state after a successful pivot.
* @old_path contains the path for the old root.
- * @new_path contains the path for the new root.
+ * @new_path contains the path for the new root.
* @sb_get_mnt_opts:
* Get the security relevant mount options used for a superblock
* @sb the superblock to get security mount options from
@@ -316,9 +316,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @inode_free_security:
* @inode contains the inode structure.
* Deallocate the inode security structure and set @inode->i_security to
- * NULL.
+ * NULL.
* @inode_init_security:
- * Obtain the security attribute name suffix and value to set on a newly
+ * Obtain the security attribute name suffix and value to set on a newly
* created inode and set up the incore security field for the new inode.
* This hook is called by the fs code as part of the inode creation
* transaction and provides for atomic labeling of the inode, unlike
@@ -349,7 +349,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @new_dentry contains the dentry structure for the new link.
* Return 0 if permission is granted.
* @inode_unlink:
- * Check the permission to remove a hard link to a file.
+ * Check the permission to remove a hard link to a file.
* @dir contains the inode structure of parent directory of the file.
* @dentry contains the dentry structure for file to be unlinked.
* Return 0 if permission is granted.
@@ -361,7 +361,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return 0 if permission is granted.
* @inode_mkdir:
* Check permissions to create a new directory in the existing directory
- * associated with inode strcture @dir.
+ * associated with inode strcture @dir.
* @dir containst the inode structure of parent of the directory to be created.
* @dentry contains the dentry structure of new directory.
* @mode contains the mode of new directory.
@@ -406,7 +406,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* called when the actual read/write operations are performed.
* @inode contains the inode structure to check.
* @mask contains the permission mask.
- * @nd contains the nameidata (may be NULL).
+ * @nd contains the nameidata (may be NULL).
* Return 0 if permission is granted.
* @inode_setattr:
* Check permission before setting file attributes. Note that the kernel
@@ -428,24 +428,24 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* can use this hook to release any persistent label associated with the
* inode.
* @inode_setxattr:
- * Check permission before setting the extended attributes
- * @value identified by @name for @dentry.
- * Return 0 if permission is granted.
+ * Check permission before setting the extended attributes
+ * @value identified by @name for @dentry.
+ * Return 0 if permission is granted.
* @inode_post_setxattr:
- * Update inode security field after successful setxattr operation.
- * @value identified by @name for @dentry.
+ * Update inode security field after successful setxattr operation.
+ * @value identified by @name for @dentry.
* @inode_getxattr:
- * Check permission before obtaining the extended attributes
- * identified by @name for @dentry.
- * Return 0 if permission is granted.
+ * Check permission before obtaining the extended attributes
+ * identified by @name for @dentry.
+ * Return 0 if permission is granted.
* @inode_listxattr:
- * Check permission before obtaining the list of extended attribute
- * names for @dentry.
- * Return 0 if permission is granted.
+ * Check permission before obtaining the list of extended attribute
+ * names for @dentry.
+ * Return 0 if permission is granted.
* @inode_removexattr:
- * Check permission before removing the extended attribute
- * identified by @name for @dentry.
- * Return 0 if permission is granted.
+ * Check permission before removing the extended attribute
+ * identified by @name for @dentry.
+ * Return 0 if permission is granted.
* @inode_getsecurity:
* Retrieve a copy of the extended attribute representation of the
* security label associated with @name for @inode via @buffer. Note that
@@ -457,7 +457,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Set the security label associated with @name for @inode from the
* extended attribute value @value. @size indicates the size of the
* @value in bytes. @flags may be XATTR_CREATE, XATTR_REPLACE, or 0.
- * Note that @name is the remainder of the attribute name after the
+ * Note that @name is the remainder of the attribute name after the
* security. prefix has been removed.
* Return 0 on success.
* @inode_listsecurity:
@@ -564,7 +564,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* struct file, so the file structure (and associated security information)
* can always be obtained:
* container_of(fown, struct file, f_owner)
- * @tsk contains the structure of task receiving signal.
+ * @tsk contains the structure of task receiving signal.
* @fown contains the file owner information.
* @sig is the signal that will be sent. When 0, kernel sends SIGIO.
* Return 0 if permission is granted.
@@ -720,14 +720,16 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @arg3 contains a argument.
* @arg4 contains a argument.
* @arg5 contains a argument.
- * Return 0 if permission is granted.
+ * @rc_p contains a pointer to communicate back the forced return code
+ * Return 0 if permission is granted, and non-zero if the security module
+ * has taken responsibility (setting *rc_p) for the prctl call.
* @task_reparent_to_init:
- * Set the security attributes in @p->security for a kernel thread that
- * is being reparented to the init task.
+ * Set the security attributes in @p->security for a kernel thread that
+ * is being reparented to the init task.
* @p contains the task_struct for the kernel thread.
* @task_to_inode:
- * Set the security attributes for an inode based on an associated task's
- * security attributes, e.g. for /proc/pid inodes.
+ * Set the security attributes for an inode based on an associated task's
+ * security attributes, e.g. for /proc/pid inodes.
* @p contains the task_struct for the task.
* @inode contains the inode structure for the inode.
*
@@ -737,7 +739,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Save security information for a netlink message so that permission
* checking can be performed when the message is processed. The security
* information can be saved using the eff_cap field of the
- * netlink_skb_parms structure. Also may be used to provide fine
+ * netlink_skb_parms structure. Also may be used to provide fine
* grained control over message transmission.
* @sk associated sock of task sending the message.,
* @skb contains the sk_buff structure for the netlink message.
@@ -805,14 +807,14 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @sock contains the socket structure.
* @address contains the address to bind to.
* @addrlen contains the length of address.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted.
* @socket_connect:
* Check permission before socket protocol layer connect operation
* attempts to connect socket @sock to a remote address, @address.
* @sock contains the socket structure.
* @address contains the address of remote endpoint.
* @addrlen contains the length of address.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted.
* @socket_listen:
* Check permission before socket protocol layer listen operation.
* @sock contains the socket structure.
@@ -842,7 +844,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @msg contains the message structure.
* @size contains the size of message structure.
* @flags contains the operational flags.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted.
* @socket_getsockname:
* Check permission before the local address (name) of the socket object
* @sock is retrieved.
@@ -866,7 +868,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @sock contains the socket structure.
* @level contains the protocol level to set options for.
* @optname contains the name of the option to set.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted.
* @socket_shutdown:
* Checks permission before all or part of a connection on the socket
* @sock is shut down.
@@ -893,19 +895,19 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return 0 if all is well, otherwise, typical getsockopt return
* values.
* @socket_getpeersec_dgram:
- * This hook allows the security module to provide peer socket security
- * state for udp sockets on a per-packet basis to userspace via
- * getsockopt SO_GETPEERSEC. The application must first have indicated
- * the IP_PASSSEC option via getsockopt. It can then retrieve the
- * security state returned by this hook for a packet via the SCM_SECURITY
- * ancillary message type.
- * @skb is the skbuff for the packet being queried
- * @secdata is a pointer to a buffer in which to copy the security data
- * @seclen is the maximum length for @secdata
- * Return 0 on success, error on failure.
+ * This hook allows the security module to provide peer socket security
+ * state for udp sockets on a per-packet basis to userspace via
+ * getsockopt SO_GETPEERSEC. The application must first have indicated
+ * the IP_PASSSEC option via getsockopt. It can then retrieve the
+ * security state returned by this hook for a packet via the SCM_SECURITY
+ * ancillary message type.
+ * @skb is the skbuff for the packet being queried
+ * @secdata is a pointer to a buffer in which to copy the security data
+ * @seclen is the maximum length for @secdata
+ * Return 0 on success, error on failure.
* @sk_alloc_security:
- * Allocate and attach a security structure to the sk->sk_security field,
- * which is used to copy security attributes between local stream sockets.
+ * Allocate and attach a security structure to the sk->sk_security field,
+ * which is used to copy security attributes between local stream sockets.
* @sk_free_security:
* Deallocate security structure.
* @sk_clone_security:
@@ -920,7 +922,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @inet_csk_clone:
* Sets the new child socket's sid to the openreq sid.
* @inet_conn_established:
- * Sets the connection's peersid to the secmark on skb.
+ * Sets the connection's peersid to the secmark on skb.
* @req_classify_flow:
* Sets the flow's sid to the openreq sid.
*
@@ -999,13 +1001,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* No return value.
* @key_permission:
* See whether a specific operational right is granted to a process on a
- * key.
+ * key.
* @key_ref refers to the key (key pointer + possession attribute bit).
* @context points to the process to provide the context against which to
- * evaluate the security data on the key.
+ * evaluate the security data on the key.
* @perm describes the combination of permissions required of this key.
* Return 1 if permission granted, 0 if permission denied and -ve it the
- * normal permissions model should be effected.
+ * normal permissions model should be effected.
*
* Security hooks affecting all System V IPC operations.
*
@@ -1056,7 +1058,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* The @msq may be NULL, e.g. for IPC_INFO or MSG_INFO.
* @msq contains the message queue to act upon. May be NULL.
* @cmd contains the operation to be performed.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted.
* @msg_queue_msgsnd:
* Check permission before a message, @msg, is enqueued on the message
* queue, @msq.
@@ -1066,8 +1068,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return 0 if permission is granted.
* @msg_queue_msgrcv:
* Check permission before a message, @msg, is removed from the message
- * queue, @msq. The @target task structure contains a pointer to the
- * process that will be receiving the message (not equal to the current
+ * queue, @msq. The @target task structure contains a pointer to the
+ * process that will be receiving the message (not equal to the current
* process when inline receives are being performed).
* @msq contains the message queue to retrieve message from.
* @msg contains the message destination.
@@ -1132,15 +1134,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return 0 if permission is granted.
* @sem_semctl:
* Check permission when a semaphore operation specified by @cmd is to be
- * performed on the semaphore @sma. The @sma may be NULL, e.g. for
+ * performed on the semaphore @sma. The @sma may be NULL, e.g. for
* IPC_INFO or SEM_INFO.
* @sma contains the semaphore structure. May be NULL.
* @cmd contains the operation to be performed.
* Return 0 if permission is granted.
* @sem_semop
* Check permissions before performing operations on members of the
- * semaphore set @sma. If the @alter flag is nonzero, the semaphore set
- * may be modified.
+ * semaphore set @sma. If the @alter flag is nonzero, the semaphore set
+ * may be modified.
* @sma contains the semaphore structure.
* @sops contains the operations to perform.
* @nsops contains the number of operations to perform.
@@ -1211,7 +1213,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @syslog:
* Check permission before accessing the kernel message ring or changing
* logging to the console.
- * See the syslog(2) manual page for an explanation of the @type values.
+ * See the syslog(2) manual page for an explanation of the @type values.
* @type contains the type of action.
* Return 0 if permission is granted.
* @settime:
@@ -1223,22 +1225,22 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @vm_enough_memory:
* Check permissions for allocating a new virtual mapping.
* @mm contains the mm struct it is being added to.
- * @pages contains the number of pages.
+ * @pages contains the number of pages.
* Return 0 if permission is granted.
*
* @register_security:
- * allow module stacking.
- * @name contains the name of the security module being stacked.
- * @ops contains a pointer to the struct security_operations of the module to stack.
- *
+ * allow module stacking.
+ * @name contains the name of the security module being stacked.
+ * @ops contains a pointer to the struct security_operations of the module to stack.
+ *
* @secid_to_secctx:
* Convert secid to security context.
* @secid contains the security ID.
* @secdata contains the pointer that stores the converted security context.
* @secctx_to_secid:
- * Convert security context to secid.
- * @secid contains the pointer to the generated security ID.
- * @secdata contains the security context.
+ * Convert security context to secid.
+ * @secid contains the pointer to the generated security ID.
+ * @secdata contains the security context.
*
* @release_secctx:
* Release the security context.
@@ -1281,49 +1283,49 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
struct security_operations {
char name[SECURITY_NAME_MAX + 1];
- int (*ptrace) (struct task_struct * parent, struct task_struct * child);
- int (*capget) (struct task_struct * target,
- kernel_cap_t * effective,
- kernel_cap_t * inheritable, kernel_cap_t * permitted);
- int (*capset_check) (struct task_struct * target,
- kernel_cap_t * effective,
- kernel_cap_t * inheritable,
- kernel_cap_t * permitted);
- void (*capset_set) (struct task_struct * target,
- kernel_cap_t * effective,
- kernel_cap_t * inheritable,
- kernel_cap_t * permitted);
- int (*capable) (struct task_struct * tsk, int cap);
- int (*acct) (struct file * file);
- int (*sysctl) (struct ctl_table * table, int op);
- int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
- int (*quota_on) (struct dentry * dentry);
+ int (*ptrace) (struct task_struct *parent, struct task_struct *child);
+ int (*capget) (struct task_struct *target,
+ kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted);
+ int (*capset_check) (struct task_struct *target,
+ kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted);
+ void (*capset_set) (struct task_struct *target,
+ kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted);
+ int (*capable) (struct task_struct *tsk, int cap);
+ int (*acct) (struct file *file);
+ int (*sysctl) (struct ctl_table *table, int op);
+ int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
+ int (*quota_on) (struct dentry *dentry);
int (*syslog) (int type);
int (*settime) (struct timespec *ts, struct timezone *tz);
int (*vm_enough_memory) (struct mm_struct *mm, long pages);
- int (*bprm_alloc_security) (struct linux_binprm * bprm);
- void (*bprm_free_security) (struct linux_binprm * bprm);
- void (*bprm_apply_creds) (struct linux_binprm * bprm, int unsafe);
- void (*bprm_post_apply_creds) (struct linux_binprm * bprm);
- int (*bprm_set_security) (struct linux_binprm * bprm);
- int (*bprm_check_security) (struct linux_binprm * bprm);
- int (*bprm_secureexec) (struct linux_binprm * bprm);
-
- int (*sb_alloc_security) (struct super_block * sb);
- void (*sb_free_security) (struct super_block * sb);
- int (*sb_copy_data)(char *orig, char *copy);
+ int (*bprm_alloc_security) (struct linux_binprm *bprm);
+ void (*bprm_free_security) (struct linux_binprm *bprm);
+ void (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
+ void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
+ int (*bprm_set_security) (struct linux_binprm *bprm);
+ int (*bprm_check_security) (struct linux_binprm *bprm);
+ int (*bprm_secureexec) (struct linux_binprm *bprm);
+
+ int (*sb_alloc_security) (struct super_block *sb);
+ void (*sb_free_security) (struct super_block *sb);
+ int (*sb_copy_data) (char *orig, char *copy);
int (*sb_kern_mount) (struct super_block *sb, void *data);
int (*sb_statfs) (struct dentry *dentry);
int (*sb_mount) (char *dev_name, struct path *path,
char *type, unsigned long flags, void *data);
- int (*sb_check_sb) (struct vfsmount * mnt, struct path *path);
- int (*sb_umount) (struct vfsmount * mnt, int flags);
- void (*sb_umount_close) (struct vfsmount * mnt);
- void (*sb_umount_busy) (struct vfsmount * mnt);
- void (*sb_post_remount) (struct vfsmount * mnt,
+ int (*sb_check_sb) (struct vfsmount *mnt, struct path *path);
+ int (*sb_umount) (struct vfsmount *mnt, int flags);
+ void (*sb_umount_close) (struct vfsmount *mnt);
+ void (*sb_umount_busy) (struct vfsmount *mnt);
+ void (*sb_post_remount) (struct vfsmount *mnt,
unsigned long flags, void *data);
- void (*sb_post_addmount) (struct vfsmount * mnt,
+ void (*sb_post_addmount) (struct vfsmount *mnt,
struct path *mountpoint);
int (*sb_pivotroot) (struct path *old_path,
struct path *new_path);
@@ -1337,29 +1339,29 @@ struct security_operations {
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
- int (*inode_alloc_security) (struct inode *inode);
+ int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
int (*inode_init_security) (struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len);
int (*inode_create) (struct inode *dir,
- struct dentry *dentry, int mode);
+ struct dentry *dentry, int mode);
int (*inode_link) (struct dentry *old_dentry,
- struct inode *dir, struct dentry *new_dentry);
+ struct inode *dir, struct dentry *new_dentry);
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
int (*inode_symlink) (struct inode *dir,
- struct dentry *dentry, const char *old_name);
+ struct dentry *dentry, const char *old_name);
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode);
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
- int mode, dev_t dev);
+ int mode, dev_t dev);
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct inode *new_dir, struct dentry *new_dentry);
int (*inode_readlink) (struct dentry *dentry);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
- void (*inode_delete) (struct inode *inode);
+ void (*inode_delete) (struct inode *inode);
int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
size_t size, int flags);
void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value,
@@ -1369,145 +1371,145 @@ struct security_operations {
int (*inode_removexattr) (struct dentry *dentry, char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
- int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
- int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
- int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
- void (*inode_getsecid)(const struct inode *inode, u32 *secid);
-
- int (*file_permission) (struct file * file, int mask);
- int (*file_alloc_security) (struct file * file);
- void (*file_free_security) (struct file * file);
- int (*file_ioctl) (struct file * file, unsigned int cmd,
+ int (*inode_getsecurity) (const struct inode *inode, const char *name, void **buffer, bool alloc);
+ int (*inode_setsecurity) (struct inode *inode, const char *name, const void *value, size_t size, int flags);
+ int (*inode_listsecurity) (struct inode *inode, char *buffer, size_t buffer_size);
+ void (*inode_getsecid) (const struct inode *inode, u32 *secid);
+
+ int (*file_permission) (struct file *file, int mask);
+ int (*file_alloc_security) (struct file *file);
+ void (*file_free_security) (struct file *file);
+ int (*file_ioctl) (struct file *file, unsigned int cmd,
unsigned long arg);
- int (*file_mmap) (struct file * file,
+ int (*file_mmap) (struct file *file,
unsigned long reqprot, unsigned long prot,
unsigned long flags, unsigned long addr,
unsigned long addr_only);
- int (*file_mprotect) (struct vm_area_struct * vma,
+ int (*file_mprotect) (struct vm_area_struct *vma,
unsigned long reqprot,
unsigned long prot);
- int (*file_lock) (struct file * file, unsigned int cmd);
- int (*file_fcntl) (struct file * file, unsigned int cmd,
+ int (*file_lock) (struct file *file, unsigned int cmd);
+ int (*file_fcntl) (struct file *file, unsigned int cmd,
unsigned long arg);
- int (*file_set_fowner) (struct file * file);
- int (*file_send_sigiotask) (struct task_struct * tsk,
- struct fown_struct * fown, int sig);
- int (*file_receive) (struct file * file);
- int (*dentry_open) (struct file *file);
+ int (*file_set_fowner) (struct file *file);
+ int (*file_send_sigiotask) (struct task_struct *tsk,
+ struct fown_struct *fown, int sig);
+ int (*file_receive) (struct file *file);
+ int (*dentry_open) (struct file *file);
int (*task_create) (unsigned long clone_flags);
- int (*task_alloc_security) (struct task_struct * p);
- void (*task_free_security) (struct task_struct * p);
+ int (*task_alloc_security) (struct task_struct *p);
+ void (*task_free_security) (struct task_struct *p);
int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ ,
uid_t old_euid, uid_t old_suid, int flags);
int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags);
- int (*task_setpgid) (struct task_struct * p, pid_t pgid);
- int (*task_getpgid) (struct task_struct * p);
- int (*task_getsid) (struct task_struct * p);
- void (*task_getsecid) (struct task_struct * p, u32 * secid);
+ int (*task_setpgid) (struct task_struct *p, pid_t pgid);
+ int (*task_getpgid) (struct task_struct *p);
+ int (*task_getsid) (struct task_struct *p);
+ void (*task_getsecid) (struct task_struct *p, u32 *secid);
int (*task_setgroups) (struct group_info *group_info);
- int (*task_setnice) (struct task_struct * p, int nice);
- int (*task_setioprio) (struct task_struct * p, int ioprio);
- int (*task_getioprio) (struct task_struct * p);
- int (*task_setrlimit) (unsigned int resource, struct rlimit * new_rlim);
- int (*task_setscheduler) (struct task_struct * p, int policy,
- struct sched_param * lp);
- int (*task_getscheduler) (struct task_struct * p);
- int (*task_movememory) (struct task_struct * p);
- int (*task_kill) (struct task_struct * p,
- struct siginfo * info, int sig, u32 secid);
- int (*task_wait) (struct task_struct * p);
+ int (*task_setnice) (struct task_struct *p, int nice);
+ int (*task_setioprio) (struct task_struct *p, int ioprio);
+ int (*task_getioprio) (struct task_struct *p);
+ int (*task_setrlimit) (unsigned int resource, struct rlimit *new_rlim);
+ int (*task_setscheduler) (struct task_struct *p, int policy,
+ struct sched_param *lp);
+ int (*task_getscheduler) (struct task_struct *p);
+ int (*task_movememory) (struct task_struct *p);
+ int (*task_kill) (struct task_struct *p,
+ struct siginfo *info, int sig, u32 secid);
+ int (*task_wait) (struct task_struct *p);
int (*task_prctl) (int option, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
- unsigned long arg5);
- void (*task_reparent_to_init) (struct task_struct * p);
- void (*task_to_inode)(struct task_struct *p, struct inode *inode);
+ unsigned long arg5, long *rc_p);
+ void (*task_reparent_to_init) (struct task_struct *p);
+ void (*task_to_inode) (struct task_struct *p, struct inode *inode);
- int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+ int (*ipc_permission) (struct kern_ipc_perm *ipcp, short flag);
void (*ipc_getsecid) (struct kern_ipc_perm *ipcp, u32 *secid);
- int (*msg_msg_alloc_security) (struct msg_msg * msg);
- void (*msg_msg_free_security) (struct msg_msg * msg);
-
- int (*msg_queue_alloc_security) (struct msg_queue * msq);
- void (*msg_queue_free_security) (struct msg_queue * msq);
- int (*msg_queue_associate) (struct msg_queue * msq, int msqflg);
- int (*msg_queue_msgctl) (struct msg_queue * msq, int cmd);
- int (*msg_queue_msgsnd) (struct msg_queue * msq,
- struct msg_msg * msg, int msqflg);
- int (*msg_queue_msgrcv) (struct msg_queue * msq,
- struct msg_msg * msg,
- struct task_struct * target,
+ int (*msg_msg_alloc_security) (struct msg_msg *msg);
+ void (*msg_msg_free_security) (struct msg_msg *msg);
+
+ int (*msg_queue_alloc_security) (struct msg_queue *msq);
+ void (*msg_queue_free_security) (struct msg_queue *msq);
+ int (*msg_queue_associate) (struct msg_queue *msq, int msqflg);
+ int (*msg_queue_msgctl) (struct msg_queue *msq, int cmd);
+ int (*msg_queue_msgsnd) (struct msg_queue *msq,
+ struct msg_msg *msg, int msqflg);
+ int (*msg_queue_msgrcv) (struct msg_queue *msq,
+ struct msg_msg *msg,
+ struct task_struct *target,
long type, int mode);
- int (*shm_alloc_security) (struct shmid_kernel * shp);
- void (*shm_free_security) (struct shmid_kernel * shp);
- int (*shm_associate) (struct shmid_kernel * shp, int shmflg);
- int (*shm_shmctl) (struct shmid_kernel * shp, int cmd);
- int (*shm_shmat) (struct shmid_kernel * shp,
+ int (*shm_alloc_security) (struct shmid_kernel *shp);
+ void (*shm_free_security) (struct shmid_kernel *shp);
+ int (*shm_associate) (struct shmid_kernel *shp, int shmflg);
+ int (*shm_shmctl) (struct shmid_kernel *shp, int cmd);
+ int (*shm_shmat) (struct shmid_kernel *shp,
char __user *shmaddr, int shmflg);
- int (*sem_alloc_security) (struct sem_array * sma);
- void (*sem_free_security) (struct sem_array * sma);
- int (*sem_associate) (struct sem_array * sma, int semflg);
- int (*sem_semctl) (struct sem_array * sma, int cmd);
- int (*sem_semop) (struct sem_array * sma,
- struct sembuf * sops, unsigned nsops, int alter);
+ int (*sem_alloc_security) (struct sem_array *sma);
+ void (*sem_free_security) (struct sem_array *sma);
+ int (*sem_associate) (struct sem_array *sma, int semflg);
+ int (*sem_semctl) (struct sem_array *sma, int cmd);
+ int (*sem_semop) (struct sem_array *sma,
+ struct sembuf *sops, unsigned nsops, int alter);
- int (*netlink_send) (struct sock * sk, struct sk_buff * skb);
- int (*netlink_recv) (struct sk_buff * skb, int cap);
+ int (*netlink_send) (struct sock *sk, struct sk_buff *skb);
+ int (*netlink_recv) (struct sk_buff *skb, int cap);
/* allow module stacking */
int (*register_security) (const char *name,
- struct security_operations *ops);
+ struct security_operations *ops);
void (*d_instantiate) (struct dentry *dentry, struct inode *inode);
- int (*getprocattr)(struct task_struct *p, char *name, char **value);
- int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size);
- int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
- int (*secctx_to_secid)(char *secdata, u32 seclen, u32 *secid);
- void (*release_secctx)(char *secdata, u32 seclen);
+ int (*getprocattr) (struct task_struct *p, char *name, char **value);
+ int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
+ int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
+ int (*secctx_to_secid) (char *secdata, u32 seclen, u32 *secid);
+ void (*release_secctx) (char *secdata, u32 seclen);
#ifdef CONFIG_SECURITY_NETWORK
- int (*unix_stream_connect) (struct socket * sock,
- struct socket * other, struct sock * newsk);
- int (*unix_may_send) (struct socket * sock, struct socket * other);
+ int (*unix_stream_connect) (struct socket *sock,
+ struct socket *other, struct sock *newsk);
+ int (*unix_may_send) (struct socket *sock, struct socket *other);
int (*socket_create) (int family, int type, int protocol, int kern);
- int (*socket_post_create) (struct socket * sock, int family,
+ int (*socket_post_create) (struct socket *sock, int family,
int type, int protocol, int kern);
- int (*socket_bind) (struct socket * sock,
- struct sockaddr * address, int addrlen);
- int (*socket_connect) (struct socket * sock,
- struct sockaddr * address, int addrlen);
- int (*socket_listen) (struct socket * sock, int backlog);
- int (*socket_accept) (struct socket * sock, struct socket * newsock);
- void (*socket_post_accept) (struct socket * sock,
- struct socket * newsock);
- int (*socket_sendmsg) (struct socket * sock,
- struct msghdr * msg, int size);
- int (*socket_recvmsg) (struct socket * sock,
- struct msghdr * msg, int size, int flags);
- int (*socket_getsockname) (struct socket * sock);
- int (*socket_getpeername) (struct socket * sock);
- int (*socket_getsockopt) (struct socket * sock, int level, int optname);
- int (*socket_setsockopt) (struct socket * sock, int level, int optname);
- int (*socket_shutdown) (struct socket * sock, int how);
- int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
+ int (*socket_bind) (struct socket *sock,
+ struct sockaddr *address, int addrlen);
+ int (*socket_connect) (struct socket *sock,
+ struct sockaddr *address, int addrlen);
+ int (*socket_listen) (struct socket *sock, int backlog);
+ int (*socket_accept) (struct socket *sock, struct socket *newsock);
+ void (*socket_post_accept) (struct socket *sock,
+ struct socket *newsock);
+ int (*socket_sendmsg) (struct socket *sock,
+ struct msghdr *msg, int size);
+ int (*socket_recvmsg) (struct socket *sock,
+ struct msghdr *msg, int size, int flags);
+ int (*socket_getsockname) (struct socket *sock);
+ int (*socket_getpeername) (struct socket *sock);
+ int (*socket_getsockopt) (struct socket *sock, int level, int optname);
+ int (*socket_setsockopt) (struct socket *sock, int level, int optname);
+ int (*socket_shutdown) (struct socket *sock, int how);
+ int (*socket_sock_rcv_skb) (struct sock *sk, struct sk_buff *skb);
int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
void (*sk_free_security) (struct sock *sk);
void (*sk_clone_security) (const struct sock *sk, struct sock *newsk);
void (*sk_getsecid) (struct sock *sk, u32 *secid);
- void (*sock_graft)(struct sock* sk, struct socket *parent);
- int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req);
- void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req);
- void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb);
- void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl);
+ void (*sock_graft) (struct sock *sk, struct socket *parent);
+ int (*inet_conn_request) (struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req);
+ void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req);
+ void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb);
+ void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1521,57 +1523,57 @@ struct security_operations {
u32 secid);
void (*xfrm_state_free_security) (struct xfrm_state *x);
int (*xfrm_state_delete_security) (struct xfrm_state *x);
- int (*xfrm_policy_lookup)(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
- int (*xfrm_state_pol_flow_match)(struct xfrm_state *x,
- struct xfrm_policy *xp, struct flowi *fl);
- int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall);
+ int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
+ int (*xfrm_state_pol_flow_match) (struct xfrm_state *x,
+ struct xfrm_policy *xp,
+ struct flowi *fl);
+ int (*xfrm_decode_session) (struct sk_buff *skb, u32 *secid, int ckall);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
/* key management security hooks */
#ifdef CONFIG_KEYS
- int (*key_alloc)(struct key *key, struct task_struct *tsk, unsigned long flags);
- void (*key_free)(struct key *key);
- int (*key_permission)(key_ref_t key_ref,
- struct task_struct *context,
- key_perm_t perm);
+ int (*key_alloc) (struct key *key, struct task_struct *tsk, unsigned long flags);
+ void (*key_free) (struct key *key);
+ int (*key_permission) (key_ref_t key_ref,
+ struct task_struct *context,
+ key_perm_t perm);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
- int (*audit_rule_init)(u32 field, u32 op, char *rulestr, void **lsmrule);
- int (*audit_rule_known)(struct audit_krule *krule);
- int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule,
- struct audit_context *actx);
- void (*audit_rule_free)(void *lsmrule);
+ int (*audit_rule_init) (u32 field, u32 op, char *rulestr, void **lsmrule);
+ int (*audit_rule_known) (struct audit_krule *krule);
+ int (*audit_rule_match) (u32 secid, u32 field, u32 op, void *lsmrule,
+ struct audit_context *actx);
+ void (*audit_rule_free) (void *lsmrule);
#endif /* CONFIG_AUDIT */
};
/* prototypes */
-extern int security_init (void);
+extern int security_init(void);
extern int security_module_enable(struct security_operations *ops);
-extern int register_security (struct security_operations *ops);
-extern int mod_reg_security (const char *name, struct security_operations *ops);
+extern int register_security(struct security_operations *ops);
+extern int mod_reg_security(const char *name, struct security_operations *ops);
extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops);
extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent);
extern void securityfs_remove(struct dentry *dentry);
-
/* Security operations */
int security_ptrace(struct task_struct *parent, struct task_struct *child);
int security_capget(struct task_struct *target,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted);
+ kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted);
int security_capset_check(struct task_struct *target,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted);
-void security_capset_set(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
+void security_capset_set(struct task_struct *target,
+ kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted);
int security_capable(struct task_struct *tsk, int cap);
int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op);
@@ -1594,7 +1596,7 @@ int security_sb_copy_data(char *orig, char *copy);
int security_sb_kern_mount(struct super_block *sb, void *data);
int security_sb_statfs(struct dentry *dentry);
int security_sb_mount(char *dev_name, struct path *path,
- char *type, unsigned long flags, void *data);
+ char *type, unsigned long flags, void *data);
int security_sb_check_sb(struct vfsmount *mnt, struct path *path);
int security_sb_umount(struct vfsmount *mnt, int flags);
void security_sb_umount_close(struct vfsmount *mnt);
@@ -1619,12 +1621,12 @@ int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry);
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
- const char *old_name);
+ const char *old_name);
int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct inode *new_dir, struct dentry *new_dentry);
int security_inode_readlink(struct dentry *dentry);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd);
@@ -1632,9 +1634,9 @@ int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
int security_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags);
+ void *value, size_t size, int flags);
void security_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags);
+ void *value, size_t size, int flags);
int security_inode_getxattr(struct dentry *dentry, char *name);
int security_inode_listxattr(struct dentry *dentry);
int security_inode_removexattr(struct dentry *dentry, char *name);
@@ -1652,12 +1654,12 @@ int security_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags,
unsigned long addr, unsigned long addr_only);
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
- unsigned long prot);
+ unsigned long prot);
int security_file_lock(struct file *file, unsigned int cmd);
int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
int security_file_set_fowner(struct file *file);
int security_file_send_sigiotask(struct task_struct *tsk,
- struct fown_struct *fown, int sig);
+ struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
int security_dentry_open(struct file *file);
int security_task_create(unsigned long clone_flags);
@@ -1665,7 +1667,7 @@ int security_task_alloc(struct task_struct *p);
void security_task_free(struct task_struct *p);
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
- uid_t old_suid, int flags);
+ uid_t old_suid, int flags);
int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags);
int security_task_setpgid(struct task_struct *p, pid_t pgid);
int security_task_getpgid(struct task_struct *p);
@@ -1684,7 +1686,7 @@ int security_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid);
int security_task_wait(struct task_struct *p);
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5);
+ unsigned long arg4, unsigned long arg5, long *rc_p);
void security_task_reparent_to_init(struct task_struct *p);
void security_task_to_inode(struct task_struct *p, struct inode *inode);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
@@ -1696,9 +1698,9 @@ void security_msg_queue_free(struct msg_queue *msq);
int security_msg_queue_associate(struct msg_queue *msq, int msqflg);
int security_msg_queue_msgctl(struct msg_queue *msq, int cmd);
int security_msg_queue_msgsnd(struct msg_queue *msq,
- struct msg_msg *msg, int msqflg);
+ struct msg_msg *msg, int msqflg);
int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
- struct task_struct *target, long type, int mode);
+ struct task_struct *target, long type, int mode);
int security_shm_alloc(struct shmid_kernel *shp);
void security_shm_free(struct shmid_kernel *shp);
int security_shm_associate(struct shmid_kernel *shp, int shmflg);
@@ -1710,7 +1712,7 @@ int security_sem_associate(struct sem_array *sma, int semflg);
int security_sem_semctl(struct sem_array *sma, int cmd);
int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
unsigned nsops, int alter);
-void security_d_instantiate (struct dentry *dentry, struct inode *inode);
+void security_d_instantiate(struct dentry *dentry, struct inode *inode);
int security_getprocattr(struct task_struct *p, char *name, char **value);
int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
@@ -1741,33 +1743,33 @@ static inline int security_init(void)
return 0;
}
-static inline int security_ptrace (struct task_struct *parent, struct task_struct * child)
+static inline int security_ptrace(struct task_struct *parent, struct task_struct *child)
{
- return cap_ptrace (parent, child);
+ return cap_ptrace(parent, child);
}
-static inline int security_capget (struct task_struct *target,
+static inline int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
- return cap_capget (target, effective, inheritable, permitted);
+ return cap_capget(target, effective, inheritable, permitted);
}
-static inline int security_capset_check (struct task_struct *target,
+static inline int security_capset_check(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
- return cap_capset_check (target, effective, inheritable, permitted);
+ return cap_capset_check(target, effective, inheritable, permitted);
}
-static inline void security_capset_set (struct task_struct *target,
+static inline void security_capset_set(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
- cap_capset_set (target, effective, inheritable, permitted);
+ cap_capset_set(target, effective, inheritable, permitted);
}
static inline int security_capable(struct task_struct *tsk, int cap)
@@ -1775,7 +1777,7 @@ static inline int security_capable(struct task_struct *tsk, int cap)
return cap_capable(tsk, cap);
}
-static inline int security_acct (struct file *file)
+static inline int security_acct(struct file *file)
{
return 0;
}
@@ -1785,13 +1787,13 @@ static inline int security_sysctl(struct ctl_table *table, int op)
return 0;
}
-static inline int security_quotactl (int cmds, int type, int id,
- struct super_block * sb)
+static inline int security_quotactl(int cmds, int type, int id,
+ struct super_block *sb)
{
return 0;
}
-static inline int security_quota_on (struct dentry * dentry)
+static inline int security_quota_on(struct dentry *dentry)
{
return 0;
}
@@ -1816,102 +1818,102 @@ static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
return cap_vm_enough_memory(mm, pages);
}
-static inline int security_bprm_alloc (struct linux_binprm *bprm)
+static inline int security_bprm_alloc(struct linux_binprm *bprm)
{
return 0;
}
-static inline void security_bprm_free (struct linux_binprm *bprm)
+static inline void security_bprm_free(struct linux_binprm *bprm)
{ }
-static inline void security_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
-{
- cap_bprm_apply_creds (bprm, unsafe);
+static inline void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+{
+ cap_bprm_apply_creds(bprm, unsafe);
}
-static inline void security_bprm_post_apply_creds (struct linux_binprm *bprm)
+static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm)
{
return;
}
-static inline int security_bprm_set (struct linux_binprm *bprm)
+static inline int security_bprm_set(struct linux_binprm *bprm)
{
- return cap_bprm_set_security (bprm);
+ return cap_bprm_set_security(bprm);
}
-static inline int security_bprm_check (struct linux_binprm *bprm)
+static inline int security_bprm_check(struct linux_binprm *bprm)
{
return 0;
}
-static inline int security_bprm_secureexec (struct linux_binprm *bprm)
+static inline int security_bprm_secureexec(struct linux_binprm *bprm)
{
return cap_bprm_secureexec(bprm);
}
-static inline int security_sb_alloc (struct super_block *sb)
+static inline int security_sb_alloc(struct super_block *sb)
{
return 0;
}
-static inline void security_sb_free (struct super_block *sb)
+static inline void security_sb_free(struct super_block *sb)
{ }
-static inline int security_sb_copy_data (char *orig, char *copy)
+static inline int security_sb_copy_data(char *orig, char *copy)
{
return 0;
}
-static inline int security_sb_kern_mount (struct super_block *sb, void *data)
+static inline int security_sb_kern_mount(struct super_block *sb, void *data)
{
return 0;
}
-static inline int security_sb_statfs (struct dentry *dentry)
+static inline int security_sb_statfs(struct dentry *dentry)
{
return 0;
}
-static inline int security_sb_mount (char *dev_name, struct path *path,
+static inline int security_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags,
void *data)
{
return 0;
}
-static inline int security_sb_check_sb (struct vfsmount *mnt,
- struct path *path)
+static inline int security_sb_check_sb(struct vfsmount *mnt,
+ struct path *path)
{
return 0;
}
-static inline int security_sb_umount (struct vfsmount *mnt, int flags)
+static inline int security_sb_umount(struct vfsmount *mnt, int flags)
{
return 0;
}
-static inline void security_sb_umount_close (struct vfsmount *mnt)
+static inline void security_sb_umount_close(struct vfsmount *mnt)
{ }
-static inline void security_sb_umount_busy (struct vfsmount *mnt)
+static inline void security_sb_umount_busy(struct vfsmount *mnt)
{ }
-static inline void security_sb_post_remount (struct vfsmount *mnt,
+static inline void security_sb_post_remount(struct vfsmount *mnt,
unsigned long flags, void *data)
{ }
-static inline void security_sb_post_addmount (struct vfsmount *mnt,
- struct path *mountpoint)
+static inline void security_sb_post_addmount(struct vfsmount *mnt,
+ struct path *mountpoint)
{ }
-static inline int security_sb_pivotroot (struct path *old_path,
- struct path *new_path)
+static inline int security_sb_pivotroot(struct path *old_path,
+ struct path *new_path)
{
return 0;
}
-static inline void security_sb_post_pivotroot (struct path *old_path,
- struct path *new_path)
+static inline void security_sb_post_pivotroot(struct path *old_path,
+ struct path *new_path)
{ }
static inline int security_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts)
@@ -1935,15 +1937,15 @@ static inline int security_sb_parse_opts_str(char *options, struct security_mnt_
return 0;
}
-static inline int security_inode_alloc (struct inode *inode)
+static inline int security_inode_alloc(struct inode *inode)
{
return 0;
}
-static inline void security_inode_free (struct inode *inode)
+static inline void security_inode_free(struct inode *inode)
{ }
-static inline int security_inode_init_security (struct inode *inode,
+static inline int security_inode_init_security(struct inode *inode,
struct inode *dir,
char **name,
void **value,
@@ -1951,55 +1953,55 @@ static inline int security_inode_init_security (struct inode *inode,
{
return -EOPNOTSUPP;
}
-
-static inline int security_inode_create (struct inode *dir,
+
+static inline int security_inode_create(struct inode *dir,
struct dentry *dentry,
int mode)
{
return 0;
}
-static inline int security_inode_link (struct dentry *old_dentry,
+static inline int security_inode_link(struct dentry *old_dentry,
struct inode *dir,
struct dentry *new_dentry)
{
return 0;
}
-static inline int security_inode_unlink (struct inode *dir,
+static inline int security_inode_unlink(struct inode *dir,
struct dentry *dentry)
{
return 0;
}
-static inline int security_inode_symlink (struct inode *dir,
+static inline int security_inode_symlink(struct inode *dir,
struct dentry *dentry,
const char *old_name)
{
return 0;
}
-static inline int security_inode_mkdir (struct inode *dir,
+static inline int security_inode_mkdir(struct inode *dir,
struct dentry *dentry,
int mode)
{
return 0;
}
-static inline int security_inode_rmdir (struct inode *dir,
+static inline int security_inode_rmdir(struct inode *dir,
struct dentry *dentry)
{
return 0;
}
-static inline int security_inode_mknod (struct inode *dir,
+static inline int security_inode_mknod(struct inode *dir,
struct dentry *dentry,
int mode, dev_t dev)
{
return 0;
}
-static inline int security_inode_rename (struct inode *old_dir,
+static inline int security_inode_rename(struct inode *old_dir,
struct dentry *old_dentry,
struct inode *new_dir,
struct dentry *new_dentry)
@@ -2007,59 +2009,59 @@ static inline int security_inode_rename (struct inode *old_dir,
return 0;
}
-static inline int security_inode_readlink (struct dentry *dentry)
+static inline int security_inode_readlink(struct dentry *dentry)
{
return 0;
}
-static inline int security_inode_follow_link (struct dentry *dentry,
+static inline int security_inode_follow_link(struct dentry *dentry,
struct nameidata *nd)
{
return 0;
}
-static inline int security_inode_permission (struct inode *inode, int mask,
+static inline int security_inode_permission(struct inode *inode, int mask,
struct nameidata *nd)
{
return 0;
}
-static inline int security_inode_setattr (struct dentry *dentry,
+static inline int security_inode_setattr(struct dentry *dentry,
struct iattr *attr)
{
return 0;
}
-static inline int security_inode_getattr (struct vfsmount *mnt,
+static inline int security_inode_getattr(struct vfsmount *mnt,
struct dentry *dentry)
{
return 0;
}
-static inline void security_inode_delete (struct inode *inode)
+static inline void security_inode_delete(struct inode *inode)
{ }
-static inline int security_inode_setxattr (struct dentry *dentry, char *name,
+static inline int security_inode_setxattr(struct dentry *dentry, char *name,
void *value, size_t size, int flags)
{
return cap_inode_setxattr(dentry, name, value, size, flags);
}
-static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
+static inline void security_inode_post_setxattr(struct dentry *dentry, char *name,
void *value, size_t size, int flags)
{ }
-static inline int security_inode_getxattr (struct dentry *dentry, char *name)
+static inline int security_inode_getxattr(struct dentry *dentry, char *name)
{
return 0;
}
-static inline int security_inode_listxattr (struct dentry *dentry)
+static inline int security_inode_listxattr(struct dentry *dentry)
{
return 0;
}
-static inline int security_inode_removexattr (struct dentry *dentry, char *name)
+static inline int security_inode_removexattr(struct dentry *dentry, char *name)
{
return cap_inode_removexattr(dentry, name);
}
@@ -2094,198 +2096,198 @@ static inline void security_inode_getsecid(const struct inode *inode, u32 *secid
*secid = 0;
}
-static inline int security_file_permission (struct file *file, int mask)
+static inline int security_file_permission(struct file *file, int mask)
{
return 0;
}
-static inline int security_file_alloc (struct file *file)
+static inline int security_file_alloc(struct file *file)
{
return 0;
}
-static inline void security_file_free (struct file *file)
+static inline void security_file_free(struct file *file)
{ }
-static inline int security_file_ioctl (struct file *file, unsigned int cmd,
- unsigned long arg)
+static inline int security_file_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
return 0;
}
-static inline int security_file_mmap (struct file *file, unsigned long reqprot,
- unsigned long prot,
- unsigned long flags,
- unsigned long addr,
- unsigned long addr_only)
+static inline int security_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot,
+ unsigned long flags,
+ unsigned long addr,
+ unsigned long addr_only)
{
return 0;
}
-static inline int security_file_mprotect (struct vm_area_struct *vma,
- unsigned long reqprot,
- unsigned long prot)
+static inline int security_file_mprotect(struct vm_area_struct *vma,
+ unsigned long reqprot,
+ unsigned long prot)
{
return 0;
}
-static inline int security_file_lock (struct file *file, unsigned int cmd)
+static inline int security_file_lock(struct file *file, unsigned int cmd)
{
return 0;
}
-static inline int security_file_fcntl (struct file *file, unsigned int cmd,
- unsigned long arg)
+static inline int security_file_fcntl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
return 0;
}
-static inline int security_file_set_fowner (struct file *file)
+static inline int security_file_set_fowner(struct file *file)
{
return 0;
}
-static inline int security_file_send_sigiotask (struct task_struct *tsk,
- struct fown_struct *fown,
- int sig)
+static inline int security_file_send_sigiotask(struct task_struct *tsk,
+ struct fown_struct *fown,
+ int sig)
{
return 0;
}
-static inline int security_file_receive (struct file *file)
+static inline int security_file_receive(struct file *file)
{
return 0;
}
-static inline int security_dentry_open (struct file *file)
+static inline int security_dentry_open(struct file *file)
{
return 0;
}
-static inline int security_task_create (unsigned long clone_flags)
+static inline int security_task_create(unsigned long clone_flags)
{
return 0;
}
-static inline int security_task_alloc (struct task_struct *p)
+static inline int security_task_alloc(struct task_struct *p)
{
return 0;
}
-static inline void security_task_free (struct task_struct *p)
+static inline void security_task_free(struct task_struct *p)
{ }
-static inline int security_task_setuid (uid_t id0, uid_t id1, uid_t id2,
- int flags)
+static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
+ int flags)
{
return 0;
}
-static inline int security_task_post_setuid (uid_t old_ruid, uid_t old_euid,
- uid_t old_suid, int flags)
+static inline int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
+ uid_t old_suid, int flags)
{
- return cap_task_post_setuid (old_ruid, old_euid, old_suid, flags);
+ return cap_task_post_setuid(old_ruid, old_euid, old_suid, flags);
}
-static inline int security_task_setgid (gid_t id0, gid_t id1, gid_t id2,
- int flags)
+static inline int security_task_setgid(gid_t id0, gid_t id1, gid_t id2,
+ int flags)
{
return 0;
}
-static inline int security_task_setpgid (struct task_struct *p, pid_t pgid)
+static inline int security_task_setpgid(struct task_struct *p, pid_t pgid)
{
return 0;
}
-static inline int security_task_getpgid (struct task_struct *p)
+static inline int security_task_getpgid(struct task_struct *p)
{
return 0;
}
-static inline int security_task_getsid (struct task_struct *p)
+static inline int security_task_getsid(struct task_struct *p)
{
return 0;
}
-static inline void security_task_getsecid (struct task_struct *p, u32 *secid)
+static inline void security_task_getsecid(struct task_struct *p, u32 *secid)
{
*secid = 0;
}
-static inline int security_task_setgroups (struct group_info *group_info)
+static inline int security_task_setgroups(struct group_info *group_info)
{
return 0;
}
-static inline int security_task_setnice (struct task_struct *p, int nice)
+static inline int security_task_setnice(struct task_struct *p, int nice)
{
return cap_task_setnice(p, nice);
}
-static inline int security_task_setioprio (struct task_struct *p, int ioprio)
+static inline int security_task_setioprio(struct task_struct *p, int ioprio)
{
return cap_task_setioprio(p, ioprio);
}
-static inline int security_task_getioprio (struct task_struct *p)
+static inline int security_task_getioprio(struct task_struct *p)
{
return 0;
}
-static inline int security_task_setrlimit (unsigned int resource,
- struct rlimit *new_rlim)
+static inline int security_task_setrlimit(unsigned int resource,
+ struct rlimit *new_rlim)
{
return 0;
}
-static inline int security_task_setscheduler (struct task_struct *p,
- int policy,
- struct sched_param *lp)
+static inline int security_task_setscheduler(struct task_struct *p,
+ int policy,
+ struct sched_param *lp)
{
return cap_task_setscheduler(p, policy, lp);
}
-static inline int security_task_getscheduler (struct task_struct *p)
+static inline int security_task_getscheduler(struct task_struct *p)
{
return 0;
}
-static inline int security_task_movememory (struct task_struct *p)
+static inline int security_task_movememory(struct task_struct *p)
{
return 0;
}
-static inline int security_task_kill (struct task_struct *p,
- struct siginfo *info, int sig,
- u32 secid)
+static inline int security_task_kill(struct task_struct *p,
+ struct siginfo *info, int sig,
+ u32 secid)
{
return 0;
}
-static inline int security_task_wait (struct task_struct *p)
+static inline int security_task_wait(struct task_struct *p)
{
return 0;
}
-static inline int security_task_prctl (int option, unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long arg5)
+static inline int security_task_prctl(int option, unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5, long *rc_p)
{
- return 0;
+ return cap_task_prctl(option, arg2, arg3, arg3, arg5, rc_p);
}
-static inline void security_task_reparent_to_init (struct task_struct *p)
+static inline void security_task_reparent_to_init(struct task_struct *p)
{
- cap_task_reparent_to_init (p);
+ cap_task_reparent_to_init(p);
}
static inline void security_task_to_inode(struct task_struct *p, struct inode *inode)
{ }
-static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
- short flag)
+static inline int security_ipc_permission(struct kern_ipc_perm *ipcp,
+ short flag)
{
return 0;
}
@@ -2295,98 +2297,98 @@ static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
*secid = 0;
}
-static inline int security_msg_msg_alloc (struct msg_msg * msg)
+static inline int security_msg_msg_alloc(struct msg_msg *msg)
{
return 0;
}
-static inline void security_msg_msg_free (struct msg_msg * msg)
+static inline void security_msg_msg_free(struct msg_msg *msg)
{ }
-static inline int security_msg_queue_alloc (struct msg_queue *msq)
+static inline int security_msg_queue_alloc(struct msg_queue *msq)
{
return 0;
}
-static inline void security_msg_queue_free (struct msg_queue *msq)
+static inline void security_msg_queue_free(struct msg_queue *msq)
{ }
-static inline int security_msg_queue_associate (struct msg_queue * msq,
- int msqflg)
+static inline int security_msg_queue_associate(struct msg_queue *msq,
+ int msqflg)
{
return 0;
}
-static inline int security_msg_queue_msgctl (struct msg_queue * msq, int cmd)
+static inline int security_msg_queue_msgctl(struct msg_queue *msq, int cmd)
{
return 0;
}
-static inline int security_msg_queue_msgsnd (struct msg_queue * msq,
- struct msg_msg * msg, int msqflg)
+static inline int security_msg_queue_msgsnd(struct msg_queue *msq,
+ struct msg_msg *msg, int msqflg)
{
return 0;
}
-static inline int security_msg_queue_msgrcv (struct msg_queue * msq,
- struct msg_msg * msg,
- struct task_struct * target,
- long type, int mode)
+static inline int security_msg_queue_msgrcv(struct msg_queue *msq,
+ struct msg_msg *msg,
+ struct task_struct *target,
+ long type, int mode)
{
return 0;
}
-static inline int security_shm_alloc (struct shmid_kernel *shp)
+static inline int security_shm_alloc(struct shmid_kernel *shp)
{
return 0;
}
-static inline void security_shm_free (struct shmid_kernel *shp)
+static inline void security_shm_free(struct shmid_kernel *shp)
{ }
-static inline int security_shm_associate (struct shmid_kernel * shp,
- int shmflg)
+static inline int security_shm_associate(struct shmid_kernel *shp,
+ int shmflg)
{
return 0;
}
-static inline int security_shm_shmctl (struct shmid_kernel * shp, int cmd)
+static inline int security_shm_shmctl(struct shmid_kernel *shp, int cmd)
{
return 0;
}
-static inline int security_shm_shmat (struct shmid_kernel * shp,
- char __user *shmaddr, int shmflg)
+static inline int security_shm_shmat(struct shmid_kernel *shp,
+ char __user *shmaddr, int shmflg)
{
return 0;
}
-static inline int security_sem_alloc (struct sem_array *sma)
+static inline int security_sem_alloc(struct sem_array *sma)
{
return 0;
}
-static inline void security_sem_free (struct sem_array *sma)
+static inline void security_sem_free(struct sem_array *sma)
{ }
-static inline int security_sem_associate (struct sem_array * sma, int semflg)
+static inline int security_sem_associate(struct sem_array *sma, int semflg)
{
return 0;
}
-static inline int security_sem_semctl (struct sem_array * sma, int cmd)
+static inline int security_sem_semctl(struct sem_array *sma, int cmd)
{
return 0;
}
-static inline int security_sem_semop (struct sem_array * sma,
- struct sembuf * sops, unsigned nsops,
- int alter)
+static inline int security_sem_semop(struct sem_array *sma,
+ struct sembuf *sops, unsigned nsops,
+ int alter)
{
return 0;
}
-static inline void security_d_instantiate (struct dentry *dentry, struct inode *inode)
+static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
{ }
static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
@@ -2399,14 +2401,14 @@ static inline int security_setprocattr(struct task_struct *p, char *name, void *
return -EINVAL;
}
-static inline int security_netlink_send (struct sock *sk, struct sk_buff *skb)
+static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- return cap_netlink_send (sk, skb);
+ return cap_netlink_send(sk, skb);
}
-static inline int security_netlink_recv (struct sk_buff *skb, int cap)
+static inline int security_netlink_recv(struct sk_buff *skb, int cap)
{
- return cap_netlink_recv (skb, cap);
+ return cap_netlink_recv(skb, cap);
}
static inline struct dentry *securityfs_create_dir(const char *name,
@@ -2484,26 +2486,26 @@ void security_inet_conn_established(struct sock *sk,
struct sk_buff *skb);
#else /* CONFIG_SECURITY_NETWORK */
-static inline int security_unix_stream_connect(struct socket * sock,
- struct socket * other,
- struct sock * newsk)
+static inline int security_unix_stream_connect(struct socket *sock,
+ struct socket *other,
+ struct sock *newsk)
{
return 0;
}
-static inline int security_unix_may_send(struct socket * sock,
- struct socket * other)
+static inline int security_unix_may_send(struct socket *sock,
+ struct socket *other)
{
return 0;
}
-static inline int security_socket_create (int family, int type,
- int protocol, int kern)
+static inline int security_socket_create(int family, int type,
+ int protocol, int kern)
{
return 0;
}
-static inline int security_socket_post_create(struct socket * sock,
+static inline int security_socket_post_create(struct socket *sock,
int family,
int type,
int protocol, int kern)
@@ -2511,77 +2513,77 @@ static inline int security_socket_post_create(struct socket * sock,
return 0;
}
-static inline int security_socket_bind(struct socket * sock,
- struct sockaddr * address,
+static inline int security_socket_bind(struct socket *sock,
+ struct sockaddr *address,
int addrlen)
{
return 0;
}
-static inline int security_socket_connect(struct socket * sock,
- struct sockaddr * address,
+static inline int security_socket_connect(struct socket *sock,
+ struct sockaddr *address,
int addrlen)
{
return 0;
}
-static inline int security_socket_listen(struct socket * sock, int backlog)
+static inline int security_socket_listen(struct socket *sock, int backlog)
{
return 0;
}
-static inline int security_socket_accept(struct socket * sock,
- struct socket * newsock)
+static inline int security_socket_accept(struct socket *sock,
+ struct socket *newsock)
{
return 0;
}
-static inline void security_socket_post_accept(struct socket * sock,
- struct socket * newsock)
+static inline void security_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
{
}
-static inline int security_socket_sendmsg(struct socket * sock,
- struct msghdr * msg, int size)
+static inline int security_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
{
return 0;
}
-static inline int security_socket_recvmsg(struct socket * sock,
- struct msghdr * msg, int size,
+static inline int security_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size,
int flags)
{
return 0;
}
-static inline int security_socket_getsockname(struct socket * sock)
+static inline int security_socket_getsockname(struct socket *sock)
{
return 0;
}
-static inline int security_socket_getpeername(struct socket * sock)
+static inline int security_socket_getpeername(struct socket *sock)
{
return 0;
}
-static inline int security_socket_getsockopt(struct socket * sock,
+static inline int security_socket_getsockopt(struct socket *sock,
int level, int optname)
{
return 0;
}
-static inline int security_socket_setsockopt(struct socket * sock,
+static inline int security_socket_setsockopt(struct socket *sock,
int level, int optname)
{
return 0;
}
-static inline int security_socket_shutdown(struct socket * sock, int how)
+static inline int security_socket_shutdown(struct socket *sock, int how)
{
return 0;
}
-static inline int security_sock_rcv_skb (struct sock * sk,
- struct sk_buff * skb)
+static inline int security_sock_rcv_skb(struct sock *sk,
+ struct sk_buff *skb)
{
return 0;
}
@@ -2618,7 +2620,7 @@ static inline void security_req_classify_flow(const struct request_sock *req, st
{
}
-static inline void security_sock_graft(struct sock* sk, struct socket *parent)
+static inline void security_sock_graft(struct sock *sk, struct socket *parent)
{
}
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 26e4925bc35b..632205ccc25d 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -85,23 +85,29 @@ static inline int write_tryseqlock(seqlock_t *sl)
/* Start of read calculation -- fetch last complete writer token */
static __always_inline unsigned read_seqbegin(const seqlock_t *sl)
{
- unsigned ret = sl->sequence;
+ unsigned ret;
+
+repeat:
+ ret = sl->sequence;
smp_rmb();
+ if (unlikely(ret & 1)) {
+ cpu_relax();
+ goto repeat;
+ }
+
return ret;
}
-/* Test if reader processed invalid data.
- * If initial values is odd,
- * then writer had already started when section was entered
- * If sequence value changed
- * then writer changed data while in section
- *
- * Using xor saves one conditional branch.
+/*
+ * Test if reader processed invalid data.
+ *
+ * If sequence value changed then writer changed data while in section.
*/
-static __always_inline int read_seqretry(const seqlock_t *sl, unsigned iv)
+static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start)
{
smp_rmb();
- return (iv & 1) | (sl->sequence ^ iv);
+
+ return (sl->sequence != start);
}
@@ -122,20 +128,26 @@ typedef struct seqcount {
/* Start of read using pointer to a sequence counter only. */
static inline unsigned read_seqcount_begin(const seqcount_t *s)
{
- unsigned ret = s->sequence;
+ unsigned ret;
+
+repeat:
+ ret = s->sequence;
smp_rmb();
+ if (unlikely(ret & 1)) {
+ cpu_relax();
+ goto repeat;
+ }
return ret;
}
-/* Test if reader processed invalid data.
- * Equivalent to: iv is odd or sequence number has changed.
- * (iv & 1) || (*s != iv)
- * Using xor saves one conditional branch.
+/*
+ * Test if reader processed invalid data because sequence number has changed.
*/
-static inline int read_seqcount_retry(const seqcount_t *s, unsigned iv)
+static inline int read_seqcount_retry(const seqcount_t *s, unsigned start)
{
smp_rmb();
- return (iv & 1) | (s->sequence ^ iv);
+
+ return s->sequence != start;
}
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 00b65c0a82ca..3d37c94abbc8 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -46,6 +46,7 @@ enum {
PLAT8250_DEV_HUB6,
PLAT8250_DEV_MCA,
PLAT8250_DEV_AU1X00,
+ PLAT8250_DEV_SM501,
};
/*
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 9f3825014674..95674d97dabd 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -211,5 +211,6 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_TOUCHWIN 0x33
#define SERIO_TAOSEVM 0x34
#define SERIO_FUJITSU 0x35
+#define SERIO_ZHENHUA 0x36
#endif
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 8d5fb36ea047..f2d12d5a21b8 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -34,8 +34,7 @@ struct shmem_sb_info {
uid_t uid; /* Mount uid for root directory */
gid_t gid; /* Mount gid for root directory */
mode_t mode; /* Mount mode for root directory */
- int policy; /* Default NUMA memory alloc policy */
- nodemask_t policy_nodes; /* nodemask for preferred and bind */
+ struct mempolicy *mpol; /* default memory policy for mappings */
};
static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 79d59c937fac..71e43a12ebbb 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -29,6 +29,7 @@ enum stat_item {
DEACTIVATE_TO_HEAD, /* Cpu slab was moved to the head of partials */
DEACTIVATE_TO_TAIL, /* Cpu slab was moved to the tail of partials */
DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */
+ ORDER_FALLBACK, /* Number of times fallback was necessary */
NR_SLUB_STAT_ITEMS };
struct kmem_cache_cpu {
@@ -48,11 +49,21 @@ struct kmem_cache_node {
struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
atomic_long_t nr_slabs;
+ atomic_long_t total_objects;
struct list_head full;
#endif
};
/*
+ * Word size structure that can be atomically updated or read and that
+ * contains both the order and the number of objects that a slab of the
+ * given order would contain.
+ */
+struct kmem_cache_order_objects {
+ unsigned long x;
+};
+
+/*
* Slab cache management.
*/
struct kmem_cache {
@@ -61,7 +72,7 @@ struct kmem_cache {
int size; /* The size of an object including meta data */
int objsize; /* The size of an object without meta data */
int offset; /* Free pointer offset. */
- int order; /* Current preferred allocation order */
+ struct kmem_cache_order_objects oo;
/*
* Avoid an extra cache line for UP, SMP and for the node local to
@@ -70,7 +81,8 @@ struct kmem_cache {
struct kmem_cache_node local_node;
/* Allocation and freeing of slabs */
- int objects; /* Number of objects in slab */
+ struct kmem_cache_order_objects max;
+ struct kmem_cache_order_objects min;
gfp_t allocflags; /* gfp flags to use on each alloc */
int refcount; /* Refcount for slab cache destroy */
void (*ctor)(struct kmem_cache *, void *);
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index 334d31411629..daf744017a31 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -14,7 +14,8 @@ enum ads7846_filter {
struct ads7846_platform_data {
u16 model; /* 7843, 7845, 7846. */
u16 vref_delay_usecs; /* 0 for external vref; etc */
- int keep_vref_on:1; /* set to keep vref on for differential
+ u16 vref_mv; /* external vref value, milliVolts */
+ bool keep_vref_on; /* set to keep vref on for differential
* measurements as well */
/* Settling time of the analog signals; a function of Vcc and the
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 1d7d4c5797ee..a6977423baf7 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -12,11 +12,22 @@
#include <asm/errno.h>
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
+extern void pm_set_vt_switch(int);
extern int pm_prepare_console(void);
extern void pm_restore_console(void);
#else
-static inline int pm_prepare_console(void) { return 0; }
-static inline void pm_restore_console(void) {}
+static inline void pm_set_vt_switch(int do_switch)
+{
+}
+
+static inline int pm_prepare_console(void)
+{
+ return 0;
+}
+
+static inline void pm_restore_console(void)
+{
+}
#endif
typedef int __bitwise suspend_state_t;
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 878459ae0454..0b3377650c85 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -177,11 +177,11 @@ extern void activate_page(struct page *);
extern void mark_page_accessed(struct page *);
extern void lru_add_drain(void);
extern int lru_add_drain_all(void);
-extern int rotate_reclaimable_page(struct page *page);
+extern void rotate_reclaimable_page(struct page *page);
extern void swap_setup(void);
/* linux/mm/vmscan.c */
-extern unsigned long try_to_free_pages(struct zone **zones, int order,
+extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
gfp_t gfp_mask);
extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
gfp_t gfp_mask);
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 5562fbf72095..45f6bc82d317 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -13,10 +13,6 @@
#define _SYNCLINK_H_
#define SYNCLINK_H_VERSION 3.6
-#define BOOLEAN int
-#define TRUE 1
-#define FALSE 0
-
#define BIT0 0x0001
#define BIT1 0x0002
#define BIT2 0x0004
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 03378e3515b3..add3c5a40827 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -32,7 +32,7 @@ struct attribute {
struct attribute_group {
const char *name;
- int (*is_visible)(struct kobject *,
+ mode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
};
@@ -105,6 +105,8 @@ void sysfs_remove_link(struct kobject *kobj, const char *name);
int __must_check sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);
+int sysfs_update_group(struct kobject *kobj,
+ const struct attribute_group *grp);
void sysfs_remove_group(struct kobject *kobj,
const struct attribute_group *grp);
int sysfs_add_file_to_group(struct kobject *kobj,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 90c1c191ea69..06d3e6eb9ca8 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -41,6 +41,7 @@ struct thermal_zone_device_ops {
int (*set_mode) (struct thermal_zone_device *, const char *);
int (*get_trip_type) (struct thermal_zone_device *, int, char *);
int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+ int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
};
struct thermal_cooling_device_ops {
@@ -65,6 +66,23 @@ struct thermal_cooling_device {
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* thermal zone devices with the same type share one hwmon device */
+struct thermal_hwmon_device {
+ char type[THERMAL_NAME_LENGTH];
+ struct device *device;
+ int count;
+ struct list_head tz_list;
+ struct list_head node;
+};
+
+struct thermal_hwmon_attr {
+ struct device_attribute attr;
+ char name[16];
+};
+#endif
+
struct thermal_zone_device {
int id;
char type[THERMAL_NAME_LENGTH];
@@ -76,6 +94,13 @@ struct thermal_zone_device {
struct idr idr;
struct mutex lock; /* protect cooling devices list */
struct list_head node;
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+ struct list_head hwmon_node;
+ struct thermal_hwmon_device *hwmon;
+ struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
+ struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
+#endif
};
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
@@ -88,24 +113,10 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
-
-#ifdef CONFIG_THERMAL
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
struct
thermal_cooling_device_ops
*);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
-#else
-static inline struct thermal_cooling_device
-*thermal_cooling_device_register(char *c, void *v,
- struct thermal_cooling_device_ops *t)
-{
- return NULL;
-}
-static inline
- void thermal_cooling_device_unregister(struct thermal_cooling_device *t)
-{
-};
-#endif
#endif /* __THERMAL_H__ */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 583e0481dfa0..c08689ea9b4b 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -23,6 +23,7 @@
struct usb_device;
struct usb_driver;
+struct wusb_dev;
/*-------------------------------------------------------------------------*/
@@ -341,103 +342,146 @@ struct usb_bus {
struct usb_tt;
-/*
+/**
* struct usb_device - kernel's representation of a USB device
- *
- * FIXME: Write the kerneldoc!
- *
+ * @devnum: device number; address on a USB bus
+ * @devpath: device ID string for use in messages (e.g., /port/...)
+ * @state: device state: configured, not attached, etc.
+ * @speed: device speed: high/full/low (or error)
+ * @tt: Transaction Translator info; used with low/full speed dev, highspeed hub
+ * @ttport: device port on that tt hub
+ * @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints
+ * @parent: our hub, unless we're the root
+ * @bus: bus we're part of
+ * @ep0: endpoint 0 data (default control pipe)
+ * @dev: generic device interface
+ * @descriptor: USB device descriptor
+ * @config: all of the device's configs
+ * @actconfig: the active configuration
+ * @ep_in: array of IN endpoints
+ * @ep_out: array of OUT endpoints
+ * @rawdescriptors: raw descriptors for each config
+ * @bus_mA: Current available from the bus
+ * @portnum: parent port number (origin 1)
+ * @level: number of USB hub ancestors
+ * @can_submit: URBs may be submitted
+ * @discon_suspended: disconnected while suspended
+ * @persist_enabled: USB_PERSIST enabled for this device
+ * @have_langid: whether string_langid is valid
+ * @authorized: policy has said we can use it;
+ * (user space) policy determines if we authorize this device to be
+ * used or not. By default, wired USB devices are authorized.
+ * WUSB devices are not, until we authorize them from user space.
+ * FIXME -- complete doc
+ * @authenticated: Crypto authentication passed
+ * @wusb: device is Wireless USB
+ * @string_langid: language ID for strings
+ * @product: iProduct string, if present (static)
+ * @manufacturer: iManufacturer string, if present (static)
+ * @serial: iSerialNumber string, if present (static)
+ * @filelist: usbfs files that are open to this device
+ * @usb_classdev: USB class device that was created for usbfs device
+ * access from userspace
+ * @usbfs_dentry: usbfs dentry entry for the device
+ * @maxchild: number of ports if hub
+ * @children: child devices - USB devices that are attached to this hub
+ * @pm_usage_cnt: usage counter for autosuspend
+ * @quirks: quirks of the whole device
+ * @urbnum: number of URBs submitted for the whole device
+ * @active_duration: total time device is not suspended
+ * @autosuspend: for delayed autosuspends
+ * @pm_mutex: protects PM operations
+ * @last_busy: time of last use
+ * @autosuspend_delay: in jiffies
+ * @connect_time: time device was first connected
+ * @auto_pm: autosuspend/resume in progress
+ * @do_remote_wakeup: remote wakeup should be enabled
+ * @reset_resume: needs reset instead of resume
+ * @autosuspend_disabled: autosuspend disabled by the user
+ * @autoresume_disabled: autoresume disabled by the user
+ * @skip_sys_resume: skip the next system resume
+ *
+ * Notes:
* Usbcore drivers should not set usbdev->state directly. Instead use
* usb_set_device_state().
- *
- * @authorized: (user space) policy determines if we authorize this
- * device to be used or not. By default, wired USB
- * devices are authorized. WUSB devices are not, until we
- * authorize them from user space. FIXME -- complete doc
*/
struct usb_device {
- int devnum; /* Address on USB bus */
- char devpath [16]; /* Use in messages: /port/port/... */
- enum usb_device_state state; /* configured, not attached, etc */
- enum usb_device_speed speed; /* high/full/low (or error) */
+ int devnum;
+ char devpath [16];
+ enum usb_device_state state;
+ enum usb_device_speed speed;
- struct usb_tt *tt; /* low/full speed dev, highspeed hub */
- int ttport; /* device port on that tt hub */
+ struct usb_tt *tt;
+ int ttport;
- unsigned int toggle[2]; /* one bit for each endpoint
- * ([0] = IN, [1] = OUT) */
+ unsigned int toggle[2];
- struct usb_device *parent; /* our hub, unless we're the root */
- struct usb_bus *bus; /* Bus we're part of */
+ struct usb_device *parent;
+ struct usb_bus *bus;
struct usb_host_endpoint ep0;
- struct device dev; /* Generic device interface */
+ struct device dev;
- struct usb_device_descriptor descriptor;/* Descriptor */
- struct usb_host_config *config; /* All of the configs */
+ struct usb_device_descriptor descriptor;
+ struct usb_host_config *config;
- struct usb_host_config *actconfig;/* the active configuration */
+ struct usb_host_config *actconfig;
struct usb_host_endpoint *ep_in[16];
struct usb_host_endpoint *ep_out[16];
- char **rawdescriptors; /* Raw descriptors for each config */
+ char **rawdescriptors;
- unsigned short bus_mA; /* Current available from the bus */
- u8 portnum; /* Parent port number (origin 1) */
- u8 level; /* Number of USB hub ancestors */
+ unsigned short bus_mA;
+ u8 portnum;
+ u8 level;
- unsigned can_submit:1; /* URBs may be submitted */
- unsigned discon_suspended:1; /* Disconnected while suspended */
- unsigned have_langid:1; /* whether string_langid is valid */
- unsigned authorized:1; /* Policy has said we can use it */
- unsigned wusb:1; /* Device is Wireless USB */
- int string_langid; /* language ID for strings */
+ unsigned can_submit:1;
+ unsigned discon_suspended:1;
+ unsigned persist_enabled:1;
+ unsigned have_langid:1;
+ unsigned authorized:1;
+ unsigned authenticated:1;
+ unsigned wusb:1;
+ int string_langid;
/* static strings from the device */
- char *product; /* iProduct string, if present */
- char *manufacturer; /* iManufacturer string, if present */
- char *serial; /* iSerialNumber string, if present */
+ char *product;
+ char *manufacturer;
+ char *serial;
struct list_head filelist;
#ifdef CONFIG_USB_DEVICE_CLASS
struct device *usb_classdev;
#endif
#ifdef CONFIG_USB_DEVICEFS
- struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
+ struct dentry *usbfs_dentry;
#endif
- /*
- * Child devices - these can be either new devices
- * (if this is a hub device), or different instances
- * of this same device.
- *
- * Each instance needs its own set of data structures.
- */
- int maxchild; /* Number of ports if hub */
+ int maxchild;
struct usb_device *children[USB_MAXCHILDREN];
- int pm_usage_cnt; /* usage counter for autosuspend */
- u32 quirks; /* quirks of the whole device */
- atomic_t urbnum; /* number of URBs submitted for
- the whole device */
+ int pm_usage_cnt;
+ u32 quirks;
+ atomic_t urbnum;
- unsigned long active_duration; /* total time device is not suspended */
+ unsigned long active_duration;
#ifdef CONFIG_PM
- struct delayed_work autosuspend; /* for delayed autosuspends */
- struct mutex pm_mutex; /* protects PM operations */
-
- unsigned long last_busy; /* time of last use */
- int autosuspend_delay; /* in jiffies */
- unsigned long connect_time; /* time device was first connected */
-
- unsigned auto_pm:1; /* autosuspend/resume in progress */
- unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */
- unsigned reset_resume:1; /* needs reset instead of resume */
- unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */
- unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
- unsigned autoresume_disabled:1; /* disabled by the user */
- unsigned skip_sys_resume:1; /* skip the next system resume */
+ struct delayed_work autosuspend;
+ struct mutex pm_mutex;
+
+ unsigned long last_busy;
+ int autosuspend_delay;
+ unsigned long connect_time;
+
+ unsigned auto_pm:1;
+ unsigned do_remote_wakeup:1;
+ unsigned reset_resume:1;
+ unsigned autosuspend_disabled:1;
+ unsigned autoresume_disabled:1;
+ unsigned skip_sys_resume:1;
#endif
+ struct wusb_dev *wusb_dev;
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -898,10 +942,11 @@ struct usbdrv_wrap {
* and should normally be the same as the module name.
* @probe: Called to see if the driver is willing to manage a particular
* interface on a device. If it is, probe returns zero and uses
- * dev_set_drvdata() to associate driver-specific data with the
+ * usb_set_intfdata() to associate driver-specific data with the
* interface. It may also use usb_set_interface() to specify the
* appropriate altsetting. If unwilling to manage the interface,
- * return a negative errno value.
+ * return -ENODEV, if genuine IO errors occured, an appropriate
+ * negative errno value.
* @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected or the
* driver module is being unloaded.
@@ -916,10 +961,7 @@ struct usbdrv_wrap {
* @pre_reset: Called by usb_reset_composite_device() when the device
* is about to be reset.
* @post_reset: Called by usb_reset_composite_device() after the device
- * has been reset, or in lieu of @resume following a reset-resume
- * (i.e., the device is reset instead of being resumed, as might
- * happen if power was lost). The second argument tells which is
- * the reason.
+ * has been reset
* @id_table: USB drivers use ID table to support hotplugging.
* Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
* or your driver's probe function will never get called.
@@ -1411,6 +1453,7 @@ extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
extern int usb_unlink_urb(struct urb *urb);
extern void usb_kill_urb(struct urb *urb);
extern void usb_kill_anchored_urbs(struct usb_anchor *anchor);
+extern void usb_unlink_anchored_urbs(struct usb_anchor *anchor);
extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor);
extern void usb_unanchor_urb(struct urb *urb);
extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
@@ -1661,13 +1704,12 @@ extern void usb_unregister_notify(struct notifier_block *nb);
#define dbg(format, arg...) do {} while (0)
#endif
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
- __FILE__ , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , \
- __FILE__ , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , \
- __FILE__ , ## arg)
-
+#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
#endif /* __KERNEL__ */
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index 2dfeef16b221..8cb025fef634 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -50,4 +50,4 @@ struct usb_ac_header_descriptor_##n { \
__u8 baInterfaceNr[n]; \
} __attribute__ ((packed))
-#endif
+#endif /* __LINUX_USB_AUDIO_H */
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 94ee4ecf0564..71e52f2f6a38 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -6,6 +6,9 @@
* firmware based USB peripherals.
*/
+#ifndef __LINUX_USB_CDC_H
+#define __LINUX_USB_CDC_H
+
#define USB_CDC_SUBCLASS_ACM 0x02
#define USB_CDC_SUBCLASS_ETHERNET 0x06
#define USB_CDC_SUBCLASS_WHCM 0x08
@@ -221,3 +224,4 @@ struct usb_cdc_notification {
__le16 wLength;
} __attribute__ ((packed));
+#endif /* __LINUX_USB_CDC_H */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 6169438ec5a2..7e0d3084f76c 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -66,8 +66,8 @@
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
/* From Wireless USB 1.0 */
-#define USB_RECIP_PORT 0x04
-#define USB_RECIP_RPIPE 0x05
+#define USB_RECIP_PORT 0x04
+#define USB_RECIP_RPIPE 0x05
/*
* Standard requests, for the bRequest field of a SETUP packet.
@@ -102,10 +102,16 @@
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
+/* The Link Power Mangement (LPM) ECN defines USB_REQ_TEST_AND_SET command,
+ * used by hubs to put ports into a new L1 suspend state, except that it
+ * forgot to define its number ...
+ */
+
/*
* USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
* are read as a bit array returned by USB_REQ_GET_STATUS. (So there
- * are at most sixteen features of each type.)
+ * are at most sixteen features of each type.) Hubs may also support a
+ * new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend.
*/
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
@@ -180,6 +186,7 @@ struct usb_ctrlrequest {
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
#define USB_DT_WIRE_ADAPTER 0x21
#define USB_DT_RPIPE 0x22
+#define USB_DT_CS_RADIO_CONTROL 0x23
/* Conventional codes for class-specific descriptors. The convention is
* defined in the USB "Common Class" Spec (3.11). Individual class specs
@@ -574,7 +581,9 @@ enum usb_device_state {
/* NOTE: there are actually four different SUSPENDED
* states, returning to POWERED, DEFAULT, ADDRESS, or
* CONFIGURED respectively when SOF tokens flow again.
+ * At this level there's no difference between L1 and L2
+ * suspend states. (L2 being original USB 1.1 suspend.)
*/
};
-#endif /* __LINUX_USB_CH9_H */
+#endif /* __LINUX_USB_CH9_H */
diff --git a/include/linux/usb/g_printer.h b/include/linux/usb/g_printer.h
index 0c5ea1e3eb98..6178fde50f74 100644
--- a/include/linux/usb/g_printer.h
+++ b/include/linux/usb/g_printer.h
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef __LINUX_USB_G_PRINTER_H
+#define __LINUX_USB_G_PRINTER_H
#define PRINTER_NOT_ERROR 0x08
#define PRINTER_SELECTED 0x10
@@ -29,3 +31,5 @@
*/
#define GADGET_GET_PRINTER_STATUS _IOR('g', 0x21, unsigned char)
#define GADGET_SET_PRINTER_STATUS _IOWR('g', 0x22, unsigned char)
+
+#endif /* __LINUX_USB_G_PRINTER_H */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index f3295296b435..d8128f7102c9 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -846,4 +846,4 @@ extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
extern void usb_ep_autoconfig_reset(struct usb_gadget *) __devinit;
-#endif /* __LINUX_USB_GADGET_H */
+#endif /* __LINUX_USB_GADGET_H */
diff --git a/include/linux/usb/gadgetfs.h b/include/linux/usb/gadgetfs.h
index c291ab1af747..ea45f265ec05 100644
--- a/include/linux/usb/gadgetfs.h
+++ b/include/linux/usb/gadgetfs.h
@@ -1,11 +1,3 @@
-#ifndef __LINUX_USB_GADGETFS_H
-#define __LINUX_USB_GADGETFS_H
-
-#include <asm/types.h>
-#include <asm/ioctl.h>
-
-#include <linux/usb/ch9.h>
-
/*
* Filesystem based user-mode API to USB Gadget controller hardware
*
@@ -23,6 +15,14 @@
* then performing data transfers by reading or writing.
*/
+#ifndef __LINUX_USB_GADGETFS_H
+#define __LINUX_USB_GADGETFS_H
+
+#include <asm/types.h>
+#include <asm/ioctl.h>
+
+#include <linux/usb/ch9.h>
+
/*
* Events are delivered on the ep0 file descriptor, when the user mode driver
* reads from this file descriptor after writing the descriptors. Don't
diff --git a/include/linux/usb/input.h b/include/linux/usb/input.h
index 716e0cc16043..0e010b220e85 100644
--- a/include/linux/usb/input.h
+++ b/include/linux/usb/input.h
@@ -1,6 +1,3 @@
-#ifndef __USB_INPUT_H
-#define __USB_INPUT_H
-
/*
* Copyright (C) 2005 Dmitry Torokhov
*
@@ -9,6 +6,9 @@
* the Free Software Foundation.
*/
+#ifndef __LINUX_USB_INPUT_H
+#define __LINUX_USB_INPUT_H
+
#include <linux/usb.h>
#include <linux/input.h>
#include <asm/byteorder.h>
@@ -22,4 +22,4 @@ usb_to_input_id(const struct usb_device *dev, struct input_id *id)
id->version = le16_to_cpu(dev->descriptor.bcdDevice);
}
-#endif
+#endif /* __LINUX_USB_INPUT_H */
diff --git a/include/linux/usb/iowarrior.h b/include/linux/usb/iowarrior.h
index de6f380e17a2..4fd6513d564c 100644
--- a/include/linux/usb/iowarrior.h
+++ b/include/linux/usb/iowarrior.h
@@ -1,5 +1,5 @@
-#ifndef _IOWARRIOR_H_
-#define _IOWARRIOR_H_
+#ifndef __LINUX_USB_IOWARRIOR_H
+#define __LINUX_USB_IOWARRIOR_H
#define CODEMERCS_MAGIC_NUMBER 0xC0 /* like COde Mercenaries */
@@ -39,4 +39,4 @@ struct iowarrior_info {
*/
#define IOW_GETINFO _IOR(CODEMERCS_MAGIC_NUMBER, 3, struct iowarrior_info)
-#endif /* _IOWARRIOR_H_ */
+#endif /* __LINUX_USB_IOWARRIOR_H */
diff --git a/include/linux/usb/isp116x.h b/include/linux/usb/isp116x.h
index 67d2826f34fe..96ca114e88d0 100644
--- a/include/linux/usb/isp116x.h
+++ b/include/linux/usb/isp116x.h
@@ -1,9 +1,11 @@
-
/*
* Board initialization code should put one of these into dev->platform_data
* and place the isp116x onto platform_bus.
*/
+#ifndef __LINUX_USB_ISP116X_H
+#define __LINUX_USB_ISP116X_H
+
struct isp116x_platform_data {
/* Enable internal resistors on downstream ports */
unsigned sel15Kres:1;
@@ -27,3 +29,5 @@ struct isp116x_platform_data {
*/
void (*delay) (struct device *dev, int delay);
};
+
+#endif /* __LINUX_USB_ISP116X_H */
diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h
index 80624c562921..1d1040865661 100644
--- a/include/linux/usb/midi.h
+++ b/include/linux/usb/midi.h
@@ -109,4 +109,4 @@ struct usb_ms_endpoint_descriptor_##n { \
__u8 baAssocJackID[n]; \
} __attribute__ ((packed))
-#endif
+#endif /* __LINUX_USB_MIDI_H */
diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h
index ec897cb844ab..96ca549a778d 100644
--- a/include/linux/usb/net2280.h
+++ b/include/linux/usb/net2280.h
@@ -1,11 +1,7 @@
/*
* NetChip 2280 high/full speed USB device controller.
* Unlike many such controllers, this one talks PCI.
- */
-#ifndef __LINUX_USB_NET2280_H
-#define __LINUX_USB_NET2280_H
-
-/*
+ *
* Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
* Copyright (C) 2003 David Brownell
*
@@ -24,6 +20,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef __LINUX_USB_NET2280_H
+#define __LINUX_USB_NET2280_H
+
/*-------------------------------------------------------------------------*/
/* NET2280 MEMORY MAPPED REGISTERS
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index e007074ebe41..1db25d152ad8 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -1,11 +1,13 @@
/* USB OTG (On The Go) defines */
-
/*
+ *
* These APIs may be used between USB controllers. USB device drivers
* (for either host or peripheral roles) don't use these calls; they
* continue to use just usb_device and usb_gadget.
*/
+#ifndef __LINUX_USB_OTG_H
+#define __LINUX_USB_OTG_H
/* OTG defines lots of enumeration states before device reset */
enum usb_otg_state {
@@ -129,3 +131,5 @@ otg_start_srp(struct otg_transceiver *otg)
/* for OTG controller drivers (and maybe other stuff) */
extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
+
+#endif /* __LINUX_USB_OTG_H */
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 1f999ec8d08c..7f6c603db654 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -4,6 +4,9 @@
* belong here.
*/
+#ifndef __LINUX_USB_QUIRKS_H
+#define __LINUX_USB_QUIRKS_H
+
/* string descriptors must not be fetched using a 255-byte read */
#define USB_QUIRK_STRING_FETCH_255 0x00000001
@@ -12,3 +15,5 @@
/* device can't handle Set-Interface requests */
#define USB_QUIRK_NO_SET_INTF 0x00000004
+
+#endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h
index edc1d4a0e272..29d6458ecb8d 100644
--- a/include/linux/usb/rndis_host.h
+++ b/include/linux/usb/rndis_host.h
@@ -17,10 +17,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
-#ifndef __RNDIS_HOST_H
-#define __RNDIS_HOST_H
-
+#ifndef __LINUX_USB_RNDIS_HOST_H
+#define __LINUX_USB_RNDIS_HOST_H
/*
* CONTROL uses CDC "encapsulated commands" with funky notifications.
@@ -270,5 +268,4 @@ extern int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
extern struct sk_buff *
rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags);
-#endif /* __RNDIS_HOST_H */
-
+#endif /* __LINUX_USB_RNDIS_HOST_H */
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 21b4a1c6f585..8f891cbaf9ab 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -10,7 +10,6 @@
*
*/
-
#ifndef __LINUX_USB_SERIAL_H
#define __LINUX_USB_SERIAL_H
@@ -146,8 +145,6 @@ struct usb_serial {
};
#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
-#define NUM_DONT_CARE 99
-
/* get and set the serial private data pointer helper functions */
static inline void *usb_get_serial_data(struct usb_serial *serial)
{
@@ -165,18 +162,6 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
* used in the syslog messages when a device is inserted or removed.
* @id_table: pointer to a list of usb_device_id structures that define all
* of the devices this structure can support.
- * @num_interrupt_in: If a device doesn't have this many interrupt-in
- * endpoints, it won't be sent to the driver's attach() method.
- * (But it might still be sent to the probe() method.)
- * @num_interrupt_out: If a device doesn't have this many interrupt-out
- * endpoints, it won't be sent to the driver's attach() method.
- * (But it might still be sent to the probe() method.)
- * @num_bulk_in: If a device doesn't have this many bulk-in
- * endpoints, it won't be sent to the driver's attach() method.
- * (But it might still be sent to the probe() method.)
- * @num_bulk_out: If a device doesn't have this many bulk-out
- * endpoints, it won't be sent to the driver's attach() method.
- * (But it might still be sent to the probe() method.)
* @num_ports: the number of different ports this device will have.
* @calc_num_ports: pointer to a function to determine how many ports this
* device has dynamically. It will be called after the probe()
@@ -212,10 +197,6 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
struct usb_serial_driver {
const char *description;
const struct usb_device_id *id_table;
- char num_interrupt_in;
- char num_interrupt_out;
- char num_bulk_in;
- char num_bulk_out;
char num_ports;
struct list_head driver_list;
@@ -340,5 +321,5 @@ static inline void usb_serial_debug_data(int debug,
-#endif /* ifdef __LINUX_USB_SERIAL_H */
+#endif /* __LINUX_USB_SERIAL_H */
diff --git a/include/linux/usb/sl811.h b/include/linux/usb/sl811.h
index 877373da410d..3afe4d16fcef 100644
--- a/include/linux/usb/sl811.h
+++ b/include/linux/usb/sl811.h
@@ -1,9 +1,11 @@
-
/*
* board initialization should put one of these into dev->platform_data
* and place the sl811hs onto platform_bus named "sl811-hcd".
*/
+#ifndef __LINUX_USB_SL811_H
+#define __LINUX_USB_SL811_H
+
struct sl811_platform_data {
unsigned can_wakeup:1;
@@ -24,3 +26,4 @@ struct sl811_platform_data {
/* void (*clock_enable)(struct device *dev, int is_on); */
};
+#endif /* __LINUX_USB_SL811_H */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index e0501da3dd11..ba09fe88adda 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -19,10 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
-#ifndef __USBNET_H
-#define __USBNET_H
-
+#ifndef __LINUX_USB_USBNET_H
+#define __LINUX_USB_USBNET_H
/* interface from usbnet core to each USB networking link we handle */
struct usbnet {
@@ -211,4 +209,4 @@ extern int usbnet_nway_reset(struct net_device *net);
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
-#endif /* __USBNET_H */
+#endif /* __LINUX_USB_USBNET_H */
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index 0a40dfa44c9f..d9a3bbe38e6b 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -85,6 +85,7 @@ enum { US_DO_ALL_FLAGS };
#define US_SC_LOCKABLE 0x07 /* Password-protected */
#define US_SC_ISD200 0xf0 /* ISD200 ATA */
+#define US_SC_CYP_ATACB 0xf1 /* Cypress ATACB */
#define US_SC_DEVICE 0xff /* Use device's value */
/* Protocols */
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 17cb108b7db0..3118ede2c67b 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -77,8 +77,11 @@ struct usbdevfs_connectinfo {
unsigned char slow;
};
-#define USBDEVFS_URB_SHORT_NOT_OK 1
-#define USBDEVFS_URB_ISO_ASAP 2
+#define USBDEVFS_URB_SHORT_NOT_OK 0x01
+#define USBDEVFS_URB_ISO_ASAP 0x02
+#define USBDEVFS_URB_NO_FSBR 0x20
+#define USBDEVFS_URB_ZERO_PACKET 0x40
+#define USBDEVFS_URB_NO_INTERRUPT 0x80
#define USBDEVFS_URB_TYPE_ISO 0
#define USBDEVFS_URB_TYPE_INTERRUPT 1
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index ce8e7da05807..364789aae9f3 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -31,6 +31,7 @@ struct vm_struct {
struct page **pages;
unsigned int nr_pages;
unsigned long phys_addr;
+ void *caller;
};
/*
@@ -66,6 +67,8 @@ static inline size_t get_vm_area_size(const struct vm_struct *area)
}
extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
+extern struct vm_struct *get_vm_area_caller(unsigned long size,
+ unsigned long flags, void *caller);
extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end);
extern struct vm_struct *get_vm_area_node(unsigned long size,
@@ -87,4 +90,6 @@ extern void free_vm_area(struct vm_struct *area);
extern rwlock_t vmlist_lock;
extern struct vm_struct *vmlist;
+extern const struct seq_operations vmalloc_op;
+
#endif /* _LINUX_VMALLOC_H */
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 9f1b4b46151e..e83b69346d23 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -25,6 +25,7 @@
#define HIGHMEM_ZONE(xx)
#endif
+
#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx) , xx##_MOVABLE
enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
@@ -37,6 +38,9 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
FOR_ALL_ZONES(PGSCAN_DIRECT),
PGINODESTEAL, SLABS_SCANNED, KSWAPD_STEAL, KSWAPD_INODESTEAL,
PAGEOUTRUN, ALLOCSTALL, PGROTATED,
+#ifdef CONFIG_HUGETLB_PAGE
+ HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL,
+#endif
NR_VM_EVENT_ITEMS
};
@@ -174,7 +178,7 @@ static inline unsigned long node_page_state(int node,
zone_page_state(&zones[ZONE_MOVABLE], item);
}
-extern void zone_statistics(struct zonelist *, struct zone *);
+extern void zone_statistics(struct zone *, struct zone *);
#else
diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h
new file mode 100644
index 000000000000..4d13732e9cf0
--- /dev/null
+++ b/include/linux/wm97xx.h
@@ -0,0 +1,314 @@
+
+/*
+ * Register bits and API for Wolfson WM97xx series of codecs
+ */
+
+#ifndef _LINUX_WM97XX_H
+#define _LINUX_WM97XX_H
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/input.h> /* Input device layer */
+#include <linux/platform_device.h>
+
+/*
+ * WM97xx AC97 Touchscreen registers
+ */
+#define AC97_WM97XX_DIGITISER1 0x76
+#define AC97_WM97XX_DIGITISER2 0x78
+#define AC97_WM97XX_DIGITISER_RD 0x7a
+#define AC97_WM9713_DIG1 0x74
+#define AC97_WM9713_DIG2 AC97_WM97XX_DIGITISER1
+#define AC97_WM9713_DIG3 AC97_WM97XX_DIGITISER2
+
+/*
+ * WM97xx register bits
+ */
+#define WM97XX_POLL 0x8000 /* initiate a polling measurement */
+#define WM97XX_ADCSEL_X 0x1000 /* x coord measurement */
+#define WM97XX_ADCSEL_Y 0x2000 /* y coord measurement */
+#define WM97XX_ADCSEL_PRES 0x3000 /* pressure measurement */
+#define WM97XX_ADCSEL_MASK 0x7000
+#define WM97XX_COO 0x0800 /* enable coordinate mode */
+#define WM97XX_CTC 0x0400 /* enable continuous mode */
+#define WM97XX_CM_RATE_93 0x0000 /* 93.75Hz continuous rate */
+#define WM97XX_CM_RATE_187 0x0100 /* 187.5Hz continuous rate */
+#define WM97XX_CM_RATE_375 0x0200 /* 375Hz continuous rate */
+#define WM97XX_CM_RATE_750 0x0300 /* 750Hz continuous rate */
+#define WM97XX_CM_RATE_8K 0x00f0 /* 8kHz continuous rate */
+#define WM97XX_CM_RATE_12K 0x01f0 /* 12kHz continuous rate */
+#define WM97XX_CM_RATE_24K 0x02f0 /* 24kHz continuous rate */
+#define WM97XX_CM_RATE_48K 0x03f0 /* 48kHz continuous rate */
+#define WM97XX_CM_RATE_MASK 0x03f0
+#define WM97XX_RATE(i) (((i & 3) << 8) | ((i & 4) ? 0xf0 : 0))
+#define WM97XX_DELAY(i) ((i << 4) & 0x00f0) /* sample delay times */
+#define WM97XX_DELAY_MASK 0x00f0
+#define WM97XX_SLEN 0x0008 /* slot read back enable */
+#define WM97XX_SLT(i) ((i - 5) & 0x7) /* panel slot (5-11) */
+#define WM97XX_SLT_MASK 0x0007
+#define WM97XX_PRP_DETW 0x4000 /* detect on, digitise off, wake */
+#define WM97XX_PRP_DET 0x8000 /* detect on, digitise off, no wake */
+#define WM97XX_PRP_DET_DIG 0xc000 /* setect on, digitise on */
+#define WM97XX_RPR 0x2000 /* wake up on pen down */
+#define WM97XX_PEN_DOWN 0x8000 /* pen is down */
+#define WM97XX_ADCSRC_MASK 0x7000 /* ADC source mask */
+
+#define WM97XX_AUX_ID1 0x8001
+#define WM97XX_AUX_ID2 0x8002
+#define WM97XX_AUX_ID3 0x8003
+#define WM97XX_AUX_ID4 0x8004
+
+
+/* WM9712 Bits */
+#define WM9712_45W 0x1000 /* set for 5-wire touchscreen */
+#define WM9712_PDEN 0x0800 /* measure only when pen down */
+#define WM9712_WAIT 0x0200 /* wait until adc is read before next sample */
+#define WM9712_PIL 0x0100 /* current used for pressure measurement. set 400uA else 200uA */
+#define WM9712_MASK_HI 0x0040 /* hi on mask pin (47) stops conversions */
+#define WM9712_MASK_EDGE 0x0080 /* rising/falling edge on pin delays sample */
+#define WM9712_MASK_SYNC 0x00c0 /* rising/falling edge on mask initiates sample */
+#define WM9712_RPU(i) (i&0x3f) /* internal pull up on pen detect (64k / rpu) */
+#define WM9712_PD(i) (0x1 << i) /* power management */
+
+/* WM9712 Registers */
+#define AC97_WM9712_POWER 0x24
+#define AC97_WM9712_REV 0x58
+
+/* WM9705 Bits */
+#define WM9705_PDEN 0x1000 /* measure only when pen is down */
+#define WM9705_PINV 0x0800 /* inverts sense of pen down output */
+#define WM9705_BSEN 0x0400 /* BUSY flag enable, pin47 is 1 when busy */
+#define WM9705_BINV 0x0200 /* invert BUSY (pin47) output */
+#define WM9705_WAIT 0x0100 /* wait until adc is read before next sample */
+#define WM9705_PIL 0x0080 /* current used for pressure measurement. set 400uA else 200uA */
+#define WM9705_PHIZ 0x0040 /* set PHONE and PCBEEP inputs to high impedance */
+#define WM9705_MASK_HI 0x0010 /* hi on mask stops conversions */
+#define WM9705_MASK_EDGE 0x0020 /* rising/falling edge on pin delays sample */
+#define WM9705_MASK_SYNC 0x0030 /* rising/falling edge on mask initiates sample */
+#define WM9705_PDD(i) (i & 0x000f) /* pen detect comparator threshold */
+
+
+/* WM9713 Bits */
+#define WM9713_PDPOL 0x0400 /* Pen down polarity */
+#define WM9713_POLL 0x0200 /* initiate a polling measurement */
+#define WM9713_CTC 0x0100 /* enable continuous mode */
+#define WM9713_ADCSEL_X 0x0002 /* X measurement */
+#define WM9713_ADCSEL_Y 0x0004 /* Y measurement */
+#define WM9713_ADCSEL_PRES 0x0008 /* Pressure measurement */
+#define WM9713_COO 0x0001 /* enable coordinate mode */
+#define WM9713_PDEN 0x0800 /* measure only when pen down */
+#define WM9713_ADCSEL_MASK 0x00fe /* ADC selection mask */
+#define WM9713_WAIT 0x0200 /* coordinate wait */
+
+/* AUX ADC ID's */
+#define TS_COMP1 0x0
+#define TS_COMP2 0x1
+#define TS_BMON 0x2
+#define TS_WIPER 0x3
+
+/* ID numbers */
+#define WM97XX_ID1 0x574d
+#define WM9712_ID2 0x4c12
+#define WM9705_ID2 0x4c05
+#define WM9713_ID2 0x4c13
+
+/* Codec GPIO's */
+#define WM97XX_MAX_GPIO 16
+#define WM97XX_GPIO_1 (1 << 1)
+#define WM97XX_GPIO_2 (1 << 2)
+#define WM97XX_GPIO_3 (1 << 3)
+#define WM97XX_GPIO_4 (1 << 4)
+#define WM97XX_GPIO_5 (1 << 5)
+#define WM97XX_GPIO_6 (1 << 6)
+#define WM97XX_GPIO_7 (1 << 7)
+#define WM97XX_GPIO_8 (1 << 8)
+#define WM97XX_GPIO_9 (1 << 9)
+#define WM97XX_GPIO_10 (1 << 10)
+#define WM97XX_GPIO_11 (1 << 11)
+#define WM97XX_GPIO_12 (1 << 12)
+#define WM97XX_GPIO_13 (1 << 13)
+#define WM97XX_GPIO_14 (1 << 14)
+#define WM97XX_GPIO_15 (1 << 15)
+
+
+#define AC97_LINK_FRAME 21 /* time in uS for AC97 link frame */
+
+
+/*---------------- Return codes from sample reading functions ---------------*/
+
+/* More data is available; call the sample gathering function again */
+#define RC_AGAIN 0x00000001
+/* The returned sample is valid */
+#define RC_VALID 0x00000002
+/* The pen is up (the first RC_VALID without RC_PENUP means pen is down) */
+#define RC_PENUP 0x00000004
+/* The pen is down (RC_VALID implies RC_PENDOWN, but sometimes it is helpful
+ to tell the handler that the pen is down but we don't know yet his coords,
+ so the handler should not sleep or wait for pendown irq) */
+#define RC_PENDOWN 0x00000008
+
+/*
+ * The wm97xx driver provides a private API for writing platform-specific
+ * drivers.
+ */
+
+/* The structure used to return arch specific sampled data into */
+struct wm97xx_data {
+ int x;
+ int y;
+ int p;
+};
+
+/*
+ * Codec GPIO status
+ */
+enum wm97xx_gpio_status {
+ WM97XX_GPIO_HIGH,
+ WM97XX_GPIO_LOW
+};
+
+/*
+ * Codec GPIO direction
+ */
+enum wm97xx_gpio_dir {
+ WM97XX_GPIO_IN,
+ WM97XX_GPIO_OUT
+};
+
+/*
+ * Codec GPIO polarity
+ */
+enum wm97xx_gpio_pol {
+ WM97XX_GPIO_POL_HIGH,
+ WM97XX_GPIO_POL_LOW
+};
+
+/*
+ * Codec GPIO sticky
+ */
+enum wm97xx_gpio_sticky {
+ WM97XX_GPIO_STICKY,
+ WM97XX_GPIO_NOTSTICKY
+};
+
+/*
+ * Codec GPIO wake
+ */
+enum wm97xx_gpio_wake {
+ WM97XX_GPIO_WAKE,
+ WM97XX_GPIO_NOWAKE
+};
+
+/*
+ * Digitiser ioctl commands
+ */
+#define WM97XX_DIG_START 0x1
+#define WM97XX_DIG_STOP 0x2
+#define WM97XX_PHY_INIT 0x3
+#define WM97XX_AUX_PREPARE 0x4
+#define WM97XX_DIG_RESTORE 0x5
+
+struct wm97xx;
+
+extern struct wm97xx_codec_drv wm9705_codec;
+extern struct wm97xx_codec_drv wm9712_codec;
+extern struct wm97xx_codec_drv wm9713_codec;
+
+/*
+ * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
+ */
+struct wm97xx_codec_drv {
+ u16 id;
+ char *name;
+
+ /* read 1 sample */
+ int (*poll_sample) (struct wm97xx *, int adcsel, int *sample);
+
+ /* read X,Y,[P] in poll */
+ int (*poll_touch) (struct wm97xx *, struct wm97xx_data *);
+
+ int (*acc_enable) (struct wm97xx *, int enable);
+ void (*phy_init) (struct wm97xx *);
+ void (*dig_enable) (struct wm97xx *, int enable);
+ void (*dig_restore) (struct wm97xx *);
+ void (*aux_prepare) (struct wm97xx *);
+};
+
+
+/* Machine specific and accelerated touch operations */
+struct wm97xx_mach_ops {
+
+ /* accelerated touch readback - coords are transmited on AC97 link */
+ int acc_enabled;
+ void (*acc_pen_up) (struct wm97xx *);
+ int (*acc_pen_down) (struct wm97xx *);
+ int (*acc_startup) (struct wm97xx *);
+ void (*acc_shutdown) (struct wm97xx *);
+
+ /* interrupt mask control - required for accelerated operation */
+ void (*irq_enable) (struct wm97xx *, int enable);
+
+ /* GPIO pin used for accelerated operation */
+ int irq_gpio;
+
+ /* pre and post sample - can be used to minimise any analog noise */
+ void (*pre_sample) (int); /* function to run before sampling */
+ void (*post_sample) (int); /* function to run after sampling */
+};
+
+struct wm97xx {
+ u16 dig[3], id, gpio[6], misc; /* Cached codec registers */
+ u16 dig_save[3]; /* saved during aux reading */
+ struct wm97xx_codec_drv *codec; /* attached codec driver*/
+ struct input_dev *input_dev; /* touchscreen input device */
+ struct snd_ac97 *ac97; /* ALSA codec access */
+ struct device *dev; /* ALSA device */
+ struct platform_device *battery_dev;
+ struct platform_device *touch_dev;
+ struct wm97xx_mach_ops *mach_ops;
+ struct mutex codec_mutex;
+ struct delayed_work ts_reader; /* Used to poll touchscreen */
+ unsigned long ts_reader_interval; /* Current interval for timer */
+ unsigned long ts_reader_min_interval; /* Minimum interval */
+ unsigned int pen_irq; /* Pen IRQ number in use */
+ struct workqueue_struct *ts_workq;
+ struct work_struct pen_event_work;
+ u16 acc_slot; /* AC97 slot used for acc touch data */
+ u16 acc_rate; /* acc touch data rate */
+ unsigned pen_is_down:1; /* Pen is down */
+ unsigned aux_waiting:1; /* aux measurement waiting */
+ unsigned pen_probably_down:1; /* used in polling mode */
+ u16 suspend_mode; /* PRP in suspend mode */
+};
+
+/*
+ * Codec GPIO access (not supported on WM9705)
+ * This can be used to set/get codec GPIO and Virtual GPIO status.
+ */
+enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio);
+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
+ enum wm97xx_gpio_status status);
+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio,
+ enum wm97xx_gpio_dir dir,
+ enum wm97xx_gpio_pol pol,
+ enum wm97xx_gpio_sticky sticky,
+ enum wm97xx_gpio_wake wake);
+
+void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode);
+
+/* codec AC97 IO access */
+int wm97xx_reg_read(struct wm97xx *wm, u16 reg);
+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val);
+
+/* aux adc readback */
+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel);
+
+/* machine ops */
+int wm97xx_register_mach_ops(struct wm97xx *, struct wm97xx_mach_ops *);
+void wm97xx_unregister_mach_ops(struct wm97xx *);
+
+#endif
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 0c82c80b277f..2ca6bae88721 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -97,10 +97,10 @@ struct xfrm_algo {
};
struct xfrm_algo_aead {
- char alg_name[64];
- int alg_key_len; /* in bits */
- int alg_icv_len; /* in bits */
- char alg_key[0];
+ char alg_name[64];
+ unsigned int alg_key_len; /* in bits */
+ unsigned int alg_icv_len; /* in bits */
+ char alg_key[0];
};
struct xfrm_stats {
diff --git a/include/mtd/Kbuild b/include/mtd/Kbuild
index 4d46b3bdebd8..8eb018f96002 100644
--- a/include/mtd/Kbuild
+++ b/include/mtd/Kbuild
@@ -3,5 +3,4 @@ header-y += jffs2-user.h
header-y += mtd-abi.h
header-y += mtd-user.h
header-y += nftl-user.h
-header-y += ubi-header.h
header-y += ubi-user.h
diff --git a/include/net/compat.h b/include/net/compat.h
index 406db242f73a..05fa5d0254ab 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -40,4 +40,7 @@ extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int);
+extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int,
+ int (*)(struct sock *, int, int, char __user *, int));
+
#endif /* NET_COMPAT_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index b8b19e2f57bb..f6a9fe0ef09c 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -181,7 +181,8 @@ struct scsi_device {
sdev_printk(prefix, (scmd)->device, fmt, ##a)
enum scsi_target_state {
- STARGET_RUNNING = 1,
+ STARGET_CREATED = 1,
+ STARGET_RUNNING,
STARGET_DEL,
};
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
index 336c20db87f8..ed64862c4e18 100644
--- a/include/video/atmel_lcdc.h
+++ b/include/video/atmel_lcdc.h
@@ -22,6 +22,15 @@
#ifndef __ATMEL_LCDC_H__
#define __ATMEL_LCDC_H__
+
+/* Way LCD wires are connected to the chip:
+ * Some Atmel chips use BGR color mode (instead of standard RGB)
+ * A swapped wiring onboard can bring to RGB mode.
+ */
+#define ATMEL_LCDC_WIRING_BGR 0
+#define ATMEL_LCDC_WIRING_RGB 1
+
+
/* LCD Controller info data structure, stored in device platform_data */
struct atmel_lcdfb_info {
spinlock_t lock;
@@ -39,8 +48,10 @@ struct atmel_lcdfb_info {
u8 bl_power;
#endif
bool lcdcon_is_backlight;
+ u8 saved_lcdcon;
u8 default_bpp;
+ u8 lcd_wiring_mode;
unsigned int default_lcdcon2;
unsigned int default_dmacon;
void (*atmel_lcdfb_power_control)(int on);
diff --git a/include/video/hecubafb.h b/include/video/hecubafb.h
new file mode 100644
index 000000000000..7b9952339762
--- /dev/null
+++ b/include/video/hecubafb.h
@@ -0,0 +1,51 @@
+/*
+ * hecubafb.h - definitions for the hecuba framebuffer driver
+ *
+ * Copyright (C) 2008 by Jaya Kumar
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_HECUBAFB_H_
+#define _LINUX_HECUBAFB_H_
+
+/* Apollo controller specific defines */
+#define APOLLO_START_NEW_IMG 0xA0
+#define APOLLO_STOP_IMG_DATA 0xA1
+#define APOLLO_DISPLAY_IMG 0xA2
+#define APOLLO_ERASE_DISPLAY 0xA3
+#define APOLLO_INIT_DISPLAY 0xA4
+
+/* Hecuba interface specific defines */
+#define HCB_WUP_BIT 0x01
+#define HCB_DS_BIT 0x02
+#define HCB_RW_BIT 0x04
+#define HCB_CD_BIT 0x08
+#define HCB_ACK_BIT 0x80
+
+/* struct used by hecuba. board specific stuff comes from *board */
+struct hecubafb_par {
+ struct fb_info *info;
+ struct hecuba_board *board;
+ void (*send_command)(struct hecubafb_par *, unsigned char);
+ void (*send_data)(struct hecubafb_par *, unsigned char);
+};
+
+/* board specific routines
+board drivers can implement wait_for_ack with interrupts if desired. if
+wait_for_ack is called with clear=0, then go to sleep and return when ack
+goes hi or if wait_for_ack with clear=1, then return when ack goes lo */
+struct hecuba_board {
+ struct module *owner;
+ void (*remove)(struct hecubafb_par *);
+ void (*set_ctl)(struct hecubafb_par *, unsigned char, unsigned char);
+ void (*set_data)(struct hecubafb_par *, unsigned char);
+ void (*wait_for_ack)(struct hecubafb_par *, int);
+ int (*init)(struct hecubafb_par *);
+};
+
+
+#endif
diff --git a/include/video/metronomefb.h b/include/video/metronomefb.h
new file mode 100644
index 000000000000..dab04b4fad7f
--- /dev/null
+++ b/include/video/metronomefb.h
@@ -0,0 +1,62 @@
+/*
+ * metronomefb.h - definitions for the metronome framebuffer driver
+ *
+ * Copyright (C) 2008 by Jaya Kumar
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_METRONOMEFB_H_
+#define _LINUX_METRONOMEFB_H_
+
+/* address and control descriptors used by metronome controller */
+struct metromem_desc {
+ u32 mFDADR0;
+ u32 mFSADR0;
+ u32 mFIDR0;
+ u32 mLDCMD0;
+};
+
+/* command structure used by metronome controller */
+struct metromem_cmd {
+ u16 opcode;
+ u16 args[((64-2)/2)];
+ u16 csum;
+};
+
+/* struct used by metronome. board specific stuff comes from *board */
+struct metronomefb_par {
+ unsigned char *metromem;
+ struct metromem_desc *metromem_desc;
+ struct metromem_cmd *metromem_cmd;
+ unsigned char *metromem_wfm;
+ unsigned char *metromem_img;
+ u16 *metromem_img_csum;
+ u16 *csum_table;
+ int metromemsize;
+ dma_addr_t metromem_dma;
+ dma_addr_t metromem_desc_dma;
+ struct fb_info *info;
+ struct metronome_board *board;
+ wait_queue_head_t waitq;
+ u8 frame_count;
+};
+
+/* board specific routines */
+struct metronome_board {
+ struct module *owner;
+ void (*free_irq)(struct fb_info *);
+ void (*init_gpio_regs)(struct metronomefb_par *);
+ void (*init_lcdc_regs)(struct metronomefb_par *);
+ void (*post_dma_setup)(struct metronomefb_par *);
+ void (*set_rst)(struct metronomefb_par *, int);
+ void (*set_stdby)(struct metronomefb_par *, int);
+ int (*met_wait_event)(struct metronomefb_par *);
+ int (*met_wait_event_intr)(struct metronomefb_par *);
+ int (*setup_irq)(struct fb_info *);
+};
+
+#endif
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
new file mode 100644
index 000000000000..fe43b0f3c86a
--- /dev/null
+++ b/include/xen/balloon.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * 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 2bde54d29be5..acd8e062c85f 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -5,13 +5,7 @@
#include <xen/interface/event_channel.h>
#include <asm/xen/hypercall.h>
-
-enum ipi_vector {
- XEN_RESCHEDULE_VECTOR,
- XEN_CALL_FUNCTION_VECTOR,
-
- XEN_NR_IPIS,
-};
+#include <asm/xen/events.h>
int bind_evtchn_to_irq(unsigned int evtchn);
int bind_evtchn_to_irqhandler(unsigned int evtchn,
@@ -37,6 +31,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
void unbind_from_irqhandler(unsigned int irq, void *dev_id);
void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
+int resend_irq_on_evtchn(unsigned int irq);
static inline void notify_remote_via_evtchn(int port)
{
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index 761c83498e03..466204846121 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -39,6 +39,7 @@
#include <asm/xen/hypervisor.h>
#include <xen/interface/grant_table.h>
+#include <asm/xen/grant_table.h>
/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
#define NR_GRANT_FRAMES 4
@@ -102,6 +103,12 @@ void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
unsigned long pfn);
+int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
+ unsigned long max_nr_gframes,
+ struct grant_entry **__shared);
+void arch_gnttab_unmap_shared(struct grant_entry *shared,
+ unsigned long nr_gframes);
+
#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
#endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/interface/callback.h b/include/xen/interface/callback.h
new file mode 100644
index 000000000000..4aadcba31af9
--- /dev/null
+++ b/include/xen/interface/callback.h
@@ -0,0 +1,102 @@
+/******************************************************************************
+ * callback.h
+ *
+ * Register guest OS callbacks with Xen.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_PUBLIC_CALLBACK_H__
+#define __XEN_PUBLIC_CALLBACK_H__
+
+#include "xen.h"
+
+/*
+ * Prototype for this hypercall is:
+ * long callback_op(int cmd, void *extra_args)
+ * @cmd == CALLBACKOP_??? (callback operation).
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+/* ia64, x86: Callback for event delivery. */
+#define CALLBACKTYPE_event 0
+
+/* x86: Failsafe callback when guest state cannot be restored by Xen. */
+#define CALLBACKTYPE_failsafe 1
+
+/* x86/64 hypervisor: Syscall by 64-bit guest app ('64-on-64-on-64'). */
+#define CALLBACKTYPE_syscall 2
+
+/*
+ * x86/32 hypervisor: Only available on x86/32 when supervisor_mode_kernel
+ * feature is enabled. Do not use this callback type in new code.
+ */
+#define CALLBACKTYPE_sysenter_deprecated 3
+
+/* x86: Callback for NMI delivery. */
+#define CALLBACKTYPE_nmi 4
+
+/*
+ * x86: sysenter is only available as follows:
+ * - 32-bit hypervisor: with the supervisor_mode_kernel feature enabled
+ * - 64-bit hypervisor: 32-bit guest applications on Intel CPUs
+ * ('32-on-32-on-64', '32-on-64-on-64')
+ * [nb. also 64-bit guest applications on Intel CPUs
+ * ('64-on-64-on-64'), but syscall is preferred]
+ */
+#define CALLBACKTYPE_sysenter 5
+
+/*
+ * x86/64 hypervisor: Syscall by 32-bit guest app on AMD CPUs
+ * ('32-on-32-on-64', '32-on-64-on-64')
+ */
+#define CALLBACKTYPE_syscall32 7
+
+/*
+ * Disable event deliver during callback? This flag is ignored for event and
+ * NMI callbacks: event delivery is unconditionally disabled.
+ */
+#define _CALLBACKF_mask_events 0
+#define CALLBACKF_mask_events (1U << _CALLBACKF_mask_events)
+
+/*
+ * Register a callback.
+ */
+#define CALLBACKOP_register 0
+struct callback_register {
+ uint16_t type;
+ uint16_t flags;
+ struct xen_callback address;
+};
+
+/*
+ * Unregister a callback.
+ *
+ * Not all callbacks can be unregistered. -EINVAL will be returned if
+ * you attempt to unregister such a callback.
+ */
+#define CALLBACKOP_unregister 1
+struct callback_unregister {
+ uint16_t type;
+ uint16_t _unused;
+};
+
+#endif /* __XEN_PUBLIC_CALLBACK_H__ */
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h
index 219049802cf2..39da93c21de0 100644
--- a/include/xen/interface/grant_table.h
+++ b/include/xen/interface/grant_table.h
@@ -185,6 +185,7 @@ struct gnttab_map_grant_ref {
grant_handle_t handle;
uint64_t dev_bus_addr;
};
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_map_grant_ref);
/*
* GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
@@ -206,6 +207,7 @@ struct gnttab_unmap_grant_ref {
/* OUT parameters. */
int16_t status; /* GNTST_* */
};
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_unmap_grant_ref);
/*
* GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
@@ -223,8 +225,9 @@ struct gnttab_setup_table {
uint32_t nr_frames;
/* OUT parameters. */
int16_t status; /* GNTST_* */
- ulong *frame_list;
+ GUEST_HANDLE(ulong) frame_list;
};
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_setup_table);
/*
* GNTTABOP_dump_table: Dump the contents of the grant table to the
@@ -237,6 +240,7 @@ struct gnttab_dump_table {
/* OUT parameters. */
int16_t status; /* GNTST_* */
};
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_dump_table);
/*
* GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
@@ -255,7 +259,7 @@ struct gnttab_transfer {
/* OUT parameters. */
int16_t status;
};
-
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_transfer);
/*
* GNTTABOP_copy: Hypervisor based copy
@@ -296,6 +300,7 @@ struct gnttab_copy {
/* OUT parameters. */
int16_t status;
};
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_copy);
/*
* GNTTABOP_query_size: Query the current and maximum sizes of the shared
@@ -313,7 +318,7 @@ struct gnttab_query_size {
uint32_t max_nr_frames;
int16_t status; /* GNTST_* */
};
-
+DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_size);
/*
* Bitfield values for update_pin_status.flags.
diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h
new file mode 100644
index 000000000000..5a934dd7796d
--- /dev/null
+++ b/include/xen/interface/io/fbif.h
@@ -0,0 +1,124 @@
+/*
+ * fbif.h -- Xen virtual frame buffer device
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ */
+
+#ifndef __XEN_PUBLIC_IO_FBIF_H__
+#define __XEN_PUBLIC_IO_FBIF_H__
+
+/* Out events (frontend -> backend) */
+
+/*
+ * Out events may be sent only when requested by backend, and receipt
+ * of an unknown out event is an error.
+ */
+
+/* Event type 1 currently not used */
+/*
+ * Framebuffer update notification event
+ * Capable frontend sets feature-update in xenstore.
+ * Backend requests it by setting request-update in xenstore.
+ */
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_update {
+ uint8_t type; /* XENFB_TYPE_UPDATE */
+ int32_t x; /* source x */
+ int32_t y; /* source y */
+ int32_t width; /* rect width */
+ int32_t height; /* rect height */
+};
+
+#define XENFB_OUT_EVENT_SIZE 40
+
+union xenfb_out_event {
+ uint8_t type;
+ struct xenfb_update update;
+ char pad[XENFB_OUT_EVENT_SIZE];
+};
+
+/* In events (backend -> frontend) */
+
+/*
+ * Frontends should ignore unknown in events.
+ * No in events currently defined.
+ */
+
+#define XENFB_IN_EVENT_SIZE 40
+
+union xenfb_in_event {
+ uint8_t type;
+ char pad[XENFB_IN_EVENT_SIZE];
+};
+
+/* shared page */
+
+#define XENFB_IN_RING_SIZE 1024
+#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE)
+#define XENFB_IN_RING_OFFS 1024
+#define XENFB_IN_RING(page) \
+ ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS))
+#define XENFB_IN_RING_REF(page, idx) \
+ (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN])
+
+#define XENFB_OUT_RING_SIZE 2048
+#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE)
+#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE)
+#define XENFB_OUT_RING(page) \
+ ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS))
+#define XENFB_OUT_RING_REF(page, idx) \
+ (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN])
+
+struct xenfb_page {
+ uint32_t in_cons, in_prod;
+ uint32_t out_cons, out_prod;
+
+ int32_t width; /* width of the framebuffer (in pixels) */
+ int32_t height; /* height of the framebuffer (in pixels) */
+ uint32_t line_length; /* length of a row of pixels (in bytes) */
+ uint32_t mem_length; /* length of the framebuffer (in bytes) */
+ uint8_t depth; /* depth of a pixel (in bits) */
+
+ /*
+ * Framebuffer page directory
+ *
+ * Each directory page holds PAGE_SIZE / sizeof(*pd)
+ * framebuffer pages, and can thus map up to PAGE_SIZE *
+ * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and
+ * sizeof(unsigned long) == 4, that's 4 Megs. Two directory
+ * pages should be enough for a while.
+ */
+ unsigned long pd[2];
+};
+
+/*
+ * Wart: xenkbd needs to know resolution. Put it here until a better
+ * solution is found, but don't leak it to the backend.
+ */
+#ifdef __KERNEL__
+#define XENFB_WIDTH 800
+#define XENFB_HEIGHT 600
+#define XENFB_DEPTH 32
+#endif
+
+#endif
diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h
new file mode 100644
index 000000000000..fb97f4284ffd
--- /dev/null
+++ b/include/xen/interface/io/kbdif.h
@@ -0,0 +1,114 @@
+/*
+ * kbdif.h -- Xen virtual keyboard/mouse
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ */
+
+#ifndef __XEN_PUBLIC_IO_KBDIF_H__
+#define __XEN_PUBLIC_IO_KBDIF_H__
+
+/* In events (backend -> frontend) */
+
+/*
+ * Frontends should ignore unknown in events.
+ */
+
+/* Pointer movement event */
+#define XENKBD_TYPE_MOTION 1
+/* Event type 2 currently not used */
+/* Key event (includes pointer buttons) */
+#define XENKBD_TYPE_KEY 3
+/*
+ * Pointer position event
+ * Capable backend sets feature-abs-pointer in xenstore.
+ * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting
+ * request-abs-update in xenstore.
+ */
+#define XENKBD_TYPE_POS 4
+
+struct xenkbd_motion {
+ uint8_t type; /* XENKBD_TYPE_MOTION */
+ int32_t rel_x; /* relative X motion */
+ int32_t rel_y; /* relative Y motion */
+};
+
+struct xenkbd_key {
+ uint8_t type; /* XENKBD_TYPE_KEY */
+ uint8_t pressed; /* 1 if pressed; 0 otherwise */
+ uint32_t keycode; /* KEY_* from linux/input.h */
+};
+
+struct xenkbd_position {
+ uint8_t type; /* XENKBD_TYPE_POS */
+ int32_t abs_x; /* absolute X position (in FB pixels) */
+ int32_t abs_y; /* absolute Y position (in FB pixels) */
+};
+
+#define XENKBD_IN_EVENT_SIZE 40
+
+union xenkbd_in_event {
+ uint8_t type;
+ struct xenkbd_motion motion;
+ struct xenkbd_key key;
+ struct xenkbd_position pos;
+ char pad[XENKBD_IN_EVENT_SIZE];
+};
+
+/* Out events (frontend -> backend) */
+
+/*
+ * Out events may be sent only when requested by backend, and receipt
+ * of an unknown out event is an error.
+ * No out events currently defined.
+ */
+
+#define XENKBD_OUT_EVENT_SIZE 40
+
+union xenkbd_out_event {
+ uint8_t type;
+ char pad[XENKBD_OUT_EVENT_SIZE];
+};
+
+/* shared page */
+
+#define XENKBD_IN_RING_SIZE 2048
+#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE)
+#define XENKBD_IN_RING_OFFS 1024
+#define XENKBD_IN_RING(page) \
+ ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS))
+#define XENKBD_IN_RING_REF(page, idx) \
+ (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN])
+
+#define XENKBD_OUT_RING_SIZE 1024
+#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE)
+#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE)
+#define XENKBD_OUT_RING(page) \
+ ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS))
+#define XENKBD_OUT_RING_REF(page, idx) \
+ (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN])
+
+struct xenkbd_page {
+ uint32_t in_cons, in_prod;
+ uint32_t out_cons, out_prod;
+};
+
+#endif
diff --git a/include/xen/interface/io/protocols.h b/include/xen/interface/io/protocols.h
new file mode 100644
index 000000000000..01fc8ae5f0b0
--- /dev/null
+++ b/include/xen/interface/io/protocols.h
@@ -0,0 +1,21 @@
+#ifndef __XEN_PROTOCOLS_H__
+#define __XEN_PROTOCOLS_H__
+
+#define XEN_IO_PROTO_ABI_X86_32 "x86_32-abi"
+#define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi"
+#define XEN_IO_PROTO_ABI_IA64 "ia64-abi"
+#define XEN_IO_PROTO_ABI_POWERPC64 "powerpc64-abi"
+
+#if defined(__i386__)
+# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32
+#elif defined(__x86_64__)
+# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64
+#elif defined(__ia64__)
+# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64
+#elif defined(__powerpc64__)
+# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64
+#else
+# error arch fixup needed here
+#endif
+
+#endif
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index af36ead16817..da768469aa92 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -29,7 +29,7 @@ struct xen_memory_reservation {
* OUT: GMFN bases of extents that were allocated
* (NB. This command also updates the mach_to_phys translation table)
*/
- GUEST_HANDLE(ulong) extent_start;
+ ulong extent_start;
/* Number of extents, and size/alignment of each (2^extent_order pages). */
unsigned long nr_extents;
@@ -50,7 +50,6 @@ struct xen_memory_reservation {
domid_t domid;
};
-DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
/*
* Returns the maximum machine frame number of mapped RAM in this system.
@@ -86,7 +85,7 @@ struct xen_machphys_mfn_list {
* any large discontiguities in the machine address space, 2MB gaps in
* the machphys table will be represented by an MFN base of zero.
*/
- GUEST_HANDLE(ulong) extent_start;
+ ulong extent_start;
/*
* Number of extents written to the above array. This will be smaller
@@ -94,7 +93,6 @@ struct xen_machphys_mfn_list {
*/
unsigned int nr_extents;
};
-DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
/*
* Sets the GPFN at which a particular page appears in the specified guest's
@@ -117,7 +115,6 @@ struct xen_add_to_physmap {
/* GPFN where the source mapping page should appear. */
unsigned long gpfn;
};
-DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap);
/*
* Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
@@ -132,14 +129,13 @@ struct xen_translate_gpfn_list {
unsigned long nr_gpfns;
/* List of GPFNs to translate. */
- GUEST_HANDLE(ulong) gpfn_list;
+ ulong gpfn_list;
/*
* Output list to contain MFN translations. May be the same as the input
* list (in which case each input GPFN is overwritten with the output MFN).
*/
- GUEST_HANDLE(ulong) mfn_list;
+ ulong mfn_list;
};
-DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
#endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
index b05d8a6d9143..87e6f8a48661 100644
--- a/include/xen/interface/vcpu.h
+++ b/include/xen/interface/vcpu.h
@@ -85,6 +85,7 @@ struct vcpu_runstate_info {
*/
uint64_t time[4];
};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_runstate_info);
/* VCPU is currently running on a physical CPU. */
#define RUNSTATE_running 0
@@ -119,6 +120,7 @@ struct vcpu_runstate_info {
#define VCPUOP_register_runstate_memory_area 5
struct vcpu_register_runstate_memory_area {
union {
+ GUEST_HANDLE(vcpu_runstate_info) h;
struct vcpu_runstate_info *v;
uint64_t p;
} addr;
@@ -134,6 +136,7 @@ struct vcpu_register_runstate_memory_area {
struct vcpu_set_periodic_timer {
uint64_t period_ns;
};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_periodic_timer);
/*
* Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot
@@ -145,6 +148,7 @@ struct vcpu_set_singleshot_timer {
uint64_t timeout_abs_ns;
uint32_t flags; /* VCPU_SSHOTTMR_??? */
};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_singleshot_timer);
/* Flags to VCPUOP_set_singleshot_timer. */
/* Require the timeout to be in the future (return -ETIME if it's passed). */
@@ -164,5 +168,6 @@ struct vcpu_register_vcpu_info {
uint32_t offset; /* offset within page */
uint32_t rsvd; /* unused */
};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_vcpu_info);
#endif /* __XEN_PUBLIC_VCPU_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 518a5bf79ed3..9b018da48cf3 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -58,6 +58,16 @@
#define __HYPERVISOR_physdev_op 33
#define __HYPERVISOR_hvm_op 34
+/* Architecture-specific hypercall definitions. */
+#define __HYPERVISOR_arch_0 48
+#define __HYPERVISOR_arch_1 49
+#define __HYPERVISOR_arch_2 50
+#define __HYPERVISOR_arch_3 51
+#define __HYPERVISOR_arch_4 52
+#define __HYPERVISOR_arch_5 53
+#define __HYPERVISOR_arch_6 54
+#define __HYPERVISOR_arch_7 55
+
/*
* VIRTUAL INTERRUPTS
*
@@ -68,8 +78,18 @@
#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */
#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */
#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */
-#define NR_VIRQS 8
+/* Architecture-specific VIRQ definitions. */
+#define VIRQ_ARCH_0 16
+#define VIRQ_ARCH_1 17
+#define VIRQ_ARCH_2 18
+#define VIRQ_ARCH_3 19
+#define VIRQ_ARCH_4 20
+#define VIRQ_ARCH_5 21
+#define VIRQ_ARCH_6 22
+#define VIRQ_ARCH_7 23
+
+#define NR_VIRQS 24
/*
* MMU-UPDATE REQUESTS
*
diff --git a/include/xen/interface/xencomm.h b/include/xen/interface/xencomm.h
new file mode 100644
index 000000000000..ac45e0712afa
--- /dev/null
+++ b/include/xen/interface/xencomm.h
@@ -0,0 +1,41 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * 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.
+ *
+ * Copyright (C) IBM Corp. 2006
+ */
+
+#ifndef _XEN_XENCOMM_H_
+#define _XEN_XENCOMM_H_
+
+/* A xencomm descriptor is a scatter/gather list containing physical
+ * addresses corresponding to a virtually contiguous memory area. The
+ * hypervisor translates these physical addresses to machine addresses to copy
+ * to and from the virtually contiguous area.
+ */
+
+#define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */
+#define XENCOMM_INVALID (~0UL)
+
+struct xencomm_desc {
+ uint32_t magic;
+ uint32_t nr_addrs; /* the number of entries in address[] */
+ uint64_t address[0];
+};
+
+#endif /* _XEN_XENCOMM_H_ */
diff --git a/include/xen/page.h b/include/xen/page.h
index 031ef22a971e..eaf85fab1263 100644
--- a/include/xen/page.h
+++ b/include/xen/page.h
@@ -1,180 +1 @@
-#ifndef __XEN_PAGE_H
-#define __XEN_PAGE_H
-
-#include <linux/pfn.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-#include <xen/features.h>
-
-#ifdef CONFIG_X86_PAE
-/* Xen machine address */
-typedef struct xmaddr {
- unsigned long long maddr;
-} xmaddr_t;
-
-/* Xen pseudo-physical address */
-typedef struct xpaddr {
- unsigned long long paddr;
-} xpaddr_t;
-#else
-/* Xen machine address */
-typedef struct xmaddr {
- unsigned long maddr;
-} xmaddr_t;
-
-/* Xen pseudo-physical address */
-typedef struct xpaddr {
- unsigned long paddr;
-} xpaddr_t;
-#endif
-
-#define XMADDR(x) ((xmaddr_t) { .maddr = (x) })
-#define XPADDR(x) ((xpaddr_t) { .paddr = (x) })
-
-/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
-#define INVALID_P2M_ENTRY (~0UL)
-#define FOREIGN_FRAME_BIT (1UL<<31)
-#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
-
-extern unsigned long *phys_to_machine_mapping;
-
-static inline unsigned long pfn_to_mfn(unsigned long pfn)
-{
- if (xen_feature(XENFEAT_auto_translated_physmap))
- return pfn;
-
- return phys_to_machine_mapping[(unsigned int)(pfn)] &
- ~FOREIGN_FRAME_BIT;
-}
-
-static inline int phys_to_machine_mapping_valid(unsigned long pfn)
-{
- if (xen_feature(XENFEAT_auto_translated_physmap))
- return 1;
-
- return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
-}
-
-static inline unsigned long mfn_to_pfn(unsigned long mfn)
-{
- unsigned long pfn;
-
- if (xen_feature(XENFEAT_auto_translated_physmap))
- return mfn;
-
-#if 0
- if (unlikely((mfn >> machine_to_phys_order) != 0))
- return max_mapnr;
-#endif
-
- pfn = 0;
- /*
- * The array access can fail (e.g., device space beyond end of RAM).
- * In such cases it doesn't matter what we return (we return garbage),
- * but we must handle the fault without crashing!
- */
- __get_user(pfn, &machine_to_phys_mapping[mfn]);
-
- return pfn;
-}
-
-static inline xmaddr_t phys_to_machine(xpaddr_t phys)
-{
- unsigned offset = phys.paddr & ~PAGE_MASK;
- return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
-}
-
-static inline xpaddr_t machine_to_phys(xmaddr_t machine)
-{
- unsigned offset = machine.maddr & ~PAGE_MASK;
- return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
-}
-
-/*
- * We detect special mappings in one of two ways:
- * 1. If the MFN is an I/O page then Xen will set the m2p entry
- * to be outside our maximum possible pseudophys range.
- * 2. If the MFN belongs to a different domain then we will certainly
- * not have MFN in our p2m table. Conversely, if the page is ours,
- * then we'll have p2m(m2p(MFN))==MFN.
- * If we detect a special mapping then it doesn't have a 'struct page'.
- * We force !pfn_valid() by returning an out-of-range pointer.
- *
- * NB. These checks require that, for any MFN that is not in our reservation,
- * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if
- * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN.
- * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety.
- *
- * NB2. When deliberately mapping foreign pages into the p2m table, you *must*
- * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we
- * require. In all the cases we care about, the FOREIGN_FRAME bit is
- * masked (e.g., pfn_to_mfn()) so behaviour there is correct.
- */
-static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
-{
- extern unsigned long max_mapnr;
- unsigned long pfn = mfn_to_pfn(mfn);
- if ((pfn < max_mapnr)
- && !xen_feature(XENFEAT_auto_translated_physmap)
- && (phys_to_machine_mapping[pfn] != mfn))
- return max_mapnr; /* force !pfn_valid() */
- return pfn;
-}
-
-static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
-{
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
- return;
- }
- phys_to_machine_mapping[pfn] = mfn;
-}
-
-/* VIRT <-> MACHINE conversion */
-#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
-#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
-#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
-
-#ifdef CONFIG_X86_PAE
-#define pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) | \
- (((_pte).pte_high & 0xfff) << (32-PAGE_SHIFT)))
-
-static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot)
-{
- pte_t pte;
-
- pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) |
- (pgprot_val(pgprot) >> 32);
- pte.pte_high &= (__supported_pte_mask >> 32);
- pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
- pte.pte_low &= __supported_pte_mask;
-
- return pte;
-}
-
-static inline unsigned long long pte_val_ma(pte_t x)
-{
- return x.pte;
-}
-#define pmd_val_ma(v) ((v).pmd)
-#define pud_val_ma(v) ((v).pgd.pgd)
-#define __pte_ma(x) ((pte_t) { .pte = (x) })
-#define __pmd_ma(x) ((pmd_t) { (x) } )
-#else /* !X86_PAE */
-#define pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT)
-#define mfn_pte(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
-#define pte_val_ma(x) ((x).pte)
-#define pmd_val_ma(v) ((v).pud.pgd.pgd)
-#define __pte_ma(x) ((pte_t) { (x) } )
-#endif /* CONFIG_X86_PAE */
-
-#define pgd_val_ma(x) ((x).pgd)
-
-
-xmaddr_t arbitrary_virt_to_machine(unsigned long address);
-void make_lowmem_page_readonly(void *vaddr);
-void make_lowmem_page_readwrite(void *vaddr);
-
-#endif /* __XEN_PAGE_H */
+#include <asm/xen/page.h>
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
new file mode 100644
index 000000000000..10ddfe0142d0
--- /dev/null
+++ b/include/xen/xen-ops.h
@@ -0,0 +1,8 @@
+#ifndef INCLUDE_XEN_OPS_H
+#define INCLUDE_XEN_OPS_H
+
+#include <linux/percpu.h>
+
+DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
+
+#endif /* INCLUDE_XEN_OPS_H */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index 6f7c290651ae..6369d89c25d5 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -97,6 +97,7 @@ struct xenbus_driver {
int (*uevent)(struct xenbus_device *, char **, int, char *, int);
struct device_driver driver;
int (*read_otherend_details)(struct xenbus_device *dev);
+ int (*is_ready)(struct xenbus_device *dev);
};
static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
diff --git a/include/xen/xencomm.h b/include/xen/xencomm.h
new file mode 100644
index 000000000000..e43b039be112
--- /dev/null
+++ b/include/xen/xencomm.h
@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ * Jerone Young <jyoung5@us.ibm.com>
+ */
+
+#ifndef _LINUX_XENCOMM_H_
+#define _LINUX_XENCOMM_H_
+
+#include <xen/interface/xencomm.h>
+
+#define XENCOMM_MINI_ADDRS 3
+struct xencomm_mini {
+ struct xencomm_desc _desc;
+ uint64_t address[XENCOMM_MINI_ADDRS];
+};
+
+/* To avoid additionnal virt to phys conversion, an opaque structure is
+ presented. */
+struct xencomm_handle;
+
+extern void xencomm_free(struct xencomm_handle *desc);
+extern struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes);
+extern struct xencomm_handle *__xencomm_map_no_alloc(void *ptr,
+ unsigned long bytes, struct xencomm_mini *xc_area);
+
+#if 0
+#define XENCOMM_MINI_ALIGNED(xc_desc, n) \
+ struct xencomm_mini xc_desc ## _base[(n)] \
+ __attribute__((__aligned__(sizeof(struct xencomm_mini)))); \
+ struct xencomm_mini *xc_desc = &xc_desc ## _base[0];
+#else
+/*
+ * gcc bug workaround:
+ * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660
+ * gcc doesn't handle properly stack variable with
+ * __attribute__((__align__(sizeof(struct xencomm_mini))))
+ */
+#define XENCOMM_MINI_ALIGNED(xc_desc, n) \
+ unsigned char xc_desc ## _base[((n) + 1 ) * \
+ sizeof(struct xencomm_mini)]; \
+ struct xencomm_mini *xc_desc = (struct xencomm_mini *) \
+ ((unsigned long)xc_desc ## _base + \
+ (sizeof(struct xencomm_mini) - \
+ ((unsigned long)xc_desc ## _base) % \
+ sizeof(struct xencomm_mini)));
+#endif
+#define xencomm_map_no_alloc(ptr, bytes) \
+ ({ XENCOMM_MINI_ALIGNED(xc_desc, 1); \
+ __xencomm_map_no_alloc(ptr, bytes, xc_desc); })
+
+/* provided by architecture code: */
+extern unsigned long xencomm_vtop(unsigned long vaddr);
+
+static inline void *xencomm_pa(void *ptr)
+{
+ return (void *)xencomm_vtop((unsigned long)ptr);
+}
+
+#define xen_guest_handle(hnd) ((hnd).p)
+
+#endif /* _LINUX_XENCOMM_H_ */
diff --git a/init/Kconfig b/init/Kconfig
index ba3a389fab94..da071c4bbfb7 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -496,16 +496,12 @@ source "usr/Kconfig"
endif
config CC_OPTIMIZE_FOR_SIZE
- bool "Optimize for size (Look out for broken compilers!)"
+ bool "Optimize for size"
default y
- depends on ARM || H8300 || SUPERH || EXPERIMENTAL
help
Enabling this option will pass "-Os" instead of "-O2" to gcc
resulting in a smaller kernel.
- WARNING: some versions of gcc may generate incorrect code with this
- option. If problems are observed, a gcc upgrade may be needed.
-
If unsure, say N.
config SYSCTL
@@ -521,7 +517,7 @@ menuconfig EMBEDDED
config UID16
bool "Enable 16-bit UID system calls" if EMBEDDED
- depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && SPARC32_COMPAT) || UML || (X86_64 && IA32_EMULATION)
+ depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION)
default y
help
This enables the legacy 16-bit UID syscall wrappers.
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
index 753dc54a6649..7473b0c59d4d 100644
--- a/init/do_mounts_md.c
+++ b/init/do_mounts_md.c
@@ -133,7 +133,7 @@ static void __init md_setup_drive(void)
else
dev = MKDEV(MD_MAJOR, minor);
create_dev(name, dev);
- for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
+ for (i = 0; i < MD_SB_DISKS && devname != NULL; i++) {
char *p;
char comp_name[64];
u32 rdev;
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index 3ac5904d1b12..46dfd64ae8fb 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -212,7 +212,7 @@ int __init rd_load_image(char *from)
}
buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
- if (buf == 0) {
+ if (!buf) {
printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
goto done;
}
diff --git a/init/main.c b/init/main.c
index 833a67df1f7e..1687b0167c4a 100644
--- a/init/main.c
+++ b/init/main.c
@@ -521,7 +521,11 @@ static void __init boot_cpu_init(void)
cpu_set(cpu, cpu_possible_map);
}
-void __init __attribute__((weak)) smp_setup_processor_id(void)
+void __init __weak smp_setup_processor_id(void)
+{
+}
+
+void __init __weak thread_info_cache_init(void)
{
}
@@ -645,6 +649,7 @@ asmlinkage void __init start_kernel(void)
if (efi_enabled)
efi_enter_virtual_mode();
#endif
+ thread_info_cache_init();
fork_init(num_physpages);
proc_caches_init();
buffer_init();
diff --git a/ipc/shm.c b/ipc/shm.c
index cc63fae02f06..e636910454a9 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -271,11 +271,9 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
if (sfd->vm_ops->get_policy)
pol = sfd->vm_ops->get_policy(vma, addr);
- else if (vma->vm_policy) {
+ else if (vma->vm_policy)
pol = vma->vm_policy;
- mpol_get(pol); /* get_vma_policy() expects this */
- } else
- pol = current->mempolicy;
+
return pol;
}
#endif
diff --git a/kernel/bounds.c b/kernel/bounds.c
new file mode 100644
index 000000000000..c3c55544db2f
--- /dev/null
+++ b/kernel/bounds.c
@@ -0,0 +1,23 @@
+/*
+ * Generate definitions needed by the preprocessor.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#define __GENERATING_BOUNDS_H
+/* Include headers that define the enum constants of interest */
+#include <linux/page-flags.h>
+#include <linux/mmzone.h>
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+void foo(void)
+{
+ /* The enum constants to put into include/linux/bounds.h */
+ DEFINE(NR_PAGEFLAGS, __NR_PAGEFLAGS);
+ DEFINE(MAX_NR_ZONES, __MAX_NR_ZONES);
+ /* End of constants */
+}
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 8b35fbd8292f..48a976c52cf5 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -941,7 +941,7 @@ static int update_nodemask(struct cpuset *cs, char *buf)
cs->mems_generation = cpuset_mems_generation++;
mutex_unlock(&callback_mutex);
- cpuset_being_rebound = cs; /* causes mpol_copy() rebind */
+ cpuset_being_rebound = cs; /* causes mpol_dup() rebind */
fudge = 10; /* spare mmarray[] slots */
fudge += cpus_weight(cs->cpus_allowed); /* imagine one fork-bomb/cpu */
@@ -992,7 +992,7 @@ static int update_nodemask(struct cpuset *cs, char *buf)
* rebind the vma mempolicies of each mm in mmarray[] to their
* new cpuset, and release that mm. The mpol_rebind_mm()
* call takes mmap_sem, which we couldn't take while holding
- * tasklist_lock. Forks can happen again now - the mpol_copy()
+ * tasklist_lock. Forks can happen again now - the mpol_dup()
* cpuset_being_rebound check will catch such forks, and rebind
* their vma mempolicies too. Because we still hold the global
* cgroup_mutex, we know that no other rebind effort will
@@ -1265,7 +1265,8 @@ static ssize_t cpuset_common_file_write(struct cgroup *cont,
return -E2BIG;
/* +1 for nul-terminator */
- if ((buffer = kmalloc(nbytes + 1, GFP_KERNEL)) == 0)
+ buffer = kmalloc(nbytes + 1, GFP_KERNEL);
+ if (!buffer)
return -ENOMEM;
if (copy_from_user(buffer, userbuf, nbytes)) {
@@ -1958,22 +1959,14 @@ nodemask_t cpuset_mems_allowed(struct task_struct *tsk)
}
/**
- * cpuset_zonelist_valid_mems_allowed - check zonelist vs. curremt mems_allowed
- * @zl: the zonelist to be checked
+ * cpuset_nodemask_valid_mems_allowed - check nodemask vs. curremt mems_allowed
+ * @nodemask: the nodemask to be checked
*
- * Are any of the nodes on zonelist zl allowed in current->mems_allowed?
+ * Are any of the nodes in the nodemask allowed in current->mems_allowed?
*/
-int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl)
+int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask)
{
- int i;
-
- for (i = 0; zl->zones[i]; i++) {
- int nid = zone_to_nid(zl->zones[i]);
-
- if (node_isset(nid, current->mems_allowed))
- return 1;
- }
- return 0;
+ return nodes_intersects(*nodemask, current->mems_allowed);
}
/*
diff --git a/kernel/exit.c b/kernel/exit.c
index cece89f80ab4..2a9d98c641ac 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -507,10 +507,9 @@ void put_files_struct(struct files_struct *files)
}
}
-EXPORT_SYMBOL(put_files_struct);
-
-void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
+void reset_files_struct(struct files_struct *files)
{
+ struct task_struct *tsk = current;
struct files_struct *old;
old = tsk->files;
@@ -519,7 +518,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
task_unlock(tsk);
put_files_struct(old);
}
-EXPORT_SYMBOL(reset_files_struct);
void exit_files(struct task_struct *tsk)
{
@@ -969,7 +967,7 @@ NORET_TYPE void do_exit(long code)
proc_exit_connector(tsk);
exit_notify(tsk, group_dead);
#ifdef CONFIG_NUMA
- mpol_free(tsk->mempolicy);
+ mpol_put(tsk->mempolicy);
tsk->mempolicy = NULL;
#endif
#ifdef CONFIG_FUTEX
diff --git a/kernel/fork.c b/kernel/fork.c
index 89fe414645e9..6067e429f281 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -279,7 +279,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
if (!tmp)
goto fail_nomem;
*tmp = *mpnt;
- pol = mpol_copy(vma_policy(mpnt));
+ pol = mpol_dup(vma_policy(mpnt));
retval = PTR_ERR(pol);
if (IS_ERR(pol))
goto fail_nomem_policy;
@@ -521,7 +521,7 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
* Allocate a new mm structure and copy contents from the
* mm structure of the passed in task structure.
*/
-static struct mm_struct *dup_mm(struct task_struct *tsk)
+struct mm_struct *dup_mm(struct task_struct *tsk)
{
struct mm_struct *mm, *oldmm = current->mm;
int err;
@@ -805,12 +805,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
goto out;
}
- /*
- * Note: we may be using current for both targets (See exec.c)
- * This works because we cache current->files (old) as oldf. Don't
- * break this.
- */
- tsk->files = NULL;
newf = dup_fd(oldf, &error);
if (!newf)
goto out;
@@ -846,34 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
return 0;
}
-/*
- * Helper to unshare the files of the current task.
- * We don't want to expose copy_files internals to
- * the exec layer of the kernel.
- */
-
-int unshare_files(void)
-{
- struct files_struct *files = current->files;
- int rc;
-
- BUG_ON(!files);
-
- /* This can race but the race causes us to copy when we don't
- need to and drop the copy */
- if(atomic_read(&files->count) == 1)
- {
- atomic_inc(&files->count);
- return 0;
- }
- rc = copy_files(0, current);
- if(rc)
- current->files = files;
- return rc;
-}
-
-EXPORT_SYMBOL(unshare_files);
-
static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
{
struct sighand_struct *sig;
@@ -1150,7 +1116,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->audit_context = NULL;
cgroup_fork(p);
#ifdef CONFIG_NUMA
- p->mempolicy = mpol_copy(p->mempolicy);
+ p->mempolicy = mpol_dup(p->mempolicy);
if (IS_ERR(p->mempolicy)) {
retval = PTR_ERR(p->mempolicy);
p->mempolicy = NULL;
@@ -1408,7 +1374,7 @@ bad_fork_cleanup_security:
security_task_free(p);
bad_fork_cleanup_policy:
#ifdef CONFIG_NUMA
- mpol_free(p->mempolicy);
+ mpol_put(p->mempolicy);
bad_fork_cleanup_cgroup:
#endif
cgroup_exit(p, cgroup_callbacks_done);
@@ -1811,3 +1777,27 @@ bad_unshare_cleanup_thread:
bad_unshare_out:
return err;
}
+
+/*
+ * Helper to unshare the files of the current task.
+ * We don't want to expose copy_files internals to
+ * the exec layer of the kernel.
+ */
+
+int unshare_files(struct files_struct **displaced)
+{
+ struct task_struct *task = current;
+ struct files_struct *copy = NULL;
+ int error;
+
+ error = unshare_fd(CLONE_FILES, &copy);
+ if (error || !copy) {
+ *displaced = NULL;
+ return error;
+ }
+ *displaced = task->files;
+ task_lock(task);
+ task->files = copy;
+ task_unlock(task);
+ return 0;
+}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index f78777abe769..dea4c9124ac8 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -590,7 +590,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
list_add_tail(&timer->cb_entry,
&base->cpu_base->cb_pending);
timer->state = HRTIMER_STATE_PENDING;
- raise_softirq(HRTIMER_SOFTIRQ);
return 1;
default:
BUG();
@@ -633,6 +632,11 @@ static int hrtimer_switch_to_hres(void)
return 1;
}
+static inline void hrtimer_raise_softirq(void)
+{
+ raise_softirq(HRTIMER_SOFTIRQ);
+}
+
#else
static inline int hrtimer_hres_active(void) { return 0; }
@@ -651,6 +655,7 @@ static inline int hrtimer_reprogram(struct hrtimer *timer,
{
return 0;
}
+static inline void hrtimer_raise_softirq(void) { }
#endif /* CONFIG_HIGH_RES_TIMERS */
@@ -850,7 +855,7 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
struct hrtimer_clock_base *base, *new_base;
unsigned long flags;
- int ret;
+ int ret, raise;
base = lock_hrtimer_base(timer, &flags);
@@ -884,8 +889,18 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
enqueue_hrtimer(timer, new_base,
new_base->cpu_base == &__get_cpu_var(hrtimer_bases));
+ /*
+ * The timer may be expired and moved to the cb_pending
+ * list. We can not raise the softirq with base lock held due
+ * to a possible deadlock with runqueue lock.
+ */
+ raise = timer->state == HRTIMER_STATE_PENDING;
+
unlock_hrtimer_base(timer, &flags);
+ if (raise)
+ hrtimer_raise_softirq();
+
return ret;
}
EXPORT_SYMBOL_GPL(hrtimer_start);
@@ -1080,8 +1095,19 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
* If the timer was rearmed on another CPU, reprogram
* the event device.
*/
- if (timer->base->first == &timer->node)
- hrtimer_reprogram(timer, timer->base);
+ struct hrtimer_clock_base *base = timer->base;
+
+ if (base->first == &timer->node &&
+ hrtimer_reprogram(timer, base)) {
+ /*
+ * Timer is expired. Thus move it from tree to
+ * pending list again.
+ */
+ __remove_hrtimer(timer, base,
+ HRTIMER_STATE_PENDING, 0);
+ list_add_tail(&timer->cb_entry,
+ &base->cpu_base->cb_pending);
+ }
}
}
spin_unlock_irq(&cpu_base->lock);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 6782dce93d01..cb85c79989b4 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1405,6 +1405,9 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
VMCOREINFO_NUMBER(NR_FREE_PAGES);
+ VMCOREINFO_NUMBER(PG_lru);
+ VMCOREINFO_NUMBER(PG_private);
+ VMCOREINFO_NUMBER(PG_swapcache);
arch_crash_save_vmcoreinfo();
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index fcfb580c3afc..1e0250cb9486 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -72,6 +72,18 @@ DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
+/*
+ * Normally, functions that we'd want to prohibit kprobes in, are marked
+ * __kprobes. But, there are cases where such functions already belong to
+ * a different section (__sched for preempt_schedule)
+ *
+ * For such cases, we now have a blacklist
+ */
+struct kprobe_blackpoint kprobe_blacklist[] = {
+ {"preempt_schedule",},
+ {NULL} /* Terminator */
+};
+
#ifdef __ARCH_WANT_KPROBES_INSN_SLOT
/*
* kprobe->ainsn.insn points to the copy of the instruction to be
@@ -417,6 +429,21 @@ static inline void free_rp_inst(struct kretprobe *rp)
}
}
+static void __kprobes cleanup_rp_inst(struct kretprobe *rp)
+{
+ unsigned long flags;
+ struct kretprobe_instance *ri;
+ struct hlist_node *pos, *next;
+ /* No race here */
+ spin_lock_irqsave(&kretprobe_lock, flags);
+ hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) {
+ ri->rp = NULL;
+ hlist_del(&ri->uflist);
+ }
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ free_rp_inst(rp);
+}
+
/*
* Keep all fields in the kprobe consistent
*/
@@ -492,9 +519,22 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
static int __kprobes in_kprobes_functions(unsigned long addr)
{
+ struct kprobe_blackpoint *kb;
+
if (addr >= (unsigned long)__kprobes_text_start &&
addr < (unsigned long)__kprobes_text_end)
return -EINVAL;
+ /*
+ * If there exists a kprobe_blacklist, verify and
+ * fail any probe registration in the prohibited area
+ */
+ for (kb = kprobe_blacklist; kb->name != NULL; kb++) {
+ if (kb->start_addr) {
+ if (addr >= kb->start_addr &&
+ addr < (kb->start_addr + kb->range))
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -555,6 +595,7 @@ static int __kprobes __register_kprobe(struct kprobe *p,
}
p->nmissed = 0;
+ INIT_LIST_HEAD(&p->list);
mutex_lock(&kprobe_mutex);
old_p = get_kprobe(p->addr);
if (old_p) {
@@ -581,35 +622,28 @@ out:
return ret;
}
-int __kprobes register_kprobe(struct kprobe *p)
-{
- return __register_kprobe(p, (unsigned long)__builtin_return_address(0));
-}
-
-void __kprobes unregister_kprobe(struct kprobe *p)
+/*
+ * Unregister a kprobe without a scheduler synchronization.
+ */
+static int __kprobes __unregister_kprobe_top(struct kprobe *p)
{
- struct module *mod;
struct kprobe *old_p, *list_p;
- int cleanup_p;
- mutex_lock(&kprobe_mutex);
old_p = get_kprobe(p->addr);
- if (unlikely(!old_p)) {
- mutex_unlock(&kprobe_mutex);
- return;
- }
+ if (unlikely(!old_p))
+ return -EINVAL;
+
if (p != old_p) {
list_for_each_entry_rcu(list_p, &old_p->list, list)
if (list_p == p)
/* kprobe p is a valid probe */
goto valid_p;
- mutex_unlock(&kprobe_mutex);
- return;
+ return -EINVAL;
}
valid_p:
if (old_p == p ||
(old_p->pre_handler == aggr_pre_handler &&
- p->list.next == &old_p->list && p->list.prev == &old_p->list)) {
+ list_is_singular(&old_p->list))) {
/*
* Only probe on the hash list. Disarm only if kprobes are
* enabled - otherwise, the breakpoint would already have
@@ -618,43 +652,97 @@ valid_p:
if (kprobe_enabled)
arch_disarm_kprobe(p);
hlist_del_rcu(&old_p->hlist);
- cleanup_p = 1;
} else {
+ if (p->break_handler)
+ old_p->break_handler = NULL;
+ if (p->post_handler) {
+ list_for_each_entry_rcu(list_p, &old_p->list, list) {
+ if ((list_p != p) && (list_p->post_handler))
+ goto noclean;
+ }
+ old_p->post_handler = NULL;
+ }
+noclean:
list_del_rcu(&p->list);
- cleanup_p = 0;
}
+ return 0;
+}
- mutex_unlock(&kprobe_mutex);
+static void __kprobes __unregister_kprobe_bottom(struct kprobe *p)
+{
+ struct module *mod;
+ struct kprobe *old_p;
- synchronize_sched();
if (p->mod_refcounted) {
mod = module_text_address((unsigned long)p->addr);
if (mod)
module_put(mod);
}
- if (cleanup_p) {
- if (p != old_p) {
- list_del_rcu(&p->list);
+ if (list_empty(&p->list) || list_is_singular(&p->list)) {
+ if (!list_empty(&p->list)) {
+ /* "p" is the last child of an aggr_kprobe */
+ old_p = list_entry(p->list.next, struct kprobe, list);
+ list_del(&p->list);
kfree(old_p);
}
arch_remove_kprobe(p);
- } else {
- mutex_lock(&kprobe_mutex);
- if (p->break_handler)
- old_p->break_handler = NULL;
- if (p->post_handler){
- list_for_each_entry_rcu(list_p, &old_p->list, list){
- if (list_p->post_handler){
- cleanup_p = 2;
- break;
- }
- }
- if (cleanup_p == 0)
- old_p->post_handler = NULL;
+ }
+}
+
+static int __register_kprobes(struct kprobe **kps, int num,
+ unsigned long called_from)
+{
+ int i, ret = 0;
+
+ if (num <= 0)
+ return -EINVAL;
+ for (i = 0; i < num; i++) {
+ ret = __register_kprobe(kps[i], called_from);
+ if (ret < 0 && i > 0) {
+ unregister_kprobes(kps, i);
+ break;
}
- mutex_unlock(&kprobe_mutex);
}
+ return ret;
+}
+
+/*
+ * Registration and unregistration functions for kprobe.
+ */
+int __kprobes register_kprobe(struct kprobe *p)
+{
+ return __register_kprobes(&p, 1,
+ (unsigned long)__builtin_return_address(0));
+}
+
+void __kprobes unregister_kprobe(struct kprobe *p)
+{
+ unregister_kprobes(&p, 1);
+}
+
+int __kprobes register_kprobes(struct kprobe **kps, int num)
+{
+ return __register_kprobes(kps, num,
+ (unsigned long)__builtin_return_address(0));
+}
+
+void __kprobes unregister_kprobes(struct kprobe **kps, int num)
+{
+ int i;
+
+ if (num <= 0)
+ return;
+ mutex_lock(&kprobe_mutex);
+ for (i = 0; i < num; i++)
+ if (__unregister_kprobe_top(kps[i]) < 0)
+ kps[i]->addr = NULL;
+ mutex_unlock(&kprobe_mutex);
+
+ synchronize_sched();
+ for (i = 0; i < num; i++)
+ if (kps[i]->addr)
+ __unregister_kprobe_bottom(kps[i]);
}
static struct notifier_block kprobe_exceptions_nb = {
@@ -667,24 +755,69 @@ unsigned long __weak arch_deref_entry_point(void *entry)
return (unsigned long)entry;
}
-int __kprobes register_jprobe(struct jprobe *jp)
+static int __register_jprobes(struct jprobe **jps, int num,
+ unsigned long called_from)
{
- unsigned long addr = arch_deref_entry_point(jp->entry);
+ struct jprobe *jp;
+ int ret = 0, i;
- if (!kernel_text_address(addr))
+ if (num <= 0)
return -EINVAL;
+ for (i = 0; i < num; i++) {
+ unsigned long addr;
+ jp = jps[i];
+ addr = arch_deref_entry_point(jp->entry);
+
+ if (!kernel_text_address(addr))
+ ret = -EINVAL;
+ else {
+ /* Todo: Verify probepoint is a function entry point */
+ jp->kp.pre_handler = setjmp_pre_handler;
+ jp->kp.break_handler = longjmp_break_handler;
+ ret = __register_kprobe(&jp->kp, called_from);
+ }
+ if (ret < 0 && i > 0) {
+ unregister_jprobes(jps, i);
+ break;
+ }
+ }
+ return ret;
+}
- /* Todo: Verify probepoint is a function entry point */
- jp->kp.pre_handler = setjmp_pre_handler;
- jp->kp.break_handler = longjmp_break_handler;
-
- return __register_kprobe(&jp->kp,
+int __kprobes register_jprobe(struct jprobe *jp)
+{
+ return __register_jprobes(&jp, 1,
(unsigned long)__builtin_return_address(0));
}
void __kprobes unregister_jprobe(struct jprobe *jp)
{
- unregister_kprobe(&jp->kp);
+ unregister_jprobes(&jp, 1);
+}
+
+int __kprobes register_jprobes(struct jprobe **jps, int num)
+{
+ return __register_jprobes(jps, num,
+ (unsigned long)__builtin_return_address(0));
+}
+
+void __kprobes unregister_jprobes(struct jprobe **jps, int num)
+{
+ int i;
+
+ if (num <= 0)
+ return;
+ mutex_lock(&kprobe_mutex);
+ for (i = 0; i < num; i++)
+ if (__unregister_kprobe_top(&jps[i]->kp) < 0)
+ jps[i]->kp.addr = NULL;
+ mutex_unlock(&kprobe_mutex);
+
+ synchronize_sched();
+ for (i = 0; i < num; i++) {
+ if (jps[i]->kp.addr)
+ __unregister_kprobe_bottom(&jps[i]->kp);
+ }
}
#ifdef CONFIG_KRETPROBES
@@ -725,7 +858,8 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
return 0;
}
-int __kprobes register_kretprobe(struct kretprobe *rp)
+static int __kprobes __register_kretprobe(struct kretprobe *rp,
+ unsigned long called_from)
{
int ret = 0;
struct kretprobe_instance *inst;
@@ -771,46 +905,101 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
rp->nmissed = 0;
/* Establish function entry probe point */
- if ((ret = __register_kprobe(&rp->kp,
- (unsigned long)__builtin_return_address(0))) != 0)
+ ret = __register_kprobe(&rp->kp, called_from);
+ if (ret != 0)
free_rp_inst(rp);
return ret;
}
+static int __register_kretprobes(struct kretprobe **rps, int num,
+ unsigned long called_from)
+{
+ int ret = 0, i;
+
+ if (num <= 0)
+ return -EINVAL;
+ for (i = 0; i < num; i++) {
+ ret = __register_kretprobe(rps[i], called_from);
+ if (ret < 0 && i > 0) {
+ unregister_kretprobes(rps, i);
+ break;
+ }
+ }
+ return ret;
+}
+
+int __kprobes register_kretprobe(struct kretprobe *rp)
+{
+ return __register_kretprobes(&rp, 1,
+ (unsigned long)__builtin_return_address(0));
+}
+
+void __kprobes unregister_kretprobe(struct kretprobe *rp)
+{
+ unregister_kretprobes(&rp, 1);
+}
+
+int __kprobes register_kretprobes(struct kretprobe **rps, int num)
+{
+ return __register_kretprobes(rps, num,
+ (unsigned long)__builtin_return_address(0));
+}
+
+void __kprobes unregister_kretprobes(struct kretprobe **rps, int num)
+{
+ int i;
+
+ if (num <= 0)
+ return;
+ mutex_lock(&kprobe_mutex);
+ for (i = 0; i < num; i++)
+ if (__unregister_kprobe_top(&rps[i]->kp) < 0)
+ rps[i]->kp.addr = NULL;
+ mutex_unlock(&kprobe_mutex);
+
+ synchronize_sched();
+ for (i = 0; i < num; i++) {
+ if (rps[i]->kp.addr) {
+ __unregister_kprobe_bottom(&rps[i]->kp);
+ cleanup_rp_inst(rps[i]);
+ }
+ }
+}
+
#else /* CONFIG_KRETPROBES */
int __kprobes register_kretprobe(struct kretprobe *rp)
{
return -ENOSYS;
}
-static int __kprobes pre_handler_kretprobe(struct kprobe *p,
- struct pt_regs *regs)
+int __kprobes register_kretprobes(struct kretprobe **rps, int num)
{
- return 0;
+ return -ENOSYS;
}
-#endif /* CONFIG_KRETPROBES */
-
void __kprobes unregister_kretprobe(struct kretprobe *rp)
{
- unsigned long flags;
- struct kretprobe_instance *ri;
- struct hlist_node *pos, *next;
+}
- unregister_kprobe(&rp->kp);
+void __kprobes unregister_kretprobes(struct kretprobe **rps, int num)
+{
+}
- /* No race here */
- spin_lock_irqsave(&kretprobe_lock, flags);
- hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) {
- ri->rp = NULL;
- hlist_del(&ri->uflist);
- }
- spin_unlock_irqrestore(&kretprobe_lock, flags);
- free_rp_inst(rp);
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+ struct pt_regs *regs)
+{
+ return 0;
}
+#endif /* CONFIG_KRETPROBES */
+
static int __init init_kprobes(void)
{
int i, err = 0;
+ unsigned long offset = 0, size = 0;
+ char *modname, namebuf[128];
+ const char *symbol_name;
+ void *addr;
+ struct kprobe_blackpoint *kb;
/* FIXME allocate the probe table, currently defined statically */
/* initialize all list heads */
@@ -819,6 +1008,28 @@ static int __init init_kprobes(void)
INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
}
+ /*
+ * Lookup and populate the kprobe_blacklist.
+ *
+ * Unlike the kretprobe blacklist, we'll need to determine
+ * the range of addresses that belong to the said functions,
+ * since a kprobe need not necessarily be at the beginning
+ * of a function.
+ */
+ for (kb = kprobe_blacklist; kb->name != NULL; kb++) {
+ kprobe_lookup_name(kb->name, addr);
+ if (!addr)
+ continue;
+
+ kb->start_addr = (unsigned long)addr;
+ symbol_name = kallsyms_lookup(kb->start_addr,
+ &size, &offset, &modname, namebuf);
+ if (!symbol_name)
+ kb->range = 0;
+ else
+ kb->range = size;
+ }
+
if (kretprobe_blacklist_size) {
/* lookup the function address from its name */
for (i = 0; kretprobe_blacklist[i].name != NULL; i++) {
@@ -1066,8 +1277,12 @@ module_init(init_kprobes);
EXPORT_SYMBOL_GPL(register_kprobe);
EXPORT_SYMBOL_GPL(unregister_kprobe);
+EXPORT_SYMBOL_GPL(register_kprobes);
+EXPORT_SYMBOL_GPL(unregister_kprobes);
EXPORT_SYMBOL_GPL(register_jprobe);
EXPORT_SYMBOL_GPL(unregister_jprobe);
+EXPORT_SYMBOL_GPL(register_jprobes);
+EXPORT_SYMBOL_GPL(unregister_jprobes);
#ifdef CONFIG_KPROBES
EXPORT_SYMBOL_GPL(jprobe_return);
#endif
@@ -1075,4 +1290,6 @@ EXPORT_SYMBOL_GPL(jprobe_return);
#ifdef CONFIG_KPROBES
EXPORT_SYMBOL_GPL(register_kretprobe);
EXPORT_SYMBOL_GPL(unregister_kretprobe);
+EXPORT_SYMBOL_GPL(register_kretprobes);
+EXPORT_SYMBOL_GPL(unregister_kretprobes);
#endif
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 6d792b66d854..5ca37fa50beb 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -92,7 +92,7 @@ static struct pid_namespace *create_pid_namespace(int level)
atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1);
for (i = 1; i < PIDMAP_ENTRIES; i++) {
- ns->pidmap[i].page = 0;
+ ns->pidmap[i].page = NULL;
atomic_set(&ns->pidmap[i].nr_free, BITS_PER_PAGE);
}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6233f3b4ae66..b45da40e8d25 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -19,16 +19,6 @@ config PM
will issue the hlt instruction if nothing is to be done, thereby
sending the processor to sleep and saving power.
-config PM_LEGACY
- bool "Legacy Power Management API (DEPRECATED)"
- depends on PM
- default n
- ---help---
- Support for pm_register() and friends. This old API is obsoleted
- by the driver model.
-
- If unsure, say N.
-
config PM_DEBUG
bool "Power Management Debug Support"
depends on PM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index f7dfff28ecdb..597823b5b700 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -4,7 +4,6 @@ EXTRA_CFLAGS += -DDEBUG
endif
obj-y := main.o
-obj-$(CONFIG_PM_LEGACY) += pm.o
obj-$(CONFIG_PM_SLEEP) += process.o console.o
obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o
diff --git a/kernel/power/console.c b/kernel/power/console.c
index 89bcf4973ee5..b8628be2a465 100644
--- a/kernel/power/console.c
+++ b/kernel/power/console.c
@@ -7,17 +7,39 @@
#include <linux/vt_kern.h>
#include <linux/kbd_kern.h>
#include <linux/console.h>
+#include <linux/module.h>
#include "power.h"
#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
static int orig_fgconsole, orig_kmsg;
+static int disable_vt_switch;
+
+/*
+ * Normally during a suspend, we allocate a new console and switch to it.
+ * When we resume, we switch back to the original console. This switch
+ * can be slow, so on systems where the framebuffer can handle restoration
+ * of video registers anyways, there's little point in doing the console
+ * switch. This function allows you to disable it by passing it '0'.
+ */
+void pm_set_vt_switch(int do_switch)
+{
+ acquire_console_sem();
+ disable_vt_switch = !do_switch;
+ release_console_sem();
+}
+EXPORT_SYMBOL(pm_set_vt_switch);
int pm_prepare_console(void)
{
acquire_console_sem();
+ if (disable_vt_switch) {
+ release_console_sem();
+ return 0;
+ }
+
orig_fgconsole = fg_console;
if (vc_allocate(SUSPEND_CONSOLE)) {
@@ -50,9 +72,12 @@ int pm_prepare_console(void)
void pm_restore_console(void)
{
acquire_console_sem();
+ if (disable_vt_switch) {
+ release_console_sem();
+ return;
+ }
set_console(orig_fgconsole);
release_console_sem();
kmsg_redirect = orig_kmsg;
- return;
}
#endif
diff --git a/kernel/power/pm.c b/kernel/power/pm.c
deleted file mode 100644
index 60c73fa670d5..000000000000
--- a/kernel/power/pm.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * pm.c - Power management interface
- *
- * Copyright (C) 2000 Andrew Henroid
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-/*
- * Locking notes:
- * pm_devs_lock can be a semaphore providing pm ops are not called
- * from an interrupt handler (already a bad idea so no change here). Each
- * change must be protected so that an unlink of an entry doesn't clash
- * with a pm send - which is permitted to sleep in the current architecture
- *
- * Module unloads clashing with pm events now work out safely, the module
- * unload path will block until the event has been sent. It may well block
- * until a resume but that will be fine.
- */
-
-static DEFINE_MUTEX(pm_devs_lock);
-static LIST_HEAD(pm_devs);
-
-/**
- * pm_register - register a device with power management
- * @type: device type
- * @id: device ID
- * @callback: callback function
- *
- * Add a device to the list of devices that wish to be notified about
- * power management events. A &pm_dev structure is returned on success,
- * on failure the return is %NULL.
- *
- * The callback function will be called in process context and
- * it may sleep.
- */
-
-struct pm_dev *pm_register(pm_dev_t type,
- unsigned long id,
- pm_callback callback)
-{
- struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL);
- if (dev) {
- dev->type = type;
- dev->id = id;
- dev->callback = callback;
-
- mutex_lock(&pm_devs_lock);
- list_add(&dev->entry, &pm_devs);
- mutex_unlock(&pm_devs_lock);
- }
- return dev;
-}
-
-/**
- * pm_send - send request to a single device
- * @dev: device to send to
- * @rqst: power management request
- * @data: data for the callback
- *
- * Issue a power management request to a given device. The
- * %PM_SUSPEND and %PM_RESUME events are handled specially. The
- * data field must hold the intended next state. No call is made
- * if the state matches.
- *
- * BUGS: what stops two power management requests occurring in parallel
- * and conflicting.
- *
- * WARNING: Calling pm_send directly is not generally recommended, in
- * particular there is no locking against the pm_dev going away. The
- * caller must maintain all needed locking or have 'inside knowledge'
- * on the safety. Also remember that this function is not locked against
- * pm_unregister. This means that you must handle SMP races on callback
- * execution and unload yourself.
- */
-
-static int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- int status = 0;
- unsigned long prev_state, next_state;
-
- if (in_interrupt())
- BUG();
-
- switch (rqst) {
- case PM_SUSPEND:
- case PM_RESUME:
- prev_state = dev->state;
- next_state = (unsigned long) data;
- if (prev_state != next_state) {
- if (dev->callback)
- status = (*dev->callback)(dev, rqst, data);
- if (!status) {
- dev->state = next_state;
- dev->prev_state = prev_state;
- }
- }
- else {
- dev->prev_state = prev_state;
- }
- break;
- default:
- if (dev->callback)
- status = (*dev->callback)(dev, rqst, data);
- break;
- }
- return status;
-}
-
-/*
- * Undo incomplete request
- */
-static void pm_undo_all(struct pm_dev *last)
-{
- struct list_head *entry = last->entry.prev;
- while (entry != &pm_devs) {
- struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
- if (dev->state != dev->prev_state) {
- /* previous state was zero (running) resume or
- * previous state was non-zero (suspended) suspend
- */
- pm_request_t undo = (dev->prev_state
- ? PM_SUSPEND:PM_RESUME);
- pm_send(dev, undo, (void*) dev->prev_state);
- }
- entry = entry->prev;
- }
-}
-
-/**
- * pm_send_all - send request to all managed devices
- * @rqst: power management request
- * @data: data for the callback
- *
- * Issue a power management request to a all devices. The
- * %PM_SUSPEND events are handled specially. Any device is
- * permitted to fail a suspend by returning a non zero (error)
- * value from its callback function. If any device vetoes a
- * suspend request then all other devices that have suspended
- * during the processing of this request are restored to their
- * previous state.
- *
- * WARNING: This function takes the pm_devs_lock. The lock is not dropped until
- * the callbacks have completed. This prevents races against pm locking
- * functions, races against module unload pm_unregister code. It does
- * mean however that you must not issue pm_ functions within the callback
- * or you will deadlock and users will hate you.
- *
- * Zero is returned on success. If a suspend fails then the status
- * from the device that vetoes the suspend is returned.
- *
- * BUGS: what stops two power management requests occurring in parallel
- * and conflicting.
- */
-
-int pm_send_all(pm_request_t rqst, void *data)
-{
- struct list_head *entry;
-
- mutex_lock(&pm_devs_lock);
- entry = pm_devs.next;
- while (entry != &pm_devs) {
- struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
- if (dev->callback) {
- int status = pm_send(dev, rqst, data);
- if (status) {
- /* return devices to previous state on
- * failed suspend request
- */
- if (rqst == PM_SUSPEND)
- pm_undo_all(dev);
- mutex_unlock(&pm_devs_lock);
- return status;
- }
- }
- entry = entry->next;
- }
- mutex_unlock(&pm_devs_lock);
- return 0;
-}
-
-EXPORT_SYMBOL(pm_register);
-EXPORT_SYMBOL(pm_send_all);
-
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 67e392ed5496..dac4b4e57293 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -612,7 +612,7 @@ int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data)
return (copied == sizeof(data)) ? 0 : -EIO;
}
-#ifdef CONFIG_COMPAT
+#if defined CONFIG_COMPAT && defined __ARCH_WANT_COMPAT_SYS_PTRACE
#include <linux/compat.h>
int compat_ptrace_request(struct task_struct *child, compat_long_t request,
@@ -667,7 +667,6 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
return ret;
}
-#ifdef __ARCH_WANT_COMPAT_SYS_PTRACE
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
compat_long_t addr, compat_long_t data)
{
@@ -710,6 +709,4 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
unlock_kernel();
return ret;
}
-#endif /* __ARCH_WANT_COMPAT_SYS_PTRACE */
-
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_COMPAT && __ARCH_WANT_COMPAT_SYS_PTRACE */
diff --git a/kernel/sched.c b/kernel/sched.c
index 0014b03adaca..740fb409e5bb 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1657,42 +1657,6 @@ void aggregate_group_weight(struct task_group *tg, struct sched_domain *sd)
}
/*
- * Redistribute tg->shares amongst all tg->cfs_rq[]s.
- */
-static void __aggregate_redistribute_shares(struct task_group *tg)
-{
- int i, max_cpu = smp_processor_id();
- unsigned long rq_weight = 0;
- unsigned long shares, max_shares = 0, shares_rem = tg->shares;
-
- for_each_possible_cpu(i)
- rq_weight += tg->cfs_rq[i]->load.weight;
-
- for_each_possible_cpu(i) {
- /*
- * divide shares proportional to the rq_weights.
- */
- shares = tg->shares * tg->cfs_rq[i]->load.weight;
- shares /= rq_weight + 1;
-
- tg->cfs_rq[i]->shares = shares;
-
- if (shares > max_shares) {
- max_shares = shares;
- max_cpu = i;
- }
- shares_rem -= shares;
- }
-
- /*
- * Ensure it all adds up to tg->shares; we can loose a few
- * due to rounding down when computing the per-cpu shares.
- */
- if (shares_rem)
- tg->cfs_rq[max_cpu]->shares += shares_rem;
-}
-
-/*
* Compute the weight of this group on the given cpus.
*/
static
@@ -1701,18 +1665,11 @@ void aggregate_group_shares(struct task_group *tg, struct sched_domain *sd)
unsigned long shares = 0;
int i;
-again:
for_each_cpu_mask(i, sd->span)
shares += tg->cfs_rq[i]->shares;
- /*
- * When the span doesn't have any shares assigned, but does have
- * tasks to run do a machine wide rebalance (should be rare).
- */
- if (unlikely(!shares && aggregate(tg, sd)->rq_weight)) {
- __aggregate_redistribute_shares(tg);
- goto again;
- }
+ if ((!shares && aggregate(tg, sd)->rq_weight) || shares > tg->shares)
+ shares = tg->shares;
aggregate(tg, sd)->shares = shares;
}
@@ -7991,11 +7948,6 @@ void __init sched_init_smp(void)
#else
void __init sched_init_smp(void)
{
-#if defined(CONFIG_NUMA)
- sched_group_nodes_bycpu = kzalloc(nr_cpu_ids * sizeof(void **),
- GFP_KERNEL);
- BUG_ON(sched_group_nodes_bycpu == NULL);
-#endif
sched_init_granularity();
}
#endif /* CONFIG_SMP */
@@ -8128,7 +8080,7 @@ void __init sched_init(void)
* we use alloc_bootmem().
*/
if (alloc_size) {
- ptr = (unsigned long)alloc_bootmem_low(alloc_size);
+ ptr = (unsigned long)alloc_bootmem(alloc_size);
#ifdef CONFIG_FAIR_GROUP_SCHED
init_task_group.se = (struct sched_entity **)ptr;
diff --git a/kernel/sys.c b/kernel/sys.c
index 6a0cc71ee88d..f2a451366953 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1632,10 +1632,9 @@ asmlinkage long sys_umask(int mask)
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
- long error;
+ long uninitialized_var(error);
- error = security_task_prctl(option, arg2, arg3, arg4, arg5);
- if (error)
+ if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
return error;
switch (option) {
@@ -1688,17 +1687,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = -EINVAL;
break;
- case PR_GET_KEEPCAPS:
- if (current->keep_capabilities)
- error = 1;
- break;
- case PR_SET_KEEPCAPS:
- if (arg2 != 0 && arg2 != 1) {
- error = -EINVAL;
- break;
- }
- current->keep_capabilities = arg2;
- break;
case PR_SET_NAME: {
struct task_struct *me = current;
unsigned char ncomm[sizeof(me->comm)];
@@ -1732,17 +1720,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
case PR_SET_SECCOMP:
error = prctl_set_seccomp(arg2);
break;
-
- case PR_CAPBSET_READ:
- if (!cap_valid(arg2))
- return -EINVAL;
- return !!cap_raised(current->cap_bset, arg2);
- case PR_CAPBSET_DROP:
-#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
- return cap_prctl_drop(arg2);
-#else
- return -EINVAL;
-#endif
case PR_GET_TSC:
error = GET_TSC_CTL(arg2);
break;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d358d4e3a958..b854a895591e 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -393,6 +393,7 @@ void tick_nohz_restart_sched_tick(void)
sub_preempt_count(HARDIRQ_OFFSET);
}
+ touch_softlockup_watchdog();
/*
* Cancel the scheduled timer and restore the tick
*/
diff --git a/lib/Kconfig b/lib/Kconfig
index 2d53dc092e8b..8cc8e8722a3f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -7,6 +7,12 @@ menu "Library routines"
config BITREVERSE
tristate
+config GENERIC_FIND_FIRST_BIT
+ def_bool n
+
+config GENERIC_FIND_NEXT_BIT
+ def_bool n
+
config CRC_CCITT
tristate "CRC-CCITT functions"
help
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 623ef24c2381..754cc0027f2a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -25,6 +25,17 @@ config ENABLE_MUST_CHECK
suppress the "warning: ignoring return value of 'foo', declared with
attribute warn_unused_result" messages.
+config FRAME_WARN
+ int "Warn for stack frames larger than (needs gcc 4.4)"
+ range 0 8192
+ default 1024 if !64BIT
+ default 2048 if 64BIT
+ help
+ Tell gcc to warn at build time for stack frames larger than this.
+ Setting this too low will cause a lot of warnings.
+ Setting it to 0 disables the warning.
+ Requires gcc 4.4
+
config MAGIC_SYSRQ
bool "Magic SysRq key"
depends on !UML
diff --git a/lib/Makefile b/lib/Makefile
index bf8000fc7d48..2d7001b7f5a4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
diff --git a/lib/bitmap.c b/lib/bitmap.c
index a6939e18d7bb..c4cb48f77f0c 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -714,6 +714,164 @@ int bitmap_bitremap(int oldbit, const unsigned long *old,
}
EXPORT_SYMBOL(bitmap_bitremap);
+/**
+ * bitmap_onto - translate one bitmap relative to another
+ * @dst: resulting translated bitmap
+ * @orig: original untranslated bitmap
+ * @relmap: bitmap relative to which translated
+ * @bits: number of bits in each of these bitmaps
+ *
+ * Set the n-th bit of @dst iff there exists some m such that the
+ * n-th bit of @relmap is set, the m-th bit of @orig is set, and
+ * the n-th bit of @relmap is also the m-th _set_ bit of @relmap.
+ * (If you understood the previous sentence the first time your
+ * read it, you're overqualified for your current job.)
+ *
+ * In other words, @orig is mapped onto (surjectively) @dst,
+ * using the the map { <n, m> | the n-th bit of @relmap is the
+ * m-th set bit of @relmap }.
+ *
+ * Any set bits in @orig above bit number W, where W is the
+ * weight of (number of set bits in) @relmap are mapped nowhere.
+ * In particular, if for all bits m set in @orig, m >= W, then
+ * @dst will end up empty. In situations where the possibility
+ * of such an empty result is not desired, one way to avoid it is
+ * to use the bitmap_fold() operator, below, to first fold the
+ * @orig bitmap over itself so that all its set bits x are in the
+ * range 0 <= x < W. The bitmap_fold() operator does this by
+ * setting the bit (m % W) in @dst, for each bit (m) set in @orig.
+ *
+ * Example [1] for bitmap_onto():
+ * Let's say @relmap has bits 30-39 set, and @orig has bits
+ * 1, 3, 5, 7, 9 and 11 set. Then on return from this routine,
+ * @dst will have bits 31, 33, 35, 37 and 39 set.
+ *
+ * When bit 0 is set in @orig, it means turn on the bit in
+ * @dst corresponding to whatever is the first bit (if any)
+ * that is turned on in @relmap. Since bit 0 was off in the
+ * above example, we leave off that bit (bit 30) in @dst.
+ *
+ * When bit 1 is set in @orig (as in the above example), it
+ * means turn on the bit in @dst corresponding to whatever
+ * is the second bit that is turned on in @relmap. The second
+ * bit in @relmap that was turned on in the above example was
+ * bit 31, so we turned on bit 31 in @dst.
+ *
+ * Similarly, we turned on bits 33, 35, 37 and 39 in @dst,
+ * because they were the 4th, 6th, 8th and 10th set bits
+ * set in @relmap, and the 4th, 6th, 8th and 10th bits of
+ * @orig (i.e. bits 3, 5, 7 and 9) were also set.
+ *
+ * When bit 11 is set in @orig, it means turn on the bit in
+ * @dst corresponding to whatever is the twelth bit that is
+ * turned on in @relmap. In the above example, there were
+ * only ten bits turned on in @relmap (30..39), so that bit
+ * 11 was set in @orig had no affect on @dst.
+ *
+ * Example [2] for bitmap_fold() + bitmap_onto():
+ * Let's say @relmap has these ten bits set:
+ * 40 41 42 43 45 48 53 61 74 95
+ * (for the curious, that's 40 plus the first ten terms of the
+ * Fibonacci sequence.)
+ *
+ * Further lets say we use the following code, invoking
+ * bitmap_fold() then bitmap_onto, as suggested above to
+ * avoid the possitility of an empty @dst result:
+ *
+ * unsigned long *tmp; // a temporary bitmap's bits
+ *
+ * bitmap_fold(tmp, orig, bitmap_weight(relmap, bits), bits);
+ * bitmap_onto(dst, tmp, relmap, bits);
+ *
+ * Then this table shows what various values of @dst would be, for
+ * various @orig's. I list the zero-based positions of each set bit.
+ * The tmp column shows the intermediate result, as computed by
+ * using bitmap_fold() to fold the @orig bitmap modulo ten
+ * (the weight of @relmap).
+ *
+ * @orig tmp @dst
+ * 0 0 40
+ * 1 1 41
+ * 9 9 95
+ * 10 0 40 (*)
+ * 1 3 5 7 1 3 5 7 41 43 48 61
+ * 0 1 2 3 4 0 1 2 3 4 40 41 42 43 45
+ * 0 9 18 27 0 9 8 7 40 61 74 95
+ * 0 10 20 30 0 40
+ * 0 11 22 33 0 1 2 3 40 41 42 43
+ * 0 12 24 36 0 2 4 6 40 42 45 53
+ * 78 102 211 1 2 8 41 42 74 (*)
+ *
+ * (*) For these marked lines, if we hadn't first done bitmap_fold()
+ * into tmp, then the @dst result would have been empty.
+ *
+ * If either of @orig or @relmap is empty (no set bits), then @dst
+ * will be returned empty.
+ *
+ * If (as explained above) the only set bits in @orig are in positions
+ * m where m >= W, (where W is the weight of @relmap) then @dst will
+ * once again be returned empty.
+ *
+ * All bits in @dst not set by the above rule are cleared.
+ */
+void bitmap_onto(unsigned long *dst, const unsigned long *orig,
+ const unsigned long *relmap, int bits)
+{
+ int n, m; /* same meaning as in above comment */
+
+ if (dst == orig) /* following doesn't handle inplace mappings */
+ return;
+ bitmap_zero(dst, bits);
+
+ /*
+ * The following code is a more efficient, but less
+ * obvious, equivalent to the loop:
+ * for (m = 0; m < bitmap_weight(relmap, bits); m++) {
+ * n = bitmap_ord_to_pos(orig, m, bits);
+ * if (test_bit(m, orig))
+ * set_bit(n, dst);
+ * }
+ */
+
+ m = 0;
+ for (n = find_first_bit(relmap, bits);
+ n < bits;
+ n = find_next_bit(relmap, bits, n + 1)) {
+ /* m == bitmap_pos_to_ord(relmap, n, bits) */
+ if (test_bit(m, orig))
+ set_bit(n, dst);
+ m++;
+ }
+}
+EXPORT_SYMBOL(bitmap_onto);
+
+/**
+ * bitmap_fold - fold larger bitmap into smaller, modulo specified size
+ * @dst: resulting smaller bitmap
+ * @orig: original larger bitmap
+ * @sz: specified size
+ * @bits: number of bits in each of these bitmaps
+ *
+ * For each bit oldbit in @orig, set bit oldbit mod @sz in @dst.
+ * Clear all other bits in @dst. See further the comment and
+ * Example [2] for bitmap_onto() for why and how to use this.
+ */
+void bitmap_fold(unsigned long *dst, const unsigned long *orig,
+ int sz, int bits)
+{
+ int oldbit;
+
+ if (dst == orig) /* following doesn't handle inplace mappings */
+ return;
+ bitmap_zero(dst, bits);
+
+ for (oldbit = find_first_bit(orig, bits);
+ oldbit < bits;
+ oldbit = find_next_bit(orig, bits, oldbit + 1))
+ set_bit(oldbit % sz, dst);
+}
+EXPORT_SYMBOL(bitmap_fold);
+
/*
* Common code for bitmap_*_region() routines.
* bitmap: array of unsigned longs corresponding to the bitmap
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c
index 78ccd73a8841..d3f5784807b4 100644
--- a/lib/find_next_bit.c
+++ b/lib/find_next_bit.c
@@ -16,14 +16,12 @@
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
+#ifdef CONFIG_GENERIC_FIND_NEXT_BIT
+/*
+ * Find the next set bit in a memory region.
*/
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
+unsigned long __find_next_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
@@ -60,15 +58,14 @@ found_first:
found_middle:
return result + __ffs(tmp);
}
-
-EXPORT_SYMBOL(find_next_bit);
+EXPORT_SYMBOL(__find_next_bit);
/*
* This implementation of find_{first,next}_zero_bit was stolen from
* Linus' asm-alpha/bitops.h.
*/
-unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
+unsigned long __find_next_zero_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
@@ -105,8 +102,64 @@ found_first:
found_middle:
return result + ffz(tmp);
}
+EXPORT_SYMBOL(__find_next_zero_bit);
+#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */
+
+#ifdef CONFIG_GENERIC_FIND_FIRST_BIT
+/*
+ * Find the first set bit in a memory region.
+ */
+unsigned long __find_first_bit(const unsigned long *addr,
+ unsigned long size)
+{
+ const unsigned long *p = addr;
+ unsigned long result = 0;
+ unsigned long tmp;
-EXPORT_SYMBOL(find_next_zero_bit);
+ while (size & ~(BITS_PER_LONG-1)) {
+ if ((tmp = *(p++)))
+ goto found;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+
+ tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found:
+ return result + __ffs(tmp);
+}
+EXPORT_SYMBOL(__find_first_bit);
+
+/*
+ * Find the first cleared bit in a memory region.
+ */
+unsigned long __find_first_zero_bit(const unsigned long *addr,
+ unsigned long size)
+{
+ const unsigned long *p = addr;
+ unsigned long result = 0;
+ unsigned long tmp;
+
+ while (size & ~(BITS_PER_LONG-1)) {
+ if (~(tmp = *(p++)))
+ goto found;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+
+ tmp = (*p) | (~0UL << size);
+ if (tmp == ~0UL) /* Are any bits zero? */
+ return result + size; /* Nope. */
+found:
+ return result + ffz(tmp);
+}
+EXPORT_SYMBOL(__find_first_zero_bit);
+#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
#ifdef __BIG_ENDIAN
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 65f0e758ec38..bd521716ab1a 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -114,8 +114,7 @@ radix_tree_node_alloc(struct radix_tree_root *root)
}
}
if (ret == NULL)
- ret = kmem_cache_alloc(radix_tree_node_cachep,
- set_migrateflags(gfp_mask, __GFP_RECLAIMABLE));
+ ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
BUG_ON(radix_tree_is_indirect_ptr(ret));
return ret;
@@ -150,8 +149,7 @@ int radix_tree_preload(gfp_t gfp_mask)
rtp = &__get_cpu_var(radix_tree_preloads);
while (rtp->nr < ARRAY_SIZE(rtp->nodes)) {
preempt_enable();
- node = kmem_cache_alloc(radix_tree_node_cachep,
- set_migrateflags(gfp_mask, __GFP_RECLAIMABLE));
+ node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
if (node == NULL)
goto out;
preempt_disable();
@@ -1098,7 +1096,8 @@ void __init radix_tree_init(void)
{
radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
sizeof(struct radix_tree_node), 0,
- SLAB_PANIC, radix_tree_node_ctor);
+ SLAB_PANIC | SLAB_RECLAIM_ACCOUNT,
+ radix_tree_node_ctor);
radix_tree_init_maxindex();
hotcpu_notifier(radix_tree_callback, 0);
}
diff --git a/mm/Kconfig b/mm/Kconfig
index 0016ebd4dcba..3aa819d628c1 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -143,6 +143,18 @@ config MEMORY_HOTREMOVE
depends on MEMORY_HOTPLUG && ARCH_ENABLE_MEMORY_HOTREMOVE
depends on MIGRATION
+#
+# If we have space for more page flags then we can enable additional
+# optimizations and functionality.
+#
+# Regular Sparsemem takes page flag bits for the sectionid if it does not
+# use a virtual memmap. Disable extended page flags for 32 bit platforms
+# that require the use of a sectionid in the page flags.
+#
+config PAGEFLAGS_EXTENDED
+ def_bool y
+ depends on 64BIT || SPARSEMEM_VMEMMAP || !NUMA || !SPARSEMEM
+
# Heavily threaded applications may benefit from splitting the mm-wide
# page_table_lock, so that faults on different parts of the user address
# space can be handled with less contention: split it at this NR_CPUS.
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 2ccea700968f..e8fb927392b9 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -111,44 +111,74 @@ static unsigned long __init init_bootmem_core(pg_data_t *pgdat,
* might be used for boot-time allocations - or it might get added
* to the free page pool later on.
*/
-static int __init reserve_bootmem_core(bootmem_data_t *bdata,
+static int __init can_reserve_bootmem_core(bootmem_data_t *bdata,
unsigned long addr, unsigned long size, int flags)
{
unsigned long sidx, eidx;
unsigned long i;
- int ret;
+
+ BUG_ON(!size);
+
+ /* out of range, don't hold other */
+ if (addr + size < bdata->node_boot_start ||
+ PFN_DOWN(addr) > bdata->node_low_pfn)
+ return 0;
/*
- * round up, partially reserved pages are considered
- * fully reserved.
+ * Round up to index to the range.
*/
+ if (addr > bdata->node_boot_start)
+ sidx= PFN_DOWN(addr - bdata->node_boot_start);
+ else
+ sidx = 0;
+
+ eidx = PFN_UP(addr + size - bdata->node_boot_start);
+ if (eidx > bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start))
+ eidx = bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start);
+
+ for (i = sidx; i < eidx; i++) {
+ if (test_bit(i, bdata->node_bootmem_map)) {
+ if (flags & BOOTMEM_EXCLUSIVE)
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+
+}
+
+static void __init reserve_bootmem_core(bootmem_data_t *bdata,
+ unsigned long addr, unsigned long size, int flags)
+{
+ unsigned long sidx, eidx;
+ unsigned long i;
+
BUG_ON(!size);
- BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn);
- BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn);
- BUG_ON(addr < bdata->node_boot_start);
- sidx = PFN_DOWN(addr - bdata->node_boot_start);
+ /* out of range */
+ if (addr + size < bdata->node_boot_start ||
+ PFN_DOWN(addr) > bdata->node_low_pfn)
+ return;
+
+ /*
+ * Round up to index to the range.
+ */
+ if (addr > bdata->node_boot_start)
+ sidx= PFN_DOWN(addr - bdata->node_boot_start);
+ else
+ sidx = 0;
+
eidx = PFN_UP(addr + size - bdata->node_boot_start);
+ if (eidx > bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start))
+ eidx = bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start);
- for (i = sidx; i < eidx; i++)
+ for (i = sidx; i < eidx; i++) {
if (test_and_set_bit(i, bdata->node_bootmem_map)) {
#ifdef CONFIG_DEBUG_BOOTMEM
printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
#endif
- if (flags & BOOTMEM_EXCLUSIVE) {
- ret = -EBUSY;
- goto err;
- }
}
-
- return 0;
-
-err:
- /* unreserve memory we accidentally reserved */
- for (i--; i >= sidx; i--)
- clear_bit(i, bdata->node_bootmem_map);
-
- return ret;
+ }
}
static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
@@ -206,9 +236,11 @@ void * __init
__alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
unsigned long align, unsigned long goal, unsigned long limit)
{
- unsigned long offset, remaining_size, areasize, preferred;
+ unsigned long areasize, preferred;
unsigned long i, start = 0, incr, eidx, end_pfn;
void *ret;
+ unsigned long node_boot_start;
+ void *node_bootmem_map;
if (!size) {
printk("__alloc_bootmem_core(): zero-sized request\n");
@@ -216,70 +248,83 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
}
BUG_ON(align & (align-1));
- if (limit && bdata->node_boot_start >= limit)
- return NULL;
-
/* on nodes without memory - bootmem_map is NULL */
if (!bdata->node_bootmem_map)
return NULL;
+ /* bdata->node_boot_start is supposed to be (12+6)bits alignment on x86_64 ? */
+ node_boot_start = bdata->node_boot_start;
+ node_bootmem_map = bdata->node_bootmem_map;
+ if (align) {
+ node_boot_start = ALIGN(bdata->node_boot_start, align);
+ if (node_boot_start > bdata->node_boot_start)
+ node_bootmem_map = (unsigned long *)bdata->node_bootmem_map +
+ PFN_DOWN(node_boot_start - bdata->node_boot_start)/BITS_PER_LONG;
+ }
+
+ if (limit && node_boot_start >= limit)
+ return NULL;
+
end_pfn = bdata->node_low_pfn;
limit = PFN_DOWN(limit);
if (limit && end_pfn > limit)
end_pfn = limit;
- eidx = end_pfn - PFN_DOWN(bdata->node_boot_start);
- offset = 0;
- if (align && (bdata->node_boot_start & (align - 1UL)) != 0)
- offset = align - (bdata->node_boot_start & (align - 1UL));
- offset = PFN_DOWN(offset);
+ eidx = end_pfn - PFN_DOWN(node_boot_start);
/*
* We try to allocate bootmem pages above 'goal'
* first, then we try to allocate lower pages.
*/
- if (goal && goal >= bdata->node_boot_start && PFN_DOWN(goal) < end_pfn) {
- preferred = goal - bdata->node_boot_start;
+ preferred = 0;
+ if (goal && PFN_DOWN(goal) < end_pfn) {
+ if (goal > node_boot_start)
+ preferred = goal - node_boot_start;
- if (bdata->last_success >= preferred)
+ if (bdata->last_success > node_boot_start &&
+ bdata->last_success - node_boot_start >= preferred)
if (!limit || (limit && limit > bdata->last_success))
- preferred = bdata->last_success;
- } else
- preferred = 0;
+ preferred = bdata->last_success - node_boot_start;
+ }
- preferred = PFN_DOWN(ALIGN(preferred, align)) + offset;
+ preferred = PFN_DOWN(ALIGN(preferred, align));
areasize = (size + PAGE_SIZE-1) / PAGE_SIZE;
incr = align >> PAGE_SHIFT ? : 1;
restart_scan:
- for (i = preferred; i < eidx; i += incr) {
+ for (i = preferred; i < eidx;) {
unsigned long j;
- i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i);
+
+ i = find_next_zero_bit(node_bootmem_map, eidx, i);
i = ALIGN(i, incr);
if (i >= eidx)
break;
- if (test_bit(i, bdata->node_bootmem_map))
+ if (test_bit(i, node_bootmem_map)) {
+ i += incr;
continue;
+ }
for (j = i + 1; j < i + areasize; ++j) {
if (j >= eidx)
goto fail_block;
- if (test_bit(j, bdata->node_bootmem_map))
+ if (test_bit(j, node_bootmem_map))
goto fail_block;
}
start = i;
goto found;
fail_block:
i = ALIGN(j, incr);
+ if (i == j)
+ i += incr;
}
- if (preferred > offset) {
- preferred = offset;
+ if (preferred > 0) {
+ preferred = 0;
goto restart_scan;
}
return NULL;
found:
- bdata->last_success = PFN_PHYS(start);
+ bdata->last_success = PFN_PHYS(start) + node_boot_start;
BUG_ON(start >= eidx);
/*
@@ -289,6 +334,7 @@ found:
*/
if (align < PAGE_SIZE &&
bdata->last_offset && bdata->last_pos+1 == start) {
+ unsigned long offset, remaining_size;
offset = ALIGN(bdata->last_offset, align);
BUG_ON(offset > PAGE_SIZE);
remaining_size = PAGE_SIZE - offset;
@@ -297,14 +343,12 @@ found:
/* last_pos unchanged */
bdata->last_offset = offset + size;
ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
- offset +
- bdata->node_boot_start);
+ offset + node_boot_start);
} else {
remaining_size = size - remaining_size;
areasize = (remaining_size + PAGE_SIZE-1) / PAGE_SIZE;
ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
- offset +
- bdata->node_boot_start);
+ offset + node_boot_start);
bdata->last_pos = start + areasize - 1;
bdata->last_offset = remaining_size;
}
@@ -312,14 +356,14 @@ found:
} else {
bdata->last_pos = start + areasize - 1;
bdata->last_offset = size & ~PAGE_MASK;
- ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);
+ ret = phys_to_virt(start * PAGE_SIZE + node_boot_start);
}
/*
* Reserve the area now:
*/
for (i = start; i < start + areasize; i++)
- if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
+ if (unlikely(test_and_set_bit(i, node_bootmem_map)))
BUG();
memset(ret, 0, size);
return ret;
@@ -401,6 +445,11 @@ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
unsigned long size, int flags)
{
+ int ret;
+
+ ret = can_reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
+ if (ret < 0)
+ return;
reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
}
@@ -412,6 +461,7 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
{
+ register_page_bootmem_info_node(pgdat);
return free_all_bootmem_core(pgdat);
}
@@ -426,7 +476,18 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
int __init reserve_bootmem(unsigned long addr, unsigned long size,
int flags)
{
- return reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size, flags);
+ bootmem_data_t *bdata;
+ int ret;
+
+ list_for_each_entry(bdata, &bdata_list, list) {
+ ret = can_reserve_bootmem_core(bdata, addr, size, flags);
+ if (ret < 0)
+ return ret;
+ }
+ list_for_each_entry(bdata, &bdata_list, list)
+ reserve_bootmem_core(bdata, addr, size, flags);
+
+ return 0;
}
#endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
@@ -484,6 +545,37 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
return __alloc_bootmem(size, align, goal);
}
+#ifdef CONFIG_SPARSEMEM
+void * __init alloc_bootmem_section(unsigned long size,
+ unsigned long section_nr)
+{
+ void *ptr;
+ unsigned long limit, goal, start_nr, end_nr, pfn;
+ struct pglist_data *pgdat;
+
+ pfn = section_nr_to_pfn(section_nr);
+ goal = PFN_PHYS(pfn);
+ limit = PFN_PHYS(section_nr_to_pfn(section_nr + 1)) - 1;
+ pgdat = NODE_DATA(early_pfn_to_nid(pfn));
+ ptr = __alloc_bootmem_core(pgdat->bdata, size, SMP_CACHE_BYTES, goal,
+ limit);
+
+ if (!ptr)
+ return NULL;
+
+ start_nr = pfn_to_section_nr(PFN_DOWN(__pa(ptr)));
+ end_nr = pfn_to_section_nr(PFN_DOWN(__pa(ptr) + size));
+ if (start_nr != section_nr || end_nr != section_nr) {
+ printk(KERN_WARNING "alloc_bootmem failed on section %ld.\n",
+ section_nr);
+ free_bootmem_core(pgdat->bdata, __pa(ptr), size);
+ ptr = NULL;
+ }
+
+ return ptr;
+}
+#endif
+
#ifndef ARCH_LOW_ADDRESS_LIMIT
#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
#endif
diff --git a/mm/dmapool.c b/mm/dmapool.c
index 34aaac451a96..b1f0885dda22 100644
--- a/mm/dmapool.c
+++ b/mm/dmapool.c
@@ -37,6 +37,10 @@
#include <linux/types.h>
#include <linux/wait.h>
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB_DEBUG_ON)
+#define DMAPOOL_DEBUG 1
+#endif
+
struct dma_pool { /* the pool */
struct list_head page_list;
spinlock_t lock;
@@ -216,7 +220,7 @@ static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)
page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation,
&page->dma, mem_flags);
if (page->vaddr) {
-#ifdef CONFIG_DEBUG_SLAB
+#ifdef DMAPOOL_DEBUG
memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
#endif
pool_initialise_page(pool, page);
@@ -239,7 +243,7 @@ static void pool_free_page(struct dma_pool *pool, struct dma_page *page)
{
dma_addr_t dma = page->dma;
-#ifdef CONFIG_DEBUG_SLAB
+#ifdef DMAPOOL_DEBUG
memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
#endif
dma_free_coherent(pool->dev, pool->allocation, page->vaddr, dma);
@@ -336,7 +340,7 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
page->offset = *(int *)(page->vaddr + offset);
retval = offset + page->vaddr;
*handle = offset + page->dma;
-#ifdef CONFIG_DEBUG_SLAB
+#ifdef DMAPOOL_DEBUG
memset(retval, POOL_POISON_ALLOCATED, pool->size);
#endif
done:
@@ -391,7 +395,7 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
}
offset = vaddr - page->vaddr;
-#ifdef CONFIG_DEBUG_SLAB
+#ifdef DMAPOOL_DEBUG
if ((dma - page->dma) != offset) {
if (pool->dev)
dev_err(pool->dev,
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 3c0f1e99f5e4..343cfdfebd9e 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -49,7 +49,7 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
goto out;
}
- if (mapping->a_ops->get_xip_page) {
+ if (mapping->a_ops->get_xip_mem) {
switch (advice) {
case POSIX_FADV_NORMAL:
case POSIX_FADV_RANDOM:
diff --git a/mm/filemap.c b/mm/filemap.c
index 07e9d9258b48..239d36163bbe 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -576,10 +576,12 @@ EXPORT_SYMBOL(unlock_page);
*/
void end_page_writeback(struct page *page)
{
- if (!TestClearPageReclaim(page) || rotate_reclaimable_page(page)) {
- if (!test_clear_page_writeback(page))
- BUG();
- }
+ if (TestClearPageReclaim(page))
+ rotate_reclaimable_page(page);
+
+ if (!test_clear_page_writeback(page))
+ BUG();
+
smp_mb__after_clear_bit();
wake_up_page(page, PG_writeback);
}
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index 5e598c42afd7..3e744abcce9d 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -15,6 +15,7 @@
#include <linux/rmap.h>
#include <linux/sched.h>
#include <asm/tlbflush.h>
+#include <asm/io.h>
/*
* We do use our own empty page to avoid interference with other users
@@ -42,37 +43,41 @@ static struct page *xip_sparse_page(void)
/*
* This is a file read routine for execute in place files, and uses
- * the mapping->a_ops->get_xip_page() function for the actual low-level
+ * the mapping->a_ops->get_xip_mem() function for the actual low-level
* stuff.
*
* Note the struct file* is not used at all. It may be NULL.
*/
-static void
+static ssize_t
do_xip_mapping_read(struct address_space *mapping,
struct file_ra_state *_ra,
struct file *filp,
- loff_t *ppos,
- read_descriptor_t *desc,
- read_actor_t actor)
+ char __user *buf,
+ size_t len,
+ loff_t *ppos)
{
struct inode *inode = mapping->host;
pgoff_t index, end_index;
unsigned long offset;
- loff_t isize;
+ loff_t isize, pos;
+ size_t copied = 0, error = 0;
- BUG_ON(!mapping->a_ops->get_xip_page);
+ BUG_ON(!mapping->a_ops->get_xip_mem);
- index = *ppos >> PAGE_CACHE_SHIFT;
- offset = *ppos & ~PAGE_CACHE_MASK;
+ pos = *ppos;
+ index = pos >> PAGE_CACHE_SHIFT;
+ offset = pos & ~PAGE_CACHE_MASK;
isize = i_size_read(inode);
if (!isize)
goto out;
end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
- for (;;) {
- struct page *page;
- unsigned long nr, ret;
+ do {
+ unsigned long nr, left;
+ void *xip_mem;
+ unsigned long xip_pfn;
+ int zero = 0;
/* nr is the maximum number of bytes to copy from this page */
nr = PAGE_CACHE_SIZE;
@@ -85,19 +90,17 @@ do_xip_mapping_read(struct address_space *mapping,
}
}
nr = nr - offset;
+ if (nr > len)
+ nr = len;
- page = mapping->a_ops->get_xip_page(mapping,
- index*(PAGE_SIZE/512), 0);
- if (!page)
- goto no_xip_page;
- if (unlikely(IS_ERR(page))) {
- if (PTR_ERR(page) == -ENODATA) {
+ error = mapping->a_ops->get_xip_mem(mapping, index, 0,
+ &xip_mem, &xip_pfn);
+ if (unlikely(error)) {
+ if (error == -ENODATA) {
/* sparse */
- page = ZERO_PAGE(0);
- } else {
- desc->error = PTR_ERR(page);
+ zero = 1;
+ } else
goto out;
- }
}
/* If users can be writing to this page using arbitrary
@@ -105,10 +108,10 @@ do_xip_mapping_read(struct address_space *mapping,
* before reading the page on the kernel side.
*/
if (mapping_writably_mapped(mapping))
- flush_dcache_page(page);
+ /* address based flush */ ;
/*
- * Ok, we have the page, so now we can copy it to user space...
+ * Ok, we have the mem, so now we can copy it to user space...
*
* The actor routine returns how many bytes were actually used..
* NOTE! This may not be the same as how much of a user buffer
@@ -116,47 +119,38 @@ do_xip_mapping_read(struct address_space *mapping,
* "pos" here (the actor routine has to update the user buffer
* pointers and the remaining count).
*/
- ret = actor(desc, page, offset, nr);
- offset += ret;
- index += offset >> PAGE_CACHE_SHIFT;
- offset &= ~PAGE_CACHE_MASK;
+ if (!zero)
+ left = __copy_to_user(buf+copied, xip_mem+offset, nr);
+ else
+ left = __clear_user(buf + copied, nr);
- if (ret == nr && desc->count)
- continue;
- goto out;
+ if (left) {
+ error = -EFAULT;
+ goto out;
+ }
-no_xip_page:
- /* Did not get the page. Report it */
- desc->error = -EIO;
- goto out;
- }
+ copied += (nr - left);
+ offset += (nr - left);
+ index += offset >> PAGE_CACHE_SHIFT;
+ offset &= ~PAGE_CACHE_MASK;
+ } while (copied < len);
out:
- *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
+ *ppos = pos + copied;
if (filp)
file_accessed(filp);
+
+ return (copied ? copied : error);
}
ssize_t
xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
- read_descriptor_t desc;
-
if (!access_ok(VERIFY_WRITE, buf, len))
return -EFAULT;
- desc.written = 0;
- desc.arg.buf = buf;
- desc.count = len;
- desc.error = 0;
-
- do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
- ppos, &desc, file_read_actor);
-
- if (desc.written)
- return desc.written;
- else
- return desc.error;
+ return do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
+ buf, len, ppos);
}
EXPORT_SYMBOL_GPL(xip_file_read);
@@ -211,13 +205,16 @@ __xip_unmap (struct address_space * mapping,
*
* This function is derived from filemap_fault, but used for execute in place
*/
-static int xip_file_fault(struct vm_area_struct *area, struct vm_fault *vmf)
+static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- struct file *file = area->vm_file;
+ struct file *file = vma->vm_file;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
- struct page *page;
pgoff_t size;
+ void *xip_mem;
+ unsigned long xip_pfn;
+ struct page *page;
+ int error;
/* XXX: are VM_FAULT_ codes OK? */
@@ -225,35 +222,44 @@ static int xip_file_fault(struct vm_area_struct *area, struct vm_fault *vmf)
if (vmf->pgoff >= size)
return VM_FAULT_SIGBUS;
- page = mapping->a_ops->get_xip_page(mapping,
- vmf->pgoff*(PAGE_SIZE/512), 0);
- if (!IS_ERR(page))
- goto out;
- if (PTR_ERR(page) != -ENODATA)
+ error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 0,
+ &xip_mem, &xip_pfn);
+ if (likely(!error))
+ goto found;
+ if (error != -ENODATA)
return VM_FAULT_OOM;
/* sparse block */
- if ((area->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
- (area->vm_flags & (VM_SHARED| VM_MAYSHARE)) &&
+ if ((vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
+ (vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) &&
(!(mapping->host->i_sb->s_flags & MS_RDONLY))) {
+ int err;
+
/* maybe shared writable, allocate new block */
- page = mapping->a_ops->get_xip_page(mapping,
- vmf->pgoff*(PAGE_SIZE/512), 1);
- if (IS_ERR(page))
+ error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 1,
+ &xip_mem, &xip_pfn);
+ if (error)
return VM_FAULT_SIGBUS;
- /* unmap page at pgoff from all other vmas */
+ /* unmap sparse mappings at pgoff from all other vmas */
__xip_unmap(mapping, vmf->pgoff);
+
+found:
+ err = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
+ xip_pfn);
+ if (err == -ENOMEM)
+ return VM_FAULT_OOM;
+ BUG_ON(err);
+ return VM_FAULT_NOPAGE;
} else {
/* not shared and writable, use xip_sparse_page() */
page = xip_sparse_page();
if (!page)
return VM_FAULT_OOM;
- }
-out:
- page_cache_get(page);
- vmf->page = page;
- return 0;
+ page_cache_get(page);
+ vmf->page = page;
+ return 0;
+ }
}
static struct vm_operations_struct xip_file_vm_ops = {
@@ -262,11 +268,11 @@ static struct vm_operations_struct xip_file_vm_ops = {
int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- BUG_ON(!file->f_mapping->a_ops->get_xip_page);
+ BUG_ON(!file->f_mapping->a_ops->get_xip_mem);
file_accessed(file);
vma->vm_ops = &xip_file_vm_ops;
- vma->vm_flags |= VM_CAN_NONLINEAR;
+ vma->vm_flags |= VM_CAN_NONLINEAR | VM_MIXEDMAP;
return 0;
}
EXPORT_SYMBOL_GPL(xip_file_mmap);
@@ -279,17 +285,17 @@ __xip_file_write(struct file *filp, const char __user *buf,
const struct address_space_operations *a_ops = mapping->a_ops;
struct inode *inode = mapping->host;
long status = 0;
- struct page *page;
size_t bytes;
ssize_t written = 0;
- BUG_ON(!mapping->a_ops->get_xip_page);
+ BUG_ON(!mapping->a_ops->get_xip_mem);
do {
unsigned long index;
unsigned long offset;
size_t copied;
- char *kaddr;
+ void *xip_mem;
+ unsigned long xip_pfn;
offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
index = pos >> PAGE_CACHE_SHIFT;
@@ -297,28 +303,22 @@ __xip_file_write(struct file *filp, const char __user *buf,
if (bytes > count)
bytes = count;
- page = a_ops->get_xip_page(mapping,
- index*(PAGE_SIZE/512), 0);
- if (IS_ERR(page) && (PTR_ERR(page) == -ENODATA)) {
+ status = a_ops->get_xip_mem(mapping, index, 0,
+ &xip_mem, &xip_pfn);
+ if (status == -ENODATA) {
/* we allocate a new page unmap it */
- page = a_ops->get_xip_page(mapping,
- index*(PAGE_SIZE/512), 1);
- if (!IS_ERR(page))
+ status = a_ops->get_xip_mem(mapping, index, 1,
+ &xip_mem, &xip_pfn);
+ if (!status)
/* unmap page at pgoff from all other vmas */
__xip_unmap(mapping, index);
}
- if (IS_ERR(page)) {
- status = PTR_ERR(page);
+ if (status)
break;
- }
- fault_in_pages_readable(buf, bytes);
- kaddr = kmap_atomic(page, KM_USER0);
copied = bytes -
- __copy_from_user_inatomic_nocache(kaddr + offset, buf, bytes);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(page);
+ __copy_from_user_nocache(xip_mem + offset, buf, bytes);
if (likely(copied > 0)) {
status = copied;
@@ -398,7 +398,7 @@ EXPORT_SYMBOL_GPL(xip_file_write);
/*
* truncate a page used for execute in place
- * functionality is analog to block_truncate_page but does use get_xip_page
+ * functionality is analog to block_truncate_page but does use get_xip_mem
* to get the page instead of page cache
*/
int
@@ -408,9 +408,11 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
unsigned offset = from & (PAGE_CACHE_SIZE-1);
unsigned blocksize;
unsigned length;
- struct page *page;
+ void *xip_mem;
+ unsigned long xip_pfn;
+ int err;
- BUG_ON(!mapping->a_ops->get_xip_page);
+ BUG_ON(!mapping->a_ops->get_xip_mem);
blocksize = 1 << mapping->host->i_blkbits;
length = offset & (blocksize - 1);
@@ -421,18 +423,16 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
length = blocksize - length;
- page = mapping->a_ops->get_xip_page(mapping,
- index*(PAGE_SIZE/512), 0);
- if (!page)
- return -ENOMEM;
- if (unlikely(IS_ERR(page))) {
- if (PTR_ERR(page) == -ENODATA)
+ err = mapping->a_ops->get_xip_mem(mapping, index, 0,
+ &xip_mem, &xip_pfn);
+ if (unlikely(err)) {
+ if (err == -ENODATA)
/* Hole? No need to truncate */
return 0;
else
- return PTR_ERR(page);
+ return err;
}
- zero_user(page, offset, length);
+ memset(xip_mem + offset, 0, length);
return 0;
}
EXPORT_SYMBOL_GPL(xip_truncate_page);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 51c9e2c01640..2c37c67ed8c9 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -95,13 +95,16 @@ static struct page *dequeue_huge_page_vma(struct vm_area_struct *vma,
int nid;
struct page *page = NULL;
struct mempolicy *mpol;
+ nodemask_t *nodemask;
struct zonelist *zonelist = huge_zonelist(vma, address,
- htlb_alloc_mask, &mpol);
- struct zone **z;
-
- for (z = zonelist->zones; *z; z++) {
- nid = zone_to_nid(*z);
- if (cpuset_zone_allowed_softwall(*z, htlb_alloc_mask) &&
+ htlb_alloc_mask, &mpol, &nodemask);
+ struct zone *zone;
+ struct zoneref *z;
+
+ for_each_zone_zonelist_nodemask(zone, z, zonelist,
+ MAX_NR_ZONES - 1, nodemask) {
+ nid = zone_to_nid(zone);
+ if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask) &&
!list_empty(&hugepage_freelists[nid])) {
page = list_entry(hugepage_freelists[nid].next,
struct page, lru);
@@ -113,7 +116,7 @@ static struct page *dequeue_huge_page_vma(struct vm_area_struct *vma,
break;
}
}
- mpol_free(mpol); /* unref if mpol !NULL */
+ mpol_cond_put(mpol);
return page;
}
@@ -129,6 +132,7 @@ static void update_and_free_page(struct page *page)
}
set_compound_page_dtor(page, NULL);
set_page_refcounted(page);
+ arch_release_hugepage(page);
__free_pages(page, HUGETLB_PAGE_ORDER);
}
@@ -198,6 +202,10 @@ static struct page *alloc_fresh_huge_page_node(int nid)
htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|__GFP_NOWARN,
HUGETLB_PAGE_ORDER);
if (page) {
+ if (arch_prepare_hugepage(page)) {
+ __free_pages(page, HUGETLB_PAGE_ORDER);
+ return NULL;
+ }
set_compound_page_dtor(page, free_huge_page);
spin_lock(&hugetlb_lock);
nr_huge_pages++;
@@ -239,6 +247,11 @@ static int alloc_fresh_huge_page(void)
hugetlb_next_nid = next_nid;
} while (!page && hugetlb_next_nid != start_nid);
+ if (ret)
+ count_vm_event(HTLB_BUDDY_PGALLOC);
+ else
+ count_vm_event(HTLB_BUDDY_PGALLOC_FAIL);
+
return ret;
}
@@ -299,9 +312,11 @@ static struct page *alloc_buddy_huge_page(struct vm_area_struct *vma,
*/
nr_huge_pages_node[nid]++;
surplus_huge_pages_node[nid]++;
+ __count_vm_event(HTLB_BUDDY_PGALLOC);
} else {
nr_huge_pages--;
surplus_huge_pages--;
+ __count_vm_event(HTLB_BUDDY_PGALLOC_FAIL);
}
spin_unlock(&hugetlb_lock);
@@ -369,11 +384,19 @@ retry:
resv_huge_pages += delta;
ret = 0;
free:
+ /* Free the needed pages to the hugetlb pool */
list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
+ if ((--needed) < 0)
+ break;
list_del(&page->lru);
- if ((--needed) >= 0)
- enqueue_huge_page(page);
- else {
+ enqueue_huge_page(page);
+ }
+
+ /* Free unnecessary surplus pages to the buddy allocator */
+ if (!list_empty(&surplus_list)) {
+ spin_unlock(&hugetlb_lock);
+ list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
+ list_del(&page->lru);
/*
* The page has a reference count of zero already, so
* call free_huge_page directly instead of using
@@ -381,10 +404,9 @@ free:
* unlocked which is safe because free_huge_page takes
* hugetlb_lock before deciding how to free the page.
*/
- spin_unlock(&hugetlb_lock);
free_huge_page(page);
- spin_lock(&hugetlb_lock);
}
+ spin_lock(&hugetlb_lock);
}
return ret;
@@ -718,7 +740,7 @@ static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page,
entry =
pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
} else {
- entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
+ entry = huge_pte_wrprotect(mk_pte(page, vma->vm_page_prot));
}
entry = pte_mkyoung(entry);
entry = pte_mkhuge(entry);
@@ -731,8 +753,8 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma,
{
pte_t entry;
- entry = pte_mkwrite(pte_mkdirty(*ptep));
- if (ptep_set_access_flags(vma, address, ptep, entry, 1)) {
+ entry = pte_mkwrite(pte_mkdirty(huge_ptep_get(ptep)));
+ if (huge_ptep_set_access_flags(vma, address, ptep, entry, 1)) {
update_mmu_cache(vma, address, entry);
}
}
@@ -762,10 +784,10 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
spin_lock(&dst->page_table_lock);
spin_lock(&src->page_table_lock);
- if (!pte_none(*src_pte)) {
+ if (!huge_pte_none(huge_ptep_get(src_pte))) {
if (cow)
- ptep_set_wrprotect(src, addr, src_pte);
- entry = *src_pte;
+ huge_ptep_set_wrprotect(src, addr, src_pte);
+ entry = huge_ptep_get(src_pte);
ptepage = pte_page(entry);
get_page(ptepage);
set_huge_pte_at(dst, addr, dst_pte, entry);
@@ -809,7 +831,7 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
continue;
pte = huge_ptep_get_and_clear(mm, address, ptep);
- if (pte_none(pte))
+ if (huge_pte_none(pte))
continue;
page = pte_page(pte);
@@ -873,8 +895,9 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
spin_lock(&mm->page_table_lock);
ptep = huge_pte_offset(mm, address & HPAGE_MASK);
- if (likely(pte_same(*ptep, pte))) {
+ if (likely(pte_same(huge_ptep_get(ptep), pte))) {
/* Break COW */
+ huge_ptep_clear_flush(vma, address, ptep);
set_huge_pte_at(mm, address, ptep,
make_huge_pte(vma, new_page, 1));
/* Make the old page be freed below */
@@ -942,7 +965,7 @@ retry:
goto backout;
ret = 0;
- if (!pte_none(*ptep))
+ if (!huge_pte_none(huge_ptep_get(ptep)))
goto backout;
new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)
@@ -984,8 +1007,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
* the same page in the page cache.
*/
mutex_lock(&hugetlb_instantiation_mutex);
- entry = *ptep;
- if (pte_none(entry)) {
+ entry = huge_ptep_get(ptep);
+ if (huge_pte_none(entry)) {
ret = hugetlb_no_page(mm, vma, address, ptep, write_access);
mutex_unlock(&hugetlb_instantiation_mutex);
return ret;
@@ -995,7 +1018,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
spin_lock(&mm->page_table_lock);
/* Check for a racing update before calling hugetlb_cow */
- if (likely(pte_same(entry, *ptep)))
+ if (likely(pte_same(entry, huge_ptep_get(ptep))))
if (write_access && !pte_write(entry))
ret = hugetlb_cow(mm, vma, address, ptep, entry);
spin_unlock(&mm->page_table_lock);
@@ -1025,7 +1048,8 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
*/
pte = huge_pte_offset(mm, vaddr & HPAGE_MASK);
- if (!pte || pte_none(*pte) || (write && !pte_write(*pte))) {
+ if (!pte || huge_pte_none(huge_ptep_get(pte)) ||
+ (write && !pte_write(huge_ptep_get(pte)))) {
int ret;
spin_unlock(&mm->page_table_lock);
@@ -1041,7 +1065,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
}
pfn_offset = (vaddr & ~HPAGE_MASK) >> PAGE_SHIFT;
- page = pte_page(*pte);
+ page = pte_page(huge_ptep_get(pte));
same_page:
if (pages) {
get_page(page);
@@ -1090,7 +1114,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
continue;
if (huge_pmd_unshare(mm, &address, ptep))
continue;
- if (!pte_none(*ptep)) {
+ if (!huge_pte_none(huge_ptep_get(ptep))) {
pte = huge_ptep_get_and_clear(mm, address, ptep);
pte = pte_mkhuge(pte_modify(pte, newprot));
set_huge_pte_at(mm, address, ptep, pte);
diff --git a/mm/internal.h b/mm/internal.h
index 789727309f4d..0034e947e4bc 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -34,8 +34,7 @@ static inline void __put_page(struct page *page)
atomic_dec(&page->_count);
}
-extern void __init __free_pages_bootmem(struct page *page,
- unsigned int order);
+extern void __free_pages_bootmem(struct page *page, unsigned int order);
/*
* function for dealing with page's order in buddy system.
diff --git a/mm/madvise.c b/mm/madvise.c
index 93ee375b38e7..23a0ec3e0ea0 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -112,7 +112,7 @@ static long madvise_willneed(struct vm_area_struct * vma,
if (!file)
return -EBADF;
- if (file->f_mapping->a_ops->get_xip_page) {
+ if (file->f_mapping->a_ops->get_xip_mem) {
/* no bad return value, but ignore advice */
return 0;
}
diff --git a/mm/memory.c b/mm/memory.c
index 0d14d1e58a5f..bbab1e37055e 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -371,57 +371,93 @@ static inline int is_cow_mapping(unsigned int flags)
}
/*
- * This function gets the "struct page" associated with a pte.
+ * vm_normal_page -- This function gets the "struct page" associated with a pte.
*
- * NOTE! Some mappings do not have "struct pages". A raw PFN mapping
- * will have each page table entry just pointing to a raw page frame
- * number, and as far as the VM layer is concerned, those do not have
- * pages associated with them - even if the PFN might point to memory
- * that otherwise is perfectly fine and has a "struct page".
+ * "Special" mappings do not wish to be associated with a "struct page" (either
+ * it doesn't exist, or it exists but they don't want to touch it). In this
+ * case, NULL is returned here. "Normal" mappings do have a struct page.
*
- * The way we recognize those mappings is through the rules set up
- * by "remap_pfn_range()": the vma will have the VM_PFNMAP bit set,
- * and the vm_pgoff will point to the first PFN mapped: thus every
- * page that is a raw mapping will always honor the rule
+ * There are 2 broad cases. Firstly, an architecture may define a pte_special()
+ * pte bit, in which case this function is trivial. Secondly, an architecture
+ * may not have a spare pte bit, which requires a more complicated scheme,
+ * described below.
+ *
+ * A raw VM_PFNMAP mapping (ie. one that is not COWed) is always considered a
+ * special mapping (even if there are underlying and valid "struct pages").
+ * COWed pages of a VM_PFNMAP are always normal.
+ *
+ * The way we recognize COWed pages within VM_PFNMAP mappings is through the
+ * rules set up by "remap_pfn_range()": the vma will have the VM_PFNMAP bit
+ * set, and the vm_pgoff will point to the first PFN mapped: thus every special
+ * mapping will always honor the rule
*
* pfn_of_page == vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT)
*
- * and if that isn't true, the page has been COW'ed (in which case it
- * _does_ have a "struct page" associated with it even if it is in a
- * VM_PFNMAP range).
+ * And for normal mappings this is false.
+ *
+ * This restricts such mappings to be a linear translation from virtual address
+ * to pfn. To get around this restriction, we allow arbitrary mappings so long
+ * as the vma is not a COW mapping; in that case, we know that all ptes are
+ * special (because none can have been COWed).
+ *
+ *
+ * In order to support COW of arbitrary special mappings, we have VM_MIXEDMAP.
+ *
+ * VM_MIXEDMAP mappings can likewise contain memory with or without "struct
+ * page" backing, however the difference is that _all_ pages with a struct
+ * page (that is, those where pfn_valid is true) are refcounted and considered
+ * normal pages by the VM. The disadvantage is that pages are refcounted
+ * (which can be slower and simply not an option for some PFNMAP users). The
+ * advantage is that we don't have to follow the strict linearity rule of
+ * PFNMAP mappings in order to support COWable mappings.
+ *
*/
-struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+#ifdef __HAVE_ARCH_PTE_SPECIAL
+# define HAVE_PTE_SPECIAL 1
+#else
+# define HAVE_PTE_SPECIAL 0
+#endif
+struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
+ pte_t pte)
{
- unsigned long pfn = pte_pfn(pte);
+ unsigned long pfn;
- if (unlikely(vma->vm_flags & VM_PFNMAP)) {
- unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
- if (pfn == vma->vm_pgoff + off)
- return NULL;
- if (!is_cow_mapping(vma->vm_flags))
- return NULL;
+ if (HAVE_PTE_SPECIAL) {
+ if (likely(!pte_special(pte))) {
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+ return pte_page(pte);
+ }
+ VM_BUG_ON(!(vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP)));
+ return NULL;
}
-#ifdef CONFIG_DEBUG_VM
- /*
- * Add some anal sanity checks for now. Eventually,
- * we should just do "return pfn_to_page(pfn)", but
- * in the meantime we check that we get a valid pfn,
- * and that the resulting page looks ok.
- */
- if (unlikely(!pfn_valid(pfn))) {
- print_bad_pte(vma, pte, addr);
- return NULL;
+ /* !HAVE_PTE_SPECIAL case follows: */
+
+ pfn = pte_pfn(pte);
+
+ if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) {
+ if (vma->vm_flags & VM_MIXEDMAP) {
+ if (!pfn_valid(pfn))
+ return NULL;
+ goto out;
+ } else {
+ unsigned long off;
+ off = (addr - vma->vm_start) >> PAGE_SHIFT;
+ if (pfn == vma->vm_pgoff + off)
+ return NULL;
+ if (!is_cow_mapping(vma->vm_flags))
+ return NULL;
+ }
}
-#endif
+
+ VM_BUG_ON(!pfn_valid(pfn));
/*
- * NOTE! We still have PageReserved() pages in the page
- * tables.
+ * NOTE! We still have PageReserved() pages in the page tables.
*
- * The PAGE_ZERO() pages and various VDSO mappings can
- * cause them to exist.
+ * eg. VDSO mappings can cause them to exist.
*/
+out:
return pfn_to_page(pfn);
}
@@ -1057,8 +1093,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
if (pages)
foll_flags |= FOLL_GET;
if (!write && !(vma->vm_flags & VM_LOCKED) &&
- (!vma->vm_ops || (!vma->vm_ops->nopage &&
- !vma->vm_ops->fault)))
+ (!vma->vm_ops || !vma->vm_ops->fault))
foll_flags |= FOLL_ANON;
do {
@@ -1141,8 +1176,10 @@ pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
* old drivers should use this, and they needed to mark their
* pages reserved for the old functions anyway.
*/
-static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *page, pgprot_t prot)
+static int insert_page(struct vm_area_struct *vma, unsigned long addr,
+ struct page *page, pgprot_t prot)
{
+ struct mm_struct *mm = vma->vm_mm;
int retval;
pte_t *pte;
spinlock_t *ptl;
@@ -1202,40 +1239,26 @@ out:
*
* The page does not need to be reserved.
*/
-int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *page)
+int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
+ struct page *page)
{
if (addr < vma->vm_start || addr >= vma->vm_end)
return -EFAULT;
if (!page_count(page))
return -EINVAL;
vma->vm_flags |= VM_INSERTPAGE;
- return insert_page(vma->vm_mm, addr, page, vma->vm_page_prot);
+ return insert_page(vma, addr, page, vma->vm_page_prot);
}
EXPORT_SYMBOL(vm_insert_page);
-/**
- * vm_insert_pfn - insert single pfn into user vma
- * @vma: user vma to map to
- * @addr: target user address of this page
- * @pfn: source kernel pfn
- *
- * Similar to vm_inert_page, this allows drivers to insert individual pages
- * they've allocated into a user vma. Same comments apply.
- *
- * This function should only be called from a vm_ops->fault handler, and
- * in that case the handler should return NULL.
- */
-int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn)
+static int insert_pfn(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, pgprot_t prot)
{
struct mm_struct *mm = vma->vm_mm;
int retval;
pte_t *pte, entry;
spinlock_t *ptl;
- BUG_ON(!(vma->vm_flags & VM_PFNMAP));
- BUG_ON(is_cow_mapping(vma->vm_flags));
-
retval = -ENOMEM;
pte = get_locked_pte(mm, addr, &ptl);
if (!pte)
@@ -1245,19 +1268,74 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
goto out_unlock;
/* Ok, finally just insert the thing.. */
- entry = pfn_pte(pfn, vma->vm_page_prot);
+ entry = pte_mkspecial(pfn_pte(pfn, prot));
set_pte_at(mm, addr, pte, entry);
- update_mmu_cache(vma, addr, entry);
+ update_mmu_cache(vma, addr, entry); /* XXX: why not for insert_page? */
retval = 0;
out_unlock:
pte_unmap_unlock(pte, ptl);
-
out:
return retval;
}
+
+/**
+ * vm_insert_pfn - insert single pfn into user vma
+ * @vma: user vma to map to
+ * @addr: target user address of this page
+ * @pfn: source kernel pfn
+ *
+ * Similar to vm_inert_page, this allows drivers to insert individual pages
+ * they've allocated into a user vma. Same comments apply.
+ *
+ * This function should only be called from a vm_ops->fault handler, and
+ * in that case the handler should return NULL.
+ */
+int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn)
+{
+ /*
+ * Technically, architectures with pte_special can avoid all these
+ * restrictions (same for remap_pfn_range). However we would like
+ * consistency in testing and feature parity among all, so we should
+ * try to keep these invariants in place for everybody.
+ */
+ BUG_ON(!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)));
+ BUG_ON((vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) ==
+ (VM_PFNMAP|VM_MIXEDMAP));
+ BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags));
+ BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn));
+
+ if (addr < vma->vm_start || addr >= vma->vm_end)
+ return -EFAULT;
+ return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+}
EXPORT_SYMBOL(vm_insert_pfn);
+int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn)
+{
+ BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
+
+ if (addr < vma->vm_start || addr >= vma->vm_end)
+ return -EFAULT;
+
+ /*
+ * If we don't have pte special, then we have to use the pfn_valid()
+ * based VM_MIXEDMAP scheme (see vm_normal_page), and thus we *must*
+ * refcount the page if pfn_valid is true (hence insert_page rather
+ * than insert_pfn).
+ */
+ if (!HAVE_PTE_SPECIAL && pfn_valid(pfn)) {
+ struct page *page;
+
+ page = pfn_to_page(pfn);
+ return insert_page(vma, addr, page, vma->vm_page_prot);
+ }
+ return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_insert_mixed);
+
/*
* maps a range of physical memory into the requested pages. the old
* mappings are removed. any references to nonexistent pages results
@@ -1276,7 +1354,7 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
arch_enter_lazy_mmu_mode();
do {
BUG_ON(!pte_none(*pte));
- set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
+ set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
pfn++;
} while (pte++, addr += PAGE_SIZE, addr != end);
arch_leave_lazy_mmu_mode();
@@ -2199,20 +2277,9 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
BUG_ON(vma->vm_flags & VM_PFNMAP);
- if (likely(vma->vm_ops->fault)) {
- ret = vma->vm_ops->fault(vma, &vmf);
- if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
- return ret;
- } else {
- /* Legacy ->nopage path */
- ret = 0;
- vmf.page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret);
- /* no page was available -- either SIGBUS or OOM */
- if (unlikely(vmf.page == NOPAGE_SIGBUS))
- return VM_FAULT_SIGBUS;
- else if (unlikely(vmf.page == NOPAGE_OOM))
- return VM_FAULT_OOM;
- }
+ ret = vma->vm_ops->fault(vma, &vmf);
+ if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
+ return ret;
/*
* For consistency in subsequent calls, make the faulted page always
@@ -2377,10 +2444,13 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long pfn;
pte_unmap(page_table);
- BUG_ON(!(vma->vm_flags & VM_PFNMAP));
- BUG_ON(is_cow_mapping(vma->vm_flags));
+ BUG_ON(!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)));
+ BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags));
pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK);
+
+ BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn));
+
if (unlikely(pfn == NOPFN_OOM))
return VM_FAULT_OOM;
else if (unlikely(pfn == NOPFN_SIGBUS))
@@ -2458,7 +2528,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
if (!pte_present(entry)) {
if (pte_none(entry)) {
if (vma->vm_ops) {
- if (vma->vm_ops->fault || vma->vm_ops->nopage)
+ if (likely(vma->vm_ops->fault))
return do_linear_fault(mm, vma, address,
pte, pmd, write_access, entry);
if (unlikely(vma->vm_ops->nopfn))
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 0fb330271271..b17dca7249f8 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -29,6 +29,8 @@
#include <asm/tlbflush.h>
+#include "internal.h"
+
/* add this memory to iomem resource */
static struct resource *register_memory_resource(u64 start, u64 size)
{
@@ -58,8 +60,105 @@ static void release_memory_resource(struct resource *res)
return;
}
-
#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+#ifndef CONFIG_SPARSEMEM_VMEMMAP
+static void get_page_bootmem(unsigned long info, struct page *page, int magic)
+{
+ atomic_set(&page->_mapcount, magic);
+ SetPagePrivate(page);
+ set_page_private(page, info);
+ atomic_inc(&page->_count);
+}
+
+void put_page_bootmem(struct page *page)
+{
+ int magic;
+
+ magic = atomic_read(&page->_mapcount);
+ BUG_ON(magic >= -1);
+
+ if (atomic_dec_return(&page->_count) == 1) {
+ ClearPagePrivate(page);
+ set_page_private(page, 0);
+ reset_page_mapcount(page);
+ __free_pages_bootmem(page, 0);
+ }
+
+}
+
+void register_page_bootmem_info_section(unsigned long start_pfn)
+{
+ unsigned long *usemap, mapsize, section_nr, i;
+ struct mem_section *ms;
+ struct page *page, *memmap;
+
+ if (!pfn_valid(start_pfn))
+ return;
+
+ section_nr = pfn_to_section_nr(start_pfn);
+ ms = __nr_to_section(section_nr);
+
+ /* Get section's memmap address */
+ memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
+
+ /*
+ * Get page for the memmap's phys address
+ * XXX: need more consideration for sparse_vmemmap...
+ */
+ page = virt_to_page(memmap);
+ mapsize = sizeof(struct page) * PAGES_PER_SECTION;
+ mapsize = PAGE_ALIGN(mapsize) >> PAGE_SHIFT;
+
+ /* remember memmap's page */
+ for (i = 0; i < mapsize; i++, page++)
+ get_page_bootmem(section_nr, page, SECTION_INFO);
+
+ usemap = __nr_to_section(section_nr)->pageblock_flags;
+ page = virt_to_page(usemap);
+
+ mapsize = PAGE_ALIGN(usemap_size()) >> PAGE_SHIFT;
+
+ for (i = 0; i < mapsize; i++, page++)
+ get_page_bootmem(section_nr, page, MIX_INFO);
+
+}
+
+void register_page_bootmem_info_node(struct pglist_data *pgdat)
+{
+ unsigned long i, pfn, end_pfn, nr_pages;
+ int node = pgdat->node_id;
+ struct page *page;
+ struct zone *zone;
+
+ nr_pages = PAGE_ALIGN(sizeof(struct pglist_data)) >> PAGE_SHIFT;
+ page = virt_to_page(pgdat);
+
+ for (i = 0; i < nr_pages; i++, page++)
+ get_page_bootmem(node, page, NODE_INFO);
+
+ zone = &pgdat->node_zones[0];
+ for (; zone < pgdat->node_zones + MAX_NR_ZONES - 1; zone++) {
+ if (zone->wait_table) {
+ nr_pages = zone->wait_table_hash_nr_entries
+ * sizeof(wait_queue_head_t);
+ nr_pages = PAGE_ALIGN(nr_pages) >> PAGE_SHIFT;
+ page = virt_to_page(zone->wait_table);
+
+ for (i = 0; i < nr_pages; i++, page++)
+ get_page_bootmem(node, page, NODE_INFO);
+ }
+ }
+
+ pfn = pgdat->node_start_pfn;
+ end_pfn = pfn + pgdat->node_spanned_pages;
+
+ /* register_section info */
+ for (; pfn < end_pfn; pfn += PAGES_PER_SECTION)
+ register_page_bootmem_info_section(pfn);
+
+}
+#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
+
static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
{
struct pglist_data *pgdat = zone->zone_pgdat;
@@ -101,6 +200,36 @@ static int __add_section(struct zone *zone, unsigned long phys_start_pfn)
return register_new_memory(__pfn_to_section(phys_start_pfn));
}
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+static int __remove_section(struct zone *zone, struct mem_section *ms)
+{
+ /*
+ * XXX: Freeing memmap with vmemmap is not implement yet.
+ * This should be removed later.
+ */
+ return -EBUSY;
+}
+#else
+static int __remove_section(struct zone *zone, struct mem_section *ms)
+{
+ unsigned long flags;
+ struct pglist_data *pgdat = zone->zone_pgdat;
+ int ret = -EINVAL;
+
+ if (!valid_section(ms))
+ return ret;
+
+ ret = unregister_memory_section(ms);
+ if (ret)
+ return ret;
+
+ pgdat_resize_lock(pgdat, &flags);
+ sparse_remove_one_section(zone, ms);
+ pgdat_resize_unlock(pgdat, &flags);
+ return 0;
+}
+#endif
+
/*
* Reasonably generic function for adding memory. It is
* expected that archs that support memory hotplug will
@@ -134,6 +263,42 @@ int __add_pages(struct zone *zone, unsigned long phys_start_pfn,
}
EXPORT_SYMBOL_GPL(__add_pages);
+/**
+ * __remove_pages() - remove sections of pages from a zone
+ * @zone: zone from which pages need to be removed
+ * @phys_start_pfn: starting pageframe (must be aligned to start of a section)
+ * @nr_pages: number of pages to remove (must be multiple of section size)
+ *
+ * Generic helper function to remove section mappings and sysfs entries
+ * for the section of the memory we are removing. Caller needs to make
+ * sure that pages are marked reserved and zones are adjust properly by
+ * calling offline_pages().
+ */
+int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
+ unsigned long nr_pages)
+{
+ unsigned long i, ret = 0;
+ int sections_to_remove;
+
+ /*
+ * We can only remove entire sections
+ */
+ BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
+ BUG_ON(nr_pages % PAGES_PER_SECTION);
+
+ release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE);
+
+ sections_to_remove = nr_pages / PAGES_PER_SECTION;
+ for (i = 0; i < sections_to_remove; i++) {
+ unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
+ ret = __remove_section(zone, __pfn_to_section(pfn));
+ if (ret)
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__remove_pages);
+
static void grow_zone_span(struct zone *zone,
unsigned long start_pfn, unsigned long end_pfn)
{
@@ -164,6 +329,25 @@ static void grow_pgdat_span(struct pglist_data *pgdat,
pgdat->node_start_pfn;
}
+void online_page(struct page *page)
+{
+ totalram_pages++;
+ num_physpages++;
+
+#ifdef CONFIG_HIGHMEM
+ if (PageHighMem(page))
+ totalhigh_pages++;
+#endif
+
+#ifdef CONFIG_FLATMEM
+ max_mapnr = max(page_to_pfn(page), max_mapnr);
+#endif
+
+ ClearPageReserved(page);
+ init_page_count(page);
+ __free_page(page);
+}
+
static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
void *arg)
{
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 3c3601121509..a37a5034f63d 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -63,7 +63,6 @@
grows down?
make bind policy root only? It can trigger oom much faster and the
kernel is not always grateful with that.
- could replace all the switch()es with a mempolicy_ops structure.
*/
#include <linux/mempolicy.h>
@@ -89,6 +88,7 @@
#include <linux/rmap.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/ctype.h>
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
@@ -105,142 +105,264 @@ static struct kmem_cache *sn_cache;
policied. */
enum zone_type policy_zone = 0;
+/*
+ * run-time system-wide default policy => local allocation
+ */
struct mempolicy default_policy = {
.refcnt = ATOMIC_INIT(1), /* never free it */
- .policy = MPOL_DEFAULT,
+ .mode = MPOL_PREFERRED,
+ .flags = MPOL_F_LOCAL,
};
-static void mpol_rebind_policy(struct mempolicy *pol,
- const nodemask_t *newmask);
+static const struct mempolicy_operations {
+ int (*create)(struct mempolicy *pol, const nodemask_t *nodes);
+ void (*rebind)(struct mempolicy *pol, const nodemask_t *nodes);
+} mpol_ops[MPOL_MAX];
-/* Do sanity checking on a policy */
-static int mpol_check_policy(int mode, nodemask_t *nodes)
+/* Check that the nodemask contains at least one populated zone */
+static int is_valid_nodemask(const nodemask_t *nodemask)
{
- int was_empty, is_empty;
+ int nd, k;
- if (!nodes)
- return 0;
+ /* Check that there is something useful in this mask */
+ k = policy_zone;
- /*
- * "Contextualize" the in-coming nodemast for cpusets:
- * Remember whether in-coming nodemask was empty, If not,
- * restrict the nodes to the allowed nodes in the cpuset.
- * This is guaranteed to be a subset of nodes with memory.
- */
- cpuset_update_task_memory_state();
- is_empty = was_empty = nodes_empty(*nodes);
- if (!was_empty) {
- nodes_and(*nodes, *nodes, cpuset_current_mems_allowed);
- is_empty = nodes_empty(*nodes); /* after "contextualization" */
- }
+ for_each_node_mask(nd, *nodemask) {
+ struct zone *z;
- switch (mode) {
- case MPOL_DEFAULT:
- /*
- * require caller to specify an empty nodemask
- * before "contextualization"
- */
- if (!was_empty)
- return -EINVAL;
- break;
- case MPOL_BIND:
- case MPOL_INTERLEAVE:
- /*
- * require at least 1 valid node after "contextualization"
- */
- if (is_empty)
- return -EINVAL;
- break;
- case MPOL_PREFERRED:
- /*
- * Did caller specify invalid nodes?
- * Don't silently accept this as "local allocation".
- */
- if (!was_empty && is_empty)
- return -EINVAL;
- break;
+ for (k = 0; k <= policy_zone; k++) {
+ z = &NODE_DATA(nd)->node_zones[k];
+ if (z->present_pages > 0)
+ return 1;
+ }
}
+
return 0;
}
-/* Generate a custom zonelist for the BIND policy. */
-static struct zonelist *bind_zonelist(nodemask_t *nodes)
+static inline int mpol_store_user_nodemask(const struct mempolicy *pol)
{
- struct zonelist *zl;
- int num, max, nd;
- enum zone_type k;
+ return pol->flags & (MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES);
+}
- max = 1 + MAX_NR_ZONES * nodes_weight(*nodes);
- max++; /* space for zlcache_ptr (see mmzone.h) */
- zl = kmalloc(sizeof(struct zone *) * max, GFP_KERNEL);
- if (!zl)
- return ERR_PTR(-ENOMEM);
- zl->zlcache_ptr = NULL;
- num = 0;
- /* First put in the highest zones from all nodes, then all the next
- lower zones etc. Avoid empty zones because the memory allocator
- doesn't like them. If you implement node hot removal you
- have to fix that. */
- k = MAX_NR_ZONES - 1;
- while (1) {
- for_each_node_mask(nd, *nodes) {
- struct zone *z = &NODE_DATA(nd)->node_zones[k];
- if (z->present_pages > 0)
- zl->zones[num++] = z;
- }
- if (k == 0)
- break;
- k--;
- }
- if (num == 0) {
- kfree(zl);
- return ERR_PTR(-EINVAL);
- }
- zl->zones[num] = NULL;
- return zl;
+static void mpol_relative_nodemask(nodemask_t *ret, const nodemask_t *orig,
+ const nodemask_t *rel)
+{
+ nodemask_t tmp;
+ nodes_fold(tmp, *orig, nodes_weight(*rel));
+ nodes_onto(*ret, tmp, *rel);
+}
+
+static int mpol_new_interleave(struct mempolicy *pol, const nodemask_t *nodes)
+{
+ if (nodes_empty(*nodes))
+ return -EINVAL;
+ pol->v.nodes = *nodes;
+ return 0;
+}
+
+static int mpol_new_preferred(struct mempolicy *pol, const nodemask_t *nodes)
+{
+ if (!nodes)
+ pol->flags |= MPOL_F_LOCAL; /* local allocation */
+ else if (nodes_empty(*nodes))
+ return -EINVAL; /* no allowed nodes */
+ else
+ pol->v.preferred_node = first_node(*nodes);
+ return 0;
+}
+
+static int mpol_new_bind(struct mempolicy *pol, const nodemask_t *nodes)
+{
+ if (!is_valid_nodemask(nodes))
+ return -EINVAL;
+ pol->v.nodes = *nodes;
+ return 0;
}
/* Create a new policy */
-static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)
+static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
+ nodemask_t *nodes)
{
struct mempolicy *policy;
+ nodemask_t cpuset_context_nmask;
+ int ret;
- pr_debug("setting mode %d nodes[0] %lx\n",
- mode, nodes ? nodes_addr(*nodes)[0] : -1);
+ pr_debug("setting mode %d flags %d nodes[0] %lx\n",
+ mode, flags, nodes ? nodes_addr(*nodes)[0] : -1);
- if (mode == MPOL_DEFAULT)
- return NULL;
+ if (mode == MPOL_DEFAULT) {
+ if (nodes && !nodes_empty(*nodes))
+ return ERR_PTR(-EINVAL);
+ return NULL; /* simply delete any existing policy */
+ }
+ VM_BUG_ON(!nodes);
+
+ /*
+ * MPOL_PREFERRED cannot be used with MPOL_F_STATIC_NODES or
+ * MPOL_F_RELATIVE_NODES if the nodemask is empty (local allocation).
+ * All other modes require a valid pointer to a non-empty nodemask.
+ */
+ if (mode == MPOL_PREFERRED) {
+ if (nodes_empty(*nodes)) {
+ if (((flags & MPOL_F_STATIC_NODES) ||
+ (flags & MPOL_F_RELATIVE_NODES)))
+ return ERR_PTR(-EINVAL);
+ nodes = NULL; /* flag local alloc */
+ }
+ } else if (nodes_empty(*nodes))
+ return ERR_PTR(-EINVAL);
policy = kmem_cache_alloc(policy_cache, GFP_KERNEL);
if (!policy)
return ERR_PTR(-ENOMEM);
atomic_set(&policy->refcnt, 1);
- switch (mode) {
- case MPOL_INTERLEAVE:
- policy->v.nodes = *nodes;
- if (nodes_weight(policy->v.nodes) == 0) {
- kmem_cache_free(policy_cache, policy);
- return ERR_PTR(-EINVAL);
- }
- break;
- case MPOL_PREFERRED:
- policy->v.preferred_node = first_node(*nodes);
- if (policy->v.preferred_node >= MAX_NUMNODES)
- policy->v.preferred_node = -1;
- break;
- case MPOL_BIND:
- policy->v.zonelist = bind_zonelist(nodes);
- if (IS_ERR(policy->v.zonelist)) {
- void *error_code = policy->v.zonelist;
- kmem_cache_free(policy_cache, policy);
- return error_code;
- }
- break;
+ policy->mode = mode;
+ policy->flags = flags;
+
+ if (nodes) {
+ /*
+ * cpuset related setup doesn't apply to local allocation
+ */
+ cpuset_update_task_memory_state();
+ if (flags & MPOL_F_RELATIVE_NODES)
+ mpol_relative_nodemask(&cpuset_context_nmask, nodes,
+ &cpuset_current_mems_allowed);
+ else
+ nodes_and(cpuset_context_nmask, *nodes,
+ cpuset_current_mems_allowed);
+ if (mpol_store_user_nodemask(policy))
+ policy->w.user_nodemask = *nodes;
+ else
+ policy->w.cpuset_mems_allowed =
+ cpuset_mems_allowed(current);
+ }
+
+ ret = mpol_ops[mode].create(policy,
+ nodes ? &cpuset_context_nmask : NULL);
+ if (ret < 0) {
+ kmem_cache_free(policy_cache, policy);
+ return ERR_PTR(ret);
}
- policy->policy = mode;
- policy->cpuset_mems_allowed = cpuset_mems_allowed(current);
return policy;
}
+/* Slow path of a mpol destructor. */
+void __mpol_put(struct mempolicy *p)
+{
+ if (!atomic_dec_and_test(&p->refcnt))
+ return;
+ kmem_cache_free(policy_cache, p);
+}
+
+static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes)
+{
+}
+
+static void mpol_rebind_nodemask(struct mempolicy *pol,
+ const nodemask_t *nodes)
+{
+ nodemask_t tmp;
+
+ if (pol->flags & MPOL_F_STATIC_NODES)
+ nodes_and(tmp, pol->w.user_nodemask, *nodes);
+ else if (pol->flags & MPOL_F_RELATIVE_NODES)
+ mpol_relative_nodemask(&tmp, &pol->w.user_nodemask, nodes);
+ else {
+ nodes_remap(tmp, pol->v.nodes, pol->w.cpuset_mems_allowed,
+ *nodes);
+ pol->w.cpuset_mems_allowed = *nodes;
+ }
+
+ pol->v.nodes = tmp;
+ if (!node_isset(current->il_next, tmp)) {
+ current->il_next = next_node(current->il_next, tmp);
+ if (current->il_next >= MAX_NUMNODES)
+ current->il_next = first_node(tmp);
+ if (current->il_next >= MAX_NUMNODES)
+ current->il_next = numa_node_id();
+ }
+}
+
+static void mpol_rebind_preferred(struct mempolicy *pol,
+ const nodemask_t *nodes)
+{
+ nodemask_t tmp;
+
+ if (pol->flags & MPOL_F_STATIC_NODES) {
+ int node = first_node(pol->w.user_nodemask);
+
+ if (node_isset(node, *nodes)) {
+ pol->v.preferred_node = node;
+ pol->flags &= ~MPOL_F_LOCAL;
+ } else
+ pol->flags |= MPOL_F_LOCAL;
+ } else if (pol->flags & MPOL_F_RELATIVE_NODES) {
+ mpol_relative_nodemask(&tmp, &pol->w.user_nodemask, nodes);
+ pol->v.preferred_node = first_node(tmp);
+ } else if (!(pol->flags & MPOL_F_LOCAL)) {
+ pol->v.preferred_node = node_remap(pol->v.preferred_node,
+ pol->w.cpuset_mems_allowed,
+ *nodes);
+ pol->w.cpuset_mems_allowed = *nodes;
+ }
+}
+
+/* Migrate a policy to a different set of nodes */
+static void mpol_rebind_policy(struct mempolicy *pol,
+ const nodemask_t *newmask)
+{
+ if (!pol)
+ return;
+ if (!mpol_store_user_nodemask(pol) &&
+ nodes_equal(pol->w.cpuset_mems_allowed, *newmask))
+ return;
+ mpol_ops[pol->mode].rebind(pol, newmask);
+}
+
+/*
+ * Wrapper for mpol_rebind_policy() that just requires task
+ * pointer, and updates task mempolicy.
+ */
+
+void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new)
+{
+ mpol_rebind_policy(tsk->mempolicy, new);
+}
+
+/*
+ * Rebind each vma in mm to new nodemask.
+ *
+ * Call holding a reference to mm. Takes mm->mmap_sem during call.
+ */
+
+void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
+{
+ struct vm_area_struct *vma;
+
+ down_write(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ mpol_rebind_policy(vma->vm_policy, new);
+ up_write(&mm->mmap_sem);
+}
+
+static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
+ [MPOL_DEFAULT] = {
+ .rebind = mpol_rebind_default,
+ },
+ [MPOL_INTERLEAVE] = {
+ .create = mpol_new_interleave,
+ .rebind = mpol_rebind_nodemask,
+ },
+ [MPOL_PREFERRED] = {
+ .create = mpol_new_preferred,
+ .rebind = mpol_rebind_preferred,
+ },
+ [MPOL_BIND] = {
+ .create = mpol_new_bind,
+ .rebind = mpol_rebind_nodemask,
+ },
+};
+
static void gather_stats(struct page *, void *, int pte_dirty);
static void migrate_page_add(struct page *page, struct list_head *pagelist,
unsigned long flags);
@@ -421,7 +543,7 @@ static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new)
if (!err) {
mpol_get(new);
vma->vm_policy = new;
- mpol_free(old);
+ mpol_put(old);
}
return err;
}
@@ -479,46 +601,55 @@ static void mpol_set_task_struct_flag(void)
}
/* Set the process memory policy */
-static long do_set_mempolicy(int mode, nodemask_t *nodes)
+static long do_set_mempolicy(unsigned short mode, unsigned short flags,
+ nodemask_t *nodes)
{
struct mempolicy *new;
+ struct mm_struct *mm = current->mm;
- if (mpol_check_policy(mode, nodes))
- return -EINVAL;
- new = mpol_new(mode, nodes);
+ new = mpol_new(mode, flags, nodes);
if (IS_ERR(new))
return PTR_ERR(new);
- mpol_free(current->mempolicy);
+
+ /*
+ * prevent changing our mempolicy while show_numa_maps()
+ * is using it.
+ * Note: do_set_mempolicy() can be called at init time
+ * with no 'mm'.
+ */
+ if (mm)
+ down_write(&mm->mmap_sem);
+ mpol_put(current->mempolicy);
current->mempolicy = new;
mpol_set_task_struct_flag();
- if (new && new->policy == MPOL_INTERLEAVE)
+ if (new && new->mode == MPOL_INTERLEAVE &&
+ nodes_weight(new->v.nodes))
current->il_next = first_node(new->v.nodes);
+ if (mm)
+ up_write(&mm->mmap_sem);
+
return 0;
}
-/* Fill a zone bitmap for a policy */
-static void get_zonemask(struct mempolicy *p, nodemask_t *nodes)
+/*
+ * Return nodemask for policy for get_mempolicy() query
+ */
+static void get_policy_nodemask(struct mempolicy *p, nodemask_t *nodes)
{
- int i;
-
nodes_clear(*nodes);
- switch (p->policy) {
+ if (p == &default_policy)
+ return;
+
+ switch (p->mode) {
case MPOL_BIND:
- for (i = 0; p->v.zonelist->zones[i]; i++)
- node_set(zone_to_nid(p->v.zonelist->zones[i]),
- *nodes);
- break;
- case MPOL_DEFAULT:
- break;
+ /* Fall through */
case MPOL_INTERLEAVE:
*nodes = p->v.nodes;
break;
case MPOL_PREFERRED:
- /* or use current node instead of memory_map? */
- if (p->v.preferred_node < 0)
- *nodes = node_states[N_HIGH_MEMORY];
- else
+ if (!(p->flags & MPOL_F_LOCAL))
node_set(p->v.preferred_node, *nodes);
+ /* else return empty node mask for local allocation */
break;
default:
BUG();
@@ -561,6 +692,11 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
}
if (flags & MPOL_F_ADDR) {
+ /*
+ * Do NOT fall back to task policy if the
+ * vma/shared policy at addr is NULL. We
+ * want to return MPOL_DEFAULT in this case.
+ */
down_read(&mm->mmap_sem);
vma = find_vma_intersection(mm, addr, addr+1);
if (!vma) {
@@ -575,7 +711,7 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
return -EINVAL;
if (!pol)
- pol = &default_policy;
+ pol = &default_policy; /* indicates default behavior */
if (flags & MPOL_F_NODE) {
if (flags & MPOL_F_ADDR) {
@@ -584,14 +720,17 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
goto out;
*policy = err;
} else if (pol == current->mempolicy &&
- pol->policy == MPOL_INTERLEAVE) {
+ pol->mode == MPOL_INTERLEAVE) {
*policy = current->il_next;
} else {
err = -EINVAL;
goto out;
}
- } else
- *policy = pol->policy;
+ } else {
+ *policy = pol == &default_policy ? MPOL_DEFAULT :
+ pol->mode;
+ *policy |= pol->flags;
+ }
if (vma) {
up_read(&current->mm->mmap_sem);
@@ -600,9 +739,10 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
err = 0;
if (nmask)
- get_zonemask(pol, nmask);
+ get_policy_nodemask(pol, nmask);
out:
+ mpol_cond_put(pol);
if (vma)
up_read(&current->mm->mmap_sem);
return err;
@@ -664,7 +804,7 @@ int do_migrate_pages(struct mm_struct *mm,
int err = 0;
nodemask_t tmp;
- down_read(&mm->mmap_sem);
+ down_read(&mm->mmap_sem);
err = migrate_vmas(mm, from_nodes, to_nodes, flags);
if (err)
@@ -781,8 +921,8 @@ static struct page *new_vma_page(struct page *page, unsigned long private, int *
#endif
static long do_mbind(unsigned long start, unsigned long len,
- unsigned long mode, nodemask_t *nmask,
- unsigned long flags)
+ unsigned short mode, unsigned short mode_flags,
+ nodemask_t *nmask, unsigned long flags)
{
struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
@@ -791,9 +931,8 @@ static long do_mbind(unsigned long start, unsigned long len,
int err;
LIST_HEAD(pagelist);
- if ((flags & ~(unsigned long)(MPOL_MF_STRICT |
- MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
- || mode > MPOL_MAX)
+ if (flags & ~(unsigned long)(MPOL_MF_STRICT |
+ MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
return -EINVAL;
if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_NICE))
return -EPERM;
@@ -812,10 +951,7 @@ static long do_mbind(unsigned long start, unsigned long len,
if (end == start)
return 0;
- if (mpol_check_policy(mode, nmask))
- return -EINVAL;
-
- new = mpol_new(mode, nmask);
+ new = mpol_new(mode, mode_flags, nmask);
if (IS_ERR(new))
return PTR_ERR(new);
@@ -826,8 +962,9 @@ static long do_mbind(unsigned long start, unsigned long len,
if (!new)
flags |= MPOL_MF_DISCONTIG_OK;
- pr_debug("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len,
- mode, nmask ? nodes_addr(*nmask)[0] : -1);
+ pr_debug("mbind %lx-%lx mode:%d flags:%d nodes:%lx\n",
+ start, start + len, mode, mode_flags,
+ nmask ? nodes_addr(*nmask)[0] : -1);
down_write(&mm->mmap_sem);
vma = check_range(mm, start, end, nmask,
@@ -848,7 +985,7 @@ static long do_mbind(unsigned long start, unsigned long len,
}
up_write(&mm->mmap_sem);
- mpol_free(new);
+ mpol_put(new);
return err;
}
@@ -926,11 +1063,19 @@ asmlinkage long sys_mbind(unsigned long start, unsigned long len,
{
nodemask_t nodes;
int err;
+ unsigned short mode_flags;
+ mode_flags = mode & MPOL_MODE_FLAGS;
+ mode &= ~MPOL_MODE_FLAGS;
+ if (mode >= MPOL_MAX)
+ return -EINVAL;
+ if ((mode_flags & MPOL_F_STATIC_NODES) &&
+ (mode_flags & MPOL_F_RELATIVE_NODES))
+ return -EINVAL;
err = get_nodes(&nodes, nmask, maxnode);
if (err)
return err;
- return do_mbind(start, len, mode, &nodes, flags);
+ return do_mbind(start, len, mode, mode_flags, &nodes, flags);
}
/* Set the process memory policy */
@@ -939,13 +1084,18 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
{
int err;
nodemask_t nodes;
+ unsigned short flags;
- if (mode < 0 || mode > MPOL_MAX)
+ flags = mode & MPOL_MODE_FLAGS;
+ mode &= ~MPOL_MODE_FLAGS;
+ if ((unsigned int)mode >= MPOL_MAX)
+ return -EINVAL;
+ if ((flags & MPOL_F_STATIC_NODES) && (flags & MPOL_F_RELATIVE_NODES))
return -EINVAL;
err = get_nodes(&nodes, nmask, maxnode);
if (err)
return err;
- return do_set_mempolicy(mode, &nodes);
+ return do_set_mempolicy(mode, flags, &nodes);
}
asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
@@ -1131,59 +1281,75 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
*
* Returns effective policy for a VMA at specified address.
* Falls back to @task or system default policy, as necessary.
- * Returned policy has extra reference count if shared, vma,
- * or some other task's policy [show_numa_maps() can pass
- * @task != current]. It is the caller's responsibility to
- * free the reference in these cases.
+ * Current or other task's task mempolicy and non-shared vma policies
+ * are protected by the task's mmap_sem, which must be held for read by
+ * the caller.
+ * Shared policies [those marked as MPOL_F_SHARED] require an extra reference
+ * count--added by the get_policy() vm_op, as appropriate--to protect against
+ * freeing by another task. It is the caller's responsibility to free the
+ * extra reference for shared policies.
*/
-static struct mempolicy * get_vma_policy(struct task_struct *task,
+static struct mempolicy *get_vma_policy(struct task_struct *task,
struct vm_area_struct *vma, unsigned long addr)
{
struct mempolicy *pol = task->mempolicy;
- int shared_pol = 0;
if (vma) {
if (vma->vm_ops && vma->vm_ops->get_policy) {
- pol = vma->vm_ops->get_policy(vma, addr);
- shared_pol = 1; /* if pol non-NULL, add ref below */
- } else if (vma->vm_policy &&
- vma->vm_policy->policy != MPOL_DEFAULT)
+ struct mempolicy *vpol = vma->vm_ops->get_policy(vma,
+ addr);
+ if (vpol)
+ pol = vpol;
+ } else if (vma->vm_policy)
pol = vma->vm_policy;
}
if (!pol)
pol = &default_policy;
- else if (!shared_pol && pol != current->mempolicy)
- mpol_get(pol); /* vma or other task's policy */
return pol;
}
-/* Return a zonelist representing a mempolicy */
-static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy)
+/*
+ * Return a nodemask representing a mempolicy for filtering nodes for
+ * page allocation
+ */
+static nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *policy)
{
- int nd;
+ /* Lower zones don't get a nodemask applied for MPOL_BIND */
+ if (unlikely(policy->mode == MPOL_BIND) &&
+ gfp_zone(gfp) >= policy_zone &&
+ cpuset_nodemask_valid_mems_allowed(&policy->v.nodes))
+ return &policy->v.nodes;
- switch (policy->policy) {
+ return NULL;
+}
+
+/* Return a zonelist indicated by gfp for node representing a mempolicy */
+static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy)
+{
+ int nd = numa_node_id();
+
+ switch (policy->mode) {
case MPOL_PREFERRED:
- nd = policy->v.preferred_node;
- if (nd < 0)
- nd = numa_node_id();
+ if (!(policy->flags & MPOL_F_LOCAL))
+ nd = policy->v.preferred_node;
break;
case MPOL_BIND:
- /* Lower zones don't get a policy applied */
- /* Careful: current->mems_allowed might have moved */
- if (gfp_zone(gfp) >= policy_zone)
- if (cpuset_zonelist_valid_mems_allowed(policy->v.zonelist))
- return policy->v.zonelist;
- /*FALL THROUGH*/
+ /*
+ * Normally, MPOL_BIND allocations are node-local within the
+ * allowed nodemask. However, if __GFP_THISNODE is set and the
+ * current node is part of the mask, we use the zonelist for
+ * the first node in the mask instead.
+ */
+ if (unlikely(gfp & __GFP_THISNODE) &&
+ unlikely(!node_isset(nd, policy->v.nodes)))
+ nd = first_node(policy->v.nodes);
+ break;
case MPOL_INTERLEAVE: /* should not happen */
- case MPOL_DEFAULT:
- nd = numa_node_id();
break;
default:
- nd = 0;
BUG();
}
- return NODE_DATA(nd)->node_zonelists + gfp_zone(gfp);
+ return node_zonelist(nd, gfp);
}
/* Do dynamic interleaving for a process */
@@ -1196,36 +1362,51 @@ static unsigned interleave_nodes(struct mempolicy *policy)
next = next_node(nid, policy->v.nodes);
if (next >= MAX_NUMNODES)
next = first_node(policy->v.nodes);
- me->il_next = next;
+ if (next < MAX_NUMNODES)
+ me->il_next = next;
return nid;
}
/*
* Depending on the memory policy provide a node from which to allocate the
* next slab entry.
+ * @policy must be protected by freeing by the caller. If @policy is
+ * the current task's mempolicy, this protection is implicit, as only the
+ * task can change it's policy. The system default policy requires no
+ * such protection.
*/
unsigned slab_node(struct mempolicy *policy)
{
- int pol = policy ? policy->policy : MPOL_DEFAULT;
+ if (!policy || policy->flags & MPOL_F_LOCAL)
+ return numa_node_id();
+
+ switch (policy->mode) {
+ case MPOL_PREFERRED:
+ /*
+ * handled MPOL_F_LOCAL above
+ */
+ return policy->v.preferred_node;
- switch (pol) {
case MPOL_INTERLEAVE:
return interleave_nodes(policy);
- case MPOL_BIND:
+ case MPOL_BIND: {
/*
* Follow bind policy behavior and start allocation at the
* first node.
*/
- return zone_to_nid(policy->v.zonelist->zones[0]);
-
- case MPOL_PREFERRED:
- if (policy->v.preferred_node >= 0)
- return policy->v.preferred_node;
- /* Fall through */
+ struct zonelist *zonelist;
+ struct zone *zone;
+ enum zone_type highest_zoneidx = gfp_zone(GFP_KERNEL);
+ zonelist = &NODE_DATA(numa_node_id())->node_zonelists[0];
+ (void)first_zones_zonelist(zonelist, highest_zoneidx,
+ &policy->v.nodes,
+ &zone);
+ return zone->node;
+ }
default:
- return numa_node_id();
+ BUG();
}
}
@@ -1234,10 +1415,13 @@ static unsigned offset_il_node(struct mempolicy *pol,
struct vm_area_struct *vma, unsigned long off)
{
unsigned nnodes = nodes_weight(pol->v.nodes);
- unsigned target = (unsigned)off % nnodes;
+ unsigned target;
int c;
int nid = -1;
+ if (!nnodes)
+ return numa_node_id();
+ target = (unsigned int)off % nnodes;
c = 0;
do {
nid = next_node(nid, pol->v.nodes);
@@ -1274,40 +1458,30 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
* @vma = virtual memory area whose policy is sought
* @addr = address in @vma for shared policy lookup and interleave policy
* @gfp_flags = for requested zone
- * @mpol = pointer to mempolicy pointer for reference counted 'BIND policy
+ * @mpol = pointer to mempolicy pointer for reference counted mempolicy
+ * @nodemask = pointer to nodemask pointer for MPOL_BIND nodemask
*
- * Returns a zonelist suitable for a huge page allocation.
- * If the effective policy is 'BIND, returns pointer to policy's zonelist.
- * If it is also a policy for which get_vma_policy() returns an extra
- * reference, we must hold that reference until after allocation.
- * In that case, return policy via @mpol so hugetlb allocation can drop
- * the reference. For non-'BIND referenced policies, we can/do drop the
- * reference here, so the caller doesn't need to know about the special case
- * for default and current task policy.
+ * Returns a zonelist suitable for a huge page allocation and a pointer
+ * to the struct mempolicy for conditional unref after allocation.
+ * If the effective policy is 'BIND, returns a pointer to the mempolicy's
+ * @nodemask for filtering the zonelist.
*/
struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
- gfp_t gfp_flags, struct mempolicy **mpol)
+ gfp_t gfp_flags, struct mempolicy **mpol,
+ nodemask_t **nodemask)
{
- struct mempolicy *pol = get_vma_policy(current, vma, addr);
struct zonelist *zl;
- *mpol = NULL; /* probably no unref needed */
- if (pol->policy == MPOL_INTERLEAVE) {
- unsigned nid;
-
- nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT);
- if (unlikely(pol != &default_policy &&
- pol != current->mempolicy))
- __mpol_free(pol); /* finished with pol */
- return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags);
- }
+ *mpol = get_vma_policy(current, vma, addr);
+ *nodemask = NULL; /* assume !MPOL_BIND */
- zl = zonelist_policy(GFP_HIGHUSER, pol);
- if (unlikely(pol != &default_policy && pol != current->mempolicy)) {
- if (pol->policy != MPOL_BIND)
- __mpol_free(pol); /* finished with pol */
- else
- *mpol = pol; /* unref needed after allocation */
+ if (unlikely((*mpol)->mode == MPOL_INTERLEAVE)) {
+ zl = node_zonelist(interleave_nid(*mpol, vma, addr,
+ HPAGE_SHIFT), gfp_flags);
+ } else {
+ zl = policy_zonelist(gfp_flags, *mpol);
+ if ((*mpol)->mode == MPOL_BIND)
+ *nodemask = &(*mpol)->v.nodes;
}
return zl;
}
@@ -1321,9 +1495,9 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
struct zonelist *zl;
struct page *page;
- zl = NODE_DATA(nid)->node_zonelists + gfp_zone(gfp);
+ zl = node_zonelist(nid, gfp);
page = __alloc_pages(gfp, order, zl);
- if (page && page_zone(page) == zl->zones[0])
+ if (page && page_zone(page) == zonelist_zone(&zl->_zonerefs[0]))
inc_zone_page_state(page, NUMA_INTERLEAVE_HIT);
return page;
}
@@ -1358,28 +1532,27 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
cpuset_update_task_memory_state();
- if (unlikely(pol->policy == MPOL_INTERLEAVE)) {
+ if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
unsigned nid;
nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
- if (unlikely(pol != &default_policy &&
- pol != current->mempolicy))
- __mpol_free(pol); /* finished with pol */
+ mpol_cond_put(pol);
return alloc_page_interleave(gfp, 0, nid);
}
- zl = zonelist_policy(gfp, pol);
- if (pol != &default_policy && pol != current->mempolicy) {
+ zl = policy_zonelist(gfp, pol);
+ if (unlikely(mpol_needs_cond_ref(pol))) {
/*
- * slow path: ref counted policy -- shared or vma
+ * slow path: ref counted shared policy
*/
- struct page *page = __alloc_pages(gfp, 0, zl);
- __mpol_free(pol);
+ struct page *page = __alloc_pages_nodemask(gfp, 0,
+ zl, policy_nodemask(gfp, pol));
+ __mpol_put(pol);
return page;
}
/*
* fast path: default or task policy
*/
- return __alloc_pages(gfp, 0, zl);
+ return __alloc_pages_nodemask(gfp, 0, zl, policy_nodemask(gfp, pol));
}
/**
@@ -1409,22 +1582,28 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
cpuset_update_task_memory_state();
if (!pol || in_interrupt() || (gfp & __GFP_THISNODE))
pol = &default_policy;
- if (pol->policy == MPOL_INTERLEAVE)
+
+ /*
+ * No reference counting needed for current->mempolicy
+ * nor system default_policy
+ */
+ if (pol->mode == MPOL_INTERLEAVE)
return alloc_page_interleave(gfp, order, interleave_nodes(pol));
- return __alloc_pages(gfp, order, zonelist_policy(gfp, pol));
+ return __alloc_pages_nodemask(gfp, order,
+ policy_zonelist(gfp, pol), policy_nodemask(gfp, pol));
}
EXPORT_SYMBOL(alloc_pages_current);
/*
- * If mpol_copy() sees current->cpuset == cpuset_being_rebound, then it
+ * If mpol_dup() sees current->cpuset == cpuset_being_rebound, then it
* rebinds the mempolicy its copying by calling mpol_rebind_policy()
* with the mems_allowed returned by cpuset_mems_allowed(). This
* keeps mempolicies cpuset relative after its cpuset moves. See
* further kernel/cpuset.c update_nodemask().
*/
-/* Slow path of a mempolicy copy */
-struct mempolicy *__mpol_copy(struct mempolicy *old)
+/* Slow path of a mempolicy duplicate */
+struct mempolicy *__mpol_dup(struct mempolicy *old)
{
struct mempolicy *new = kmem_cache_alloc(policy_cache, GFP_KERNEL);
@@ -1436,55 +1615,64 @@ struct mempolicy *__mpol_copy(struct mempolicy *old)
}
*new = *old;
atomic_set(&new->refcnt, 1);
- if (new->policy == MPOL_BIND) {
- int sz = ksize(old->v.zonelist);
- new->v.zonelist = kmemdup(old->v.zonelist, sz, GFP_KERNEL);
- if (!new->v.zonelist) {
- kmem_cache_free(policy_cache, new);
- return ERR_PTR(-ENOMEM);
- }
- }
return new;
}
+/*
+ * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
+ * eliminate the * MPOL_F_* flags that require conditional ref and
+ * [NOTE!!!] drop the extra ref. Not safe to reference *frompol directly
+ * after return. Use the returned value.
+ *
+ * Allows use of a mempolicy for, e.g., multiple allocations with a single
+ * policy lookup, even if the policy needs/has extra ref on lookup.
+ * shmem_readahead needs this.
+ */
+struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
+ struct mempolicy *frompol)
+{
+ if (!mpol_needs_cond_ref(frompol))
+ return frompol;
+
+ *tompol = *frompol;
+ tompol->flags &= ~MPOL_F_SHARED; /* copy doesn't need unref */
+ __mpol_put(frompol);
+ return tompol;
+}
+
+static int mpol_match_intent(const struct mempolicy *a,
+ const struct mempolicy *b)
+{
+ if (a->flags != b->flags)
+ return 0;
+ if (!mpol_store_user_nodemask(a))
+ return 1;
+ return nodes_equal(a->w.user_nodemask, b->w.user_nodemask);
+}
+
/* Slow path of a mempolicy comparison */
int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
{
if (!a || !b)
return 0;
- if (a->policy != b->policy)
+ if (a->mode != b->mode)
return 0;
- switch (a->policy) {
- case MPOL_DEFAULT:
- return 1;
+ if (a->mode != MPOL_DEFAULT && !mpol_match_intent(a, b))
+ return 0;
+ switch (a->mode) {
+ case MPOL_BIND:
+ /* Fall through */
case MPOL_INTERLEAVE:
return nodes_equal(a->v.nodes, b->v.nodes);
case MPOL_PREFERRED:
- return a->v.preferred_node == b->v.preferred_node;
- case MPOL_BIND: {
- int i;
- for (i = 0; a->v.zonelist->zones[i]; i++)
- if (a->v.zonelist->zones[i] != b->v.zonelist->zones[i])
- return 0;
- return b->v.zonelist->zones[i] == NULL;
- }
+ return a->v.preferred_node == b->v.preferred_node &&
+ a->flags == b->flags;
default:
BUG();
return 0;
}
}
-/* Slow path of a mpol destructor. */
-void __mpol_free(struct mempolicy *p)
-{
- if (!atomic_dec_and_test(&p->refcnt))
- return;
- if (p->policy == MPOL_BIND)
- kfree(p->v.zonelist);
- p->policy = MPOL_DEFAULT;
- kmem_cache_free(policy_cache, p);
-}
-
/*
* Shared memory backing store policy support.
*
@@ -1547,7 +1735,7 @@ static void sp_insert(struct shared_policy *sp, struct sp_node *new)
rb_link_node(&new->nd, parent, p);
rb_insert_color(&new->nd, &sp->root);
pr_debug("inserting %lx-%lx: %d\n", new->start, new->end,
- new->policy ? new->policy->policy : 0);
+ new->policy ? new->policy->mode : 0);
}
/* Find shared policy intersecting idx */
@@ -1573,7 +1761,7 @@ static void sp_delete(struct shared_policy *sp, struct sp_node *n)
{
pr_debug("deleting %lx-l%lx\n", n->start, n->end);
rb_erase(&n->nd, &sp->root);
- mpol_free(n->policy);
+ mpol_put(n->policy);
kmem_cache_free(sn_cache, n);
}
@@ -1587,6 +1775,7 @@ static struct sp_node *sp_alloc(unsigned long start, unsigned long end,
n->start = start;
n->end = end;
mpol_get(pol);
+ pol->flags |= MPOL_F_SHARED; /* for unref */
n->policy = pol;
return n;
}
@@ -1633,33 +1822,41 @@ restart:
sp_insert(sp, new);
spin_unlock(&sp->lock);
if (new2) {
- mpol_free(new2->policy);
+ mpol_put(new2->policy);
kmem_cache_free(sn_cache, new2);
}
return 0;
}
-void mpol_shared_policy_init(struct shared_policy *info, int policy,
- nodemask_t *policy_nodes)
-{
- info->root = RB_ROOT;
- spin_lock_init(&info->lock);
-
- if (policy != MPOL_DEFAULT) {
- struct mempolicy *newpol;
-
- /* Falls back to MPOL_DEFAULT on any error */
- newpol = mpol_new(policy, policy_nodes);
- if (!IS_ERR(newpol)) {
- /* Create pseudo-vma that contains just the policy */
- struct vm_area_struct pvma;
-
- memset(&pvma, 0, sizeof(struct vm_area_struct));
- /* Policy covers entire file */
- pvma.vm_end = TASK_SIZE;
- mpol_set_shared_policy(info, &pvma, newpol);
- mpol_free(newpol);
- }
+/**
+ * mpol_shared_policy_init - initialize shared policy for inode
+ * @sp: pointer to inode shared policy
+ * @mpol: struct mempolicy to install
+ *
+ * Install non-NULL @mpol in inode's shared policy rb-tree.
+ * On entry, the current task has a reference on a non-NULL @mpol.
+ * This must be released on exit.
+ */
+void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
+{
+ sp->root = RB_ROOT; /* empty tree == default mempolicy */
+ spin_lock_init(&sp->lock);
+
+ if (mpol) {
+ struct vm_area_struct pvma;
+ struct mempolicy *new;
+
+ /* contextualize the tmpfs mount point mempolicy */
+ new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask);
+ mpol_put(mpol); /* drop our ref on sb mpol */
+ if (IS_ERR(new))
+ return; /* no valid nodemask intersection */
+
+ /* Create pseudo-vma that contains just the policy */
+ memset(&pvma, 0, sizeof(struct vm_area_struct));
+ pvma.vm_end = TASK_SIZE; /* policy covers entire file */
+ mpol_set_shared_policy(sp, &pvma, new); /* adds ref */
+ mpol_put(new); /* drop initial ref */
}
}
@@ -1670,9 +1867,10 @@ int mpol_set_shared_policy(struct shared_policy *info,
struct sp_node *new = NULL;
unsigned long sz = vma_pages(vma);
- pr_debug("set_shared_policy %lx sz %lu %d %lx\n",
+ pr_debug("set_shared_policy %lx sz %lu %d %d %lx\n",
vma->vm_pgoff,
- sz, npol? npol->policy : -1,
+ sz, npol ? npol->mode : -1,
+ npol ? npol->flags : -1,
npol ? nodes_addr(npol->v.nodes)[0] : -1);
if (npol) {
@@ -1700,7 +1898,7 @@ void mpol_free_shared_policy(struct shared_policy *p)
n = rb_entry(next, struct sp_node, nd);
next = rb_next(&n->nd);
rb_erase(&n->nd, &p->root);
- mpol_free(n->policy);
+ mpol_put(n->policy);
kmem_cache_free(sn_cache, n);
}
spin_unlock(&p->lock);
@@ -1745,120 +1943,177 @@ void __init numa_policy_init(void)
if (unlikely(nodes_empty(interleave_nodes)))
node_set(prefer, interleave_nodes);
- if (do_set_mempolicy(MPOL_INTERLEAVE, &interleave_nodes))
+ if (do_set_mempolicy(MPOL_INTERLEAVE, 0, &interleave_nodes))
printk("numa_policy_init: interleaving failed\n");
}
/* Reset policy of current process to default */
void numa_default_policy(void)
{
- do_set_mempolicy(MPOL_DEFAULT, NULL);
+ do_set_mempolicy(MPOL_DEFAULT, 0, NULL);
}
-/* Migrate a policy to a different set of nodes */
-static void mpol_rebind_policy(struct mempolicy *pol,
- const nodemask_t *newmask)
-{
- nodemask_t *mpolmask;
- nodemask_t tmp;
+/*
+ * Parse and format mempolicy from/to strings
+ */
- if (!pol)
- return;
- mpolmask = &pol->cpuset_mems_allowed;
- if (nodes_equal(*mpolmask, *newmask))
- return;
+/*
+ * "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag
+ * Used only for mpol_parse_str() and mpol_to_str()
+ */
+#define MPOL_LOCAL (MPOL_INTERLEAVE + 1)
+static const char * const policy_types[] =
+ { "default", "prefer", "bind", "interleave", "local" };
- switch (pol->policy) {
- case MPOL_DEFAULT:
- break;
- case MPOL_INTERLEAVE:
- nodes_remap(tmp, pol->v.nodes, *mpolmask, *newmask);
- pol->v.nodes = tmp;
- *mpolmask = *newmask;
- current->il_next = node_remap(current->il_next,
- *mpolmask, *newmask);
- break;
- case MPOL_PREFERRED:
- pol->v.preferred_node = node_remap(pol->v.preferred_node,
- *mpolmask, *newmask);
- *mpolmask = *newmask;
- break;
- case MPOL_BIND: {
- nodemask_t nodes;
- struct zone **z;
- struct zonelist *zonelist;
+#ifdef CONFIG_TMPFS
+/**
+ * mpol_parse_str - parse string to mempolicy
+ * @str: string containing mempolicy to parse
+ * @mpol: pointer to struct mempolicy pointer, returned on success.
+ * @no_context: flag whether to "contextualize" the mempolicy
+ *
+ * Format of input:
+ * <mode>[=<flags>][:<nodelist>]
+ *
+ * if @no_context is true, save the input nodemask in w.user_nodemask in
+ * the returned mempolicy. This will be used to "clone" the mempolicy in
+ * a specific context [cpuset] at a later time. Used to parse tmpfs mpol
+ * mount option. Note that if 'static' or 'relative' mode flags were
+ * specified, the input nodemask will already have been saved. Saving
+ * it again is redundant, but safe.
+ *
+ * On success, returns 0, else 1
+ */
+int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
+{
+ struct mempolicy *new = NULL;
+ unsigned short uninitialized_var(mode);
+ unsigned short uninitialized_var(mode_flags);
+ nodemask_t nodes;
+ char *nodelist = strchr(str, ':');
+ char *flags = strchr(str, '=');
+ int i;
+ int err = 1;
+
+ if (nodelist) {
+ /* NUL-terminate mode or flags string */
+ *nodelist++ = '\0';
+ if (nodelist_parse(nodelist, nodes))
+ goto out;
+ if (!nodes_subset(nodes, node_states[N_HIGH_MEMORY]))
+ goto out;
+ } else
nodes_clear(nodes);
- for (z = pol->v.zonelist->zones; *z; z++)
- node_set(zone_to_nid(*z), nodes);
- nodes_remap(tmp, nodes, *mpolmask, *newmask);
- nodes = tmp;
- zonelist = bind_zonelist(&nodes);
+ if (flags)
+ *flags++ = '\0'; /* terminate mode string */
- /* If no mem, then zonelist is NULL and we keep old zonelist.
- * If that old zonelist has no remaining mems_allowed nodes,
- * then zonelist_policy() will "FALL THROUGH" to MPOL_DEFAULT.
- */
+ for (i = 0; i <= MPOL_LOCAL; i++) {
+ if (!strcmp(str, policy_types[i])) {
+ mode = i;
+ break;
+ }
+ }
+ if (i > MPOL_LOCAL)
+ goto out;
- if (!IS_ERR(zonelist)) {
- /* Good - got mem - substitute new zonelist */
- kfree(pol->v.zonelist);
- pol->v.zonelist = zonelist;
+ switch (mode) {
+ case MPOL_PREFERRED:
+ /*
+ * Insist on a nodelist of one node only
+ */
+ if (nodelist) {
+ char *rest = nodelist;
+ while (isdigit(*rest))
+ rest++;
+ if (!*rest)
+ err = 0;
}
- *mpolmask = *newmask;
break;
- }
- default:
- BUG();
+ case MPOL_INTERLEAVE:
+ /*
+ * Default to online nodes with memory if no nodelist
+ */
+ if (!nodelist)
+ nodes = node_states[N_HIGH_MEMORY];
+ err = 0;
+ break;
+ case MPOL_LOCAL:
+ /*
+ * Don't allow a nodelist; mpol_new() checks flags
+ */
+ if (nodelist)
+ goto out;
+ mode = MPOL_PREFERRED;
break;
- }
-}
-
-/*
- * Wrapper for mpol_rebind_policy() that just requires task
- * pointer, and updates task mempolicy.
- */
-void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new)
-{
- mpol_rebind_policy(tsk->mempolicy, new);
-}
+ /*
+ * case MPOL_BIND: mpol_new() enforces non-empty nodemask.
+ * case MPOL_DEFAULT: mpol_new() enforces empty nodemask, ignores flags.
+ */
+ }
-/*
- * Rebind each vma in mm to new nodemask.
- *
- * Call holding a reference to mm. Takes mm->mmap_sem during call.
- */
+ mode_flags = 0;
+ if (flags) {
+ /*
+ * Currently, we only support two mutually exclusive
+ * mode flags.
+ */
+ if (!strcmp(flags, "static"))
+ mode_flags |= MPOL_F_STATIC_NODES;
+ else if (!strcmp(flags, "relative"))
+ mode_flags |= MPOL_F_RELATIVE_NODES;
+ else
+ err = 1;
+ }
-void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
-{
- struct vm_area_struct *vma;
+ new = mpol_new(mode, mode_flags, &nodes);
+ if (IS_ERR(new))
+ err = 1;
+ else if (no_context)
+ new->w.user_nodemask = nodes; /* save for contextualization */
- down_write(&mm->mmap_sem);
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- mpol_rebind_policy(vma->vm_policy, new);
- up_write(&mm->mmap_sem);
+out:
+ /* Restore string for error message */
+ if (nodelist)
+ *--nodelist = ':';
+ if (flags)
+ *--flags = '=';
+ if (!err)
+ *mpol = new;
+ return err;
}
+#endif /* CONFIG_TMPFS */
-/*
- * Display pages allocated per node and memory policy via /proc.
- */
-
-static const char * const policy_types[] =
- { "default", "prefer", "bind", "interleave" };
-
-/*
+/**
+ * mpol_to_str - format a mempolicy structure for printing
+ * @buffer: to contain formatted mempolicy string
+ * @maxlen: length of @buffer
+ * @pol: pointer to mempolicy to be formatted
+ * @no_context: "context free" mempolicy - use nodemask in w.user_nodemask
+ *
* Convert a mempolicy into a string.
* Returns the number of characters in buffer (if positive)
* or an error (negative)
*/
-static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
+int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
{
char *p = buffer;
int l;
nodemask_t nodes;
- int mode = pol ? pol->policy : MPOL_DEFAULT;
+ unsigned short mode;
+ unsigned short flags = pol ? pol->flags : 0;
+
+ /*
+ * Sanity check: room for longest mode, flag and some nodes
+ */
+ VM_BUG_ON(maxlen < strlen("interleave") + strlen("relative") + 16);
+
+ if (!pol || pol == &default_policy)
+ mode = MPOL_DEFAULT;
+ else
+ mode = pol->mode;
switch (mode) {
case MPOL_DEFAULT:
@@ -1867,33 +2122,50 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
case MPOL_PREFERRED:
nodes_clear(nodes);
- node_set(pol->v.preferred_node, nodes);
+ if (flags & MPOL_F_LOCAL)
+ mode = MPOL_LOCAL; /* pseudo-policy */
+ else
+ node_set(pol->v.preferred_node, nodes);
break;
case MPOL_BIND:
- get_zonemask(pol, &nodes);
- break;
-
+ /* Fall through */
case MPOL_INTERLEAVE:
- nodes = pol->v.nodes;
+ if (no_context)
+ nodes = pol->w.user_nodemask;
+ else
+ nodes = pol->v.nodes;
break;
default:
BUG();
- return -EFAULT;
}
l = strlen(policy_types[mode]);
- if (buffer + maxlen < p + l + 1)
- return -ENOSPC;
+ if (buffer + maxlen < p + l + 1)
+ return -ENOSPC;
strcpy(p, policy_types[mode]);
p += l;
- if (!nodes_empty(nodes)) {
+ if (flags & MPOL_MODE_FLAGS) {
if (buffer + maxlen < p + 2)
return -ENOSPC;
*p++ = '=';
+
+ /*
+ * Currently, the only defined flags are mutually exclusive
+ */
+ if (flags & MPOL_F_STATIC_NODES)
+ p += snprintf(p, buffer + maxlen - p, "static");
+ else if (flags & MPOL_F_RELATIVE_NODES)
+ p += snprintf(p, buffer + maxlen - p, "relative");
+ }
+
+ if (!nodes_empty(nodes)) {
+ if (buffer + maxlen < p + 2)
+ return -ENOSPC;
+ *p++ = ':';
p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
}
return p - buffer;
@@ -1971,6 +2243,9 @@ static inline void check_huge_range(struct vm_area_struct *vma,
}
#endif
+/*
+ * Display pages allocated per node and memory policy via /proc.
+ */
int show_numa_map(struct seq_file *m, void *v)
{
struct proc_maps_private *priv = m->private;
@@ -1990,12 +2265,8 @@ int show_numa_map(struct seq_file *m, void *v)
return 0;
pol = get_vma_policy(priv->task, vma, vma->vm_start);
- mpol_to_str(buffer, sizeof(buffer), pol);
- /*
- * unref shared or other task's mempolicy
- */
- if (pol != &default_policy && pol != current->mempolicy)
- __mpol_free(pol);
+ mpol_to_str(buffer, sizeof(buffer), pol, 0);
+ mpol_cond_put(pol);
seq_printf(m, "%08lx %s", vma->vm_start, buffer);
diff --git a/mm/mincore.c b/mm/mincore.c
index 5efe0ded69b1..5178800bc129 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -33,7 +33,7 @@ static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
* When tmpfs swaps out a page from a file, any process mapping that
* file will not get a swp_entry_t in its pte, but rather it is like
* any other file mapping (ie. marked !present and faulted in with
- * tmpfs's .nopage). So swapped out tmpfs mappings are tested here.
+ * tmpfs's .fault). So swapped out tmpfs mappings are tested here.
*
* However when tmpfs moves the page from pagecache and into swapcache,
* it is still in core, but the find_get_page below won't find it.
diff --git a/mm/mmap.c b/mm/mmap.c
index a32d28ce31cd..677d184b0d42 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -232,7 +232,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
vma->vm_ops->close(vma);
if (vma->vm_file)
fput(vma->vm_file);
- mpol_free(vma_policy(vma));
+ mpol_put(vma_policy(vma));
kmem_cache_free(vm_area_cachep, vma);
return next;
}
@@ -626,7 +626,7 @@ again: remove_next = 1 + (end > next->vm_end);
if (file)
fput(file);
mm->map_count--;
- mpol_free(vma_policy(next));
+ mpol_put(vma_policy(next));
kmem_cache_free(vm_area_cachep, next);
/*
* In mprotect's case 6 (see comments on vma_merge),
@@ -1068,7 +1068,6 @@ int vma_wants_writenotify(struct vm_area_struct *vma)
mapping_cap_account_dirty(vma->vm_file->f_mapping);
}
-
unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long len, unsigned long flags,
unsigned int vm_flags, unsigned long pgoff,
@@ -1181,22 +1180,20 @@ munmap_back:
if (vma_wants_writenotify(vma))
vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);
- if (!file || !vma_merge(mm, prev, addr, vma->vm_end,
+ if (file && vma_merge(mm, prev, addr, vma->vm_end,
vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) {
- file = vma->vm_file;
- vma_link(mm, vma, prev, rb_link, rb_parent);
- if (correct_wcount)
- atomic_inc(&inode->i_writecount);
- } else {
- if (file) {
- if (correct_wcount)
- atomic_inc(&inode->i_writecount);
- fput(file);
- }
- mpol_free(vma_policy(vma));
+ mpol_put(vma_policy(vma));
kmem_cache_free(vm_area_cachep, vma);
+ fput(file);
+ } else {
+ vma_link(mm, vma, prev, rb_link, rb_parent);
+ file = vma->vm_file;
}
-out:
+
+ /* Once vma denies write, undo our temporary denial count */
+ if (correct_wcount)
+ atomic_inc(&inode->i_writecount);
+out:
mm->total_vm += len >> PAGE_SHIFT;
vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT);
if (vm_flags & VM_LOCKED) {
@@ -1813,7 +1810,7 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT);
}
- pol = mpol_copy(vma_policy(vma));
+ pol = mpol_dup(vma_policy(vma));
if (IS_ERR(pol)) {
kmem_cache_free(vm_area_cachep, new);
return PTR_ERR(pol);
@@ -2129,7 +2126,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
new_vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
if (new_vma) {
*new_vma = *vma;
- pol = mpol_copy(vma_policy(vma));
+ pol = mpol_dup(vma_policy(vma));
if (IS_ERR(pol)) {
kmem_cache_free(vm_area_cachep, new_vma);
return NULL;
diff --git a/mm/mmzone.c b/mm/mmzone.c
index eb5838634f18..486ed595ee6f 100644
--- a/mm/mmzone.c
+++ b/mm/mmzone.c
@@ -42,3 +42,33 @@ struct zone *next_zone(struct zone *zone)
return zone;
}
+static inline int zref_in_nodemask(struct zoneref *zref, nodemask_t *nodes)
+{
+#ifdef CONFIG_NUMA
+ return node_isset(zonelist_node_idx(zref), *nodes);
+#else
+ return 1;
+#endif /* CONFIG_NUMA */
+}
+
+/* Returns the next zone at or below highest_zoneidx in a zonelist */
+struct zoneref *next_zones_zonelist(struct zoneref *z,
+ enum zone_type highest_zoneidx,
+ nodemask_t *nodes,
+ struct zone **zone)
+{
+ /*
+ * Find the next suitable zone to use for the allocation.
+ * Only filter based on nodemask if it's set
+ */
+ if (likely(nodes == NULL))
+ while (zonelist_zone_idx(z) > highest_zoneidx)
+ z++;
+ else
+ while (zonelist_zone_idx(z) > highest_zoneidx ||
+ (z->zone && !zref_in_nodemask(z, nodes)))
+ z++;
+
+ *zone = zonelist_zone(z++);
+ return z;
+}
diff --git a/mm/nommu.c b/mm/nommu.c
index 5d8ae086f74e..1d32fe89d57b 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -105,7 +105,11 @@ unsigned int kobjsize(const void *objp)
{
struct page *page;
- if (!objp || !((page = virt_to_page(objp))))
+ /*
+ * If the object we have should not have ksize performed on it,
+ * return size of 0
+ */
+ if (!objp || (unsigned long)objp >= memory_end || !((page = virt_to_page(objp))))
return 0;
if (PageSlab(page))
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index beb592fe9389..8a5467ee6265 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -53,8 +53,7 @@ static DEFINE_SPINLOCK(zone_scan_mutex);
* of least surprise ... (be careful when you change it)
*/
-unsigned long badness(struct task_struct *p, unsigned long uptime,
- struct mem_cgroup *mem)
+unsigned long badness(struct task_struct *p, unsigned long uptime)
{
unsigned long points, cpu_time, run_time, s;
struct mm_struct *mm;
@@ -175,12 +174,14 @@ static inline enum oom_constraint constrained_alloc(struct zonelist *zonelist,
gfp_t gfp_mask)
{
#ifdef CONFIG_NUMA
- struct zone **z;
+ struct zone *zone;
+ struct zoneref *z;
+ enum zone_type high_zoneidx = gfp_zone(gfp_mask);
nodemask_t nodes = node_states[N_HIGH_MEMORY];
- for (z = zonelist->zones; *z; z++)
- if (cpuset_zone_allowed_softwall(*z, gfp_mask))
- node_clear(zone_to_nid(*z), nodes);
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
+ if (cpuset_zone_allowed_softwall(zone, gfp_mask))
+ node_clear(zone_to_nid(zone), nodes);
else
return CONSTRAINT_CPUSET;
@@ -254,7 +255,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints,
if (p->oomkilladj == OOM_DISABLE)
continue;
- points = badness(p, uptime.tv_sec, mem);
+ points = badness(p, uptime.tv_sec);
if (points > *ppoints || !chosen) {
chosen = p;
*ppoints = points;
@@ -460,29 +461,29 @@ EXPORT_SYMBOL_GPL(unregister_oom_notifier);
* if a parallel OOM killing is already taking place that includes a zone in
* the zonelist. Otherwise, locks all zones in the zonelist and returns 1.
*/
-int try_set_zone_oom(struct zonelist *zonelist)
+int try_set_zone_oom(struct zonelist *zonelist, gfp_t gfp_mask)
{
- struct zone **z;
+ struct zoneref *z;
+ struct zone *zone;
int ret = 1;
- z = zonelist->zones;
-
spin_lock(&zone_scan_mutex);
- do {
- if (zone_is_oom_locked(*z)) {
+ for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
+ if (zone_is_oom_locked(zone)) {
ret = 0;
goto out;
}
- } while (*(++z) != NULL);
+ }
+
+ for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
+ /*
+ * Lock each zone in the zonelist under zone_scan_mutex so a
+ * parallel invocation of try_set_zone_oom() doesn't succeed
+ * when it shouldn't.
+ */
+ zone_set_flag(zone, ZONE_OOM_LOCKED);
+ }
- /*
- * Lock each zone in the zonelist under zone_scan_mutex so a parallel
- * invocation of try_set_zone_oom() doesn't succeed when it shouldn't.
- */
- z = zonelist->zones;
- do {
- zone_set_flag(*z, ZONE_OOM_LOCKED);
- } while (*(++z) != NULL);
out:
spin_unlock(&zone_scan_mutex);
return ret;
@@ -493,16 +494,15 @@ out:
* allocation attempts with zonelists containing them may now recall the OOM
* killer, if necessary.
*/
-void clear_zonelist_oom(struct zonelist *zonelist)
+void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_mask)
{
- struct zone **z;
-
- z = zonelist->zones;
+ struct zoneref *z;
+ struct zone *zone;
spin_lock(&zone_scan_mutex);
- do {
- zone_clear_flag(*z, ZONE_OOM_LOCKED);
- } while (*(++z) != NULL);
+ for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
+ zone_clear_flag(zone, ZONE_OOM_LOCKED);
+ }
spin_unlock(&zone_scan_mutex);
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 32e796af12a1..d1cf4f05dcda 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -546,7 +546,7 @@ static void __free_pages_ok(struct page *page, unsigned int order)
/*
* permit the bootmem allocator to evade page validation on high-order frees
*/
-void __init __free_pages_bootmem(struct page *page, unsigned int order)
+void __free_pages_bootmem(struct page *page, unsigned int order)
{
if (order == 0) {
__ClearPageReserved(page);
@@ -632,7 +632,7 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
if (PageReserved(page))
return 1;
- page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_readahead |
+ page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_reclaim |
1 << PG_referenced | 1 << PG_arch_1 |
1 << PG_owner_priv_1 | 1 << PG_mappedtodisk);
set_page_private(page, 0);
@@ -1050,7 +1050,7 @@ void split_page(struct page *page, unsigned int order)
* we cheat by calling it from here, in the order > 0 path. Saves a branch
* or two.
*/
-static struct page *buffered_rmqueue(struct zonelist *zonelist,
+static struct page *buffered_rmqueue(struct zone *preferred_zone,
struct zone *zone, int order, gfp_t gfp_flags)
{
unsigned long flags;
@@ -1102,7 +1102,7 @@ again:
}
__count_zone_vm_events(PGALLOC, zone, 1 << order);
- zone_statistics(zonelist, zone);
+ zone_statistics(preferred_zone, zone);
local_irq_restore(flags);
put_cpu();
@@ -1284,7 +1284,7 @@ static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags)
if (!zlc)
return NULL;
- if (time_after(jiffies, zlc->last_full_zap + HZ)) {
+ if (time_after(jiffies, zlc->last_full_zap + HZ)) {
bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST);
zlc->last_full_zap = jiffies;
}
@@ -1317,7 +1317,7 @@ static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags)
* We are low on memory in the second scan, and should leave no stone
* unturned looking for a free page.
*/
-static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zone **z,
+static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zoneref *z,
nodemask_t *allowednodes)
{
struct zonelist_cache *zlc; /* cached zonelist speedup info */
@@ -1328,7 +1328,7 @@ static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zone **z,
if (!zlc)
return 1;
- i = z - zonelist->zones;
+ i = z - zonelist->_zonerefs;
n = zlc->z_to_n[i];
/* This zone is worth trying if it is allowed but not full */
@@ -1340,7 +1340,7 @@ static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zone **z,
* zlc->fullzones, so that subsequent attempts to allocate a page
* from that zone don't waste time re-examining it.
*/
-static void zlc_mark_zone_full(struct zonelist *zonelist, struct zone **z)
+static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z)
{
struct zonelist_cache *zlc; /* cached zonelist speedup info */
int i; /* index of *z in zonelist zones */
@@ -1349,7 +1349,7 @@ static void zlc_mark_zone_full(struct zonelist *zonelist, struct zone **z)
if (!zlc)
return;
- i = z - zonelist->zones;
+ i = z - zonelist->_zonerefs;
set_bit(i, zlc->fullzones);
}
@@ -1361,13 +1361,13 @@ static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags)
return NULL;
}
-static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zone **z,
+static int zlc_zone_worth_trying(struct zonelist *zonelist, struct zoneref *z,
nodemask_t *allowednodes)
{
return 1;
}
-static void zlc_mark_zone_full(struct zonelist *zonelist, struct zone **z)
+static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z)
{
}
#endif /* CONFIG_NUMA */
@@ -1377,42 +1377,31 @@ static void zlc_mark_zone_full(struct zonelist *zonelist, struct zone **z)
* a page.
*/
static struct page *
-get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
- struct zonelist *zonelist, int alloc_flags)
+get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order,
+ struct zonelist *zonelist, int high_zoneidx, int alloc_flags)
{
- struct zone **z;
+ struct zoneref *z;
struct page *page = NULL;
- int classzone_idx = zone_idx(zonelist->zones[0]);
- struct zone *zone;
+ int classzone_idx;
+ struct zone *zone, *preferred_zone;
nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */
int zlc_active = 0; /* set if using zonelist_cache */
int did_zlc_setup = 0; /* just call zlc_setup() one time */
- enum zone_type highest_zoneidx = -1; /* Gets set for policy zonelists */
+
+ (void)first_zones_zonelist(zonelist, high_zoneidx, nodemask,
+ &preferred_zone);
+ classzone_idx = zone_idx(preferred_zone);
zonelist_scan:
/*
* Scan zonelist, looking for a zone with enough free.
* See also cpuset_zone_allowed() comment in kernel/cpuset.c.
*/
- z = zonelist->zones;
-
- do {
- /*
- * In NUMA, this could be a policy zonelist which contains
- * zones that may not be allowed by the current gfp_mask.
- * Check the zone is allowed by the current flags
- */
- if (unlikely(alloc_should_filter_zonelist(zonelist))) {
- if (highest_zoneidx == -1)
- highest_zoneidx = gfp_zone(gfp_mask);
- if (zone_idx(*z) > highest_zoneidx)
- continue;
- }
-
+ for_each_zone_zonelist_nodemask(zone, z, zonelist,
+ high_zoneidx, nodemask) {
if (NUMA_BUILD && zlc_active &&
!zlc_zone_worth_trying(zonelist, z, allowednodes))
continue;
- zone = *z;
if ((alloc_flags & ALLOC_CPUSET) &&
!cpuset_zone_allowed_softwall(zone, gfp_mask))
goto try_next_zone;
@@ -1433,7 +1422,7 @@ zonelist_scan:
}
}
- page = buffered_rmqueue(zonelist, zone, order, gfp_mask);
+ page = buffered_rmqueue(preferred_zone, zone, order, gfp_mask);
if (page)
break;
this_zone_full:
@@ -1446,7 +1435,7 @@ try_next_zone:
zlc_active = 1;
did_zlc_setup = 1;
}
- } while (*(++z) != NULL);
+ }
if (unlikely(NUMA_BUILD && page == NULL && zlc_active)) {
/* Disable zlc cache for second zonelist scan */
@@ -1459,12 +1448,14 @@ try_next_zone:
/*
* This is the 'heart' of the zoned buddy allocator.
*/
-struct page *
-__alloc_pages(gfp_t gfp_mask, unsigned int order,
- struct zonelist *zonelist)
+static struct page *
+__alloc_pages_internal(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, nodemask_t *nodemask)
{
const gfp_t wait = gfp_mask & __GFP_WAIT;
- struct zone **z;
+ enum zone_type high_zoneidx = gfp_zone(gfp_mask);
+ struct zoneref *z;
+ struct zone *zone;
struct page *page;
struct reclaim_state reclaim_state;
struct task_struct *p = current;
@@ -1478,9 +1469,9 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order,
return NULL;
restart:
- z = zonelist->zones; /* the list of zones suitable for gfp_mask */
+ z = zonelist->_zonerefs; /* the list of zones suitable for gfp_mask */
- if (unlikely(*z == NULL)) {
+ if (unlikely(!z->zone)) {
/*
* Happens if we have an empty zonelist as a result of
* GFP_THISNODE being used on a memoryless node
@@ -1488,8 +1479,8 @@ restart:
return NULL;
}
- page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
- zonelist, ALLOC_WMARK_LOW|ALLOC_CPUSET);
+ page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
+ zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET);
if (page)
goto got_pg;
@@ -1504,8 +1495,8 @@ restart:
if (NUMA_BUILD && (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
goto nopage;
- for (z = zonelist->zones; *z; z++)
- wakeup_kswapd(*z, order);
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
+ wakeup_kswapd(zone, order);
/*
* OK, we're below the kswapd watermark and have kicked background
@@ -1533,7 +1524,8 @@ restart:
* Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
* See also cpuset_zone_allowed() comment in kernel/cpuset.c.
*/
- page = get_page_from_freelist(gfp_mask, order, zonelist, alloc_flags);
+ page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
+ high_zoneidx, alloc_flags);
if (page)
goto got_pg;
@@ -1545,8 +1537,8 @@ rebalance:
if (!(gfp_mask & __GFP_NOMEMALLOC)) {
nofail_alloc:
/* go through the zonelist yet again, ignoring mins */
- page = get_page_from_freelist(gfp_mask, order,
- zonelist, ALLOC_NO_WATERMARKS);
+ page = get_page_from_freelist(gfp_mask, nodemask, order,
+ zonelist, high_zoneidx, ALLOC_NO_WATERMARKS);
if (page)
goto got_pg;
if (gfp_mask & __GFP_NOFAIL) {
@@ -1569,7 +1561,7 @@ nofail_alloc:
reclaim_state.reclaimed_slab = 0;
p->reclaim_state = &reclaim_state;
- did_some_progress = try_to_free_pages(zonelist->zones, order, gfp_mask);
+ did_some_progress = try_to_free_pages(zonelist, order, gfp_mask);
p->reclaim_state = NULL;
p->flags &= ~PF_MEMALLOC;
@@ -1580,12 +1572,12 @@ nofail_alloc:
drain_all_pages();
if (likely(did_some_progress)) {
- page = get_page_from_freelist(gfp_mask, order,
- zonelist, alloc_flags);
+ page = get_page_from_freelist(gfp_mask, nodemask, order,
+ zonelist, high_zoneidx, alloc_flags);
if (page)
goto got_pg;
} else if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
- if (!try_set_zone_oom(zonelist)) {
+ if (!try_set_zone_oom(zonelist, gfp_mask)) {
schedule_timeout_uninterruptible(1);
goto restart;
}
@@ -1596,21 +1588,22 @@ nofail_alloc:
* a parallel oom killing, we must fail if we're still
* under heavy pressure.
*/
- page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
- zonelist, ALLOC_WMARK_HIGH|ALLOC_CPUSET);
+ page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask,
+ order, zonelist, high_zoneidx,
+ ALLOC_WMARK_HIGH|ALLOC_CPUSET);
if (page) {
- clear_zonelist_oom(zonelist);
+ clear_zonelist_oom(zonelist, gfp_mask);
goto got_pg;
}
/* The OOM killer will not help higher order allocs so fail */
if (order > PAGE_ALLOC_COSTLY_ORDER) {
- clear_zonelist_oom(zonelist);
+ clear_zonelist_oom(zonelist, gfp_mask);
goto nopage;
}
out_of_memory(zonelist, gfp_mask, order);
- clear_zonelist_oom(zonelist);
+ clear_zonelist_oom(zonelist, gfp_mask);
goto restart;
}
@@ -1646,6 +1639,20 @@ got_pg:
return page;
}
+struct page *
+__alloc_pages(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist)
+{
+ return __alloc_pages_internal(gfp_mask, order, zonelist, NULL);
+}
+
+struct page *
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, nodemask_t *nodemask)
+{
+ return __alloc_pages_internal(gfp_mask, order, zonelist, nodemask);
+}
+
EXPORT_SYMBOL(__alloc_pages);
/*
@@ -1712,15 +1719,15 @@ EXPORT_SYMBOL(free_pages);
static unsigned int nr_free_zone_pages(int offset)
{
+ struct zoneref *z;
+ struct zone *zone;
+
/* Just pick one node, since fallback list is circular */
- pg_data_t *pgdat = NODE_DATA(numa_node_id());
unsigned int sum = 0;
- struct zonelist *zonelist = pgdat->node_zonelists + offset;
- struct zone **zonep = zonelist->zones;
- struct zone *zone;
+ struct zonelist *zonelist = node_zonelist(numa_node_id(), GFP_KERNEL);
- for (zone = *zonep++; zone; zone = *zonep++) {
+ for_each_zone_zonelist(zone, z, zonelist, offset) {
unsigned long size = zone->present_pages;
unsigned long high = zone->pages_high;
if (size > high)
@@ -1889,6 +1896,12 @@ void show_free_areas(void)
show_swap_cache_info();
}
+static void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
+{
+ zoneref->zone = zone;
+ zoneref->zone_idx = zone_idx(zone);
+}
+
/*
* Builds allocation fallback zone lists.
*
@@ -1906,7 +1919,8 @@ static int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist,
zone_type--;
zone = pgdat->node_zones + zone_type;
if (populated_zone(zone)) {
- zonelist->zones[nr_zones++] = zone;
+ zoneref_set_zone(zone,
+ &zonelist->_zonerefs[nr_zones++]);
check_highest_zone(zone_type);
}
@@ -2078,17 +2092,16 @@ static int find_next_best_node(int node, nodemask_t *used_node_mask)
*/
static void build_zonelists_in_node_order(pg_data_t *pgdat, int node)
{
- enum zone_type i;
int j;
struct zonelist *zonelist;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- zonelist = pgdat->node_zonelists + i;
- for (j = 0; zonelist->zones[j] != NULL; j++)
- ;
- j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
- zonelist->zones[j] = NULL;
- }
+ zonelist = &pgdat->node_zonelists[0];
+ for (j = 0; zonelist->_zonerefs[j].zone != NULL; j++)
+ ;
+ j = build_zonelists_node(NODE_DATA(node), zonelist, j,
+ MAX_NR_ZONES - 1);
+ zonelist->_zonerefs[j].zone = NULL;
+ zonelist->_zonerefs[j].zone_idx = 0;
}
/*
@@ -2096,15 +2109,13 @@ static void build_zonelists_in_node_order(pg_data_t *pgdat, int node)
*/
static void build_thisnode_zonelists(pg_data_t *pgdat)
{
- enum zone_type i;
int j;
struct zonelist *zonelist;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- zonelist = pgdat->node_zonelists + MAX_NR_ZONES + i;
- j = build_zonelists_node(pgdat, zonelist, 0, i);
- zonelist->zones[j] = NULL;
- }
+ zonelist = &pgdat->node_zonelists[1];
+ j = build_zonelists_node(pgdat, zonelist, 0, MAX_NR_ZONES - 1);
+ zonelist->_zonerefs[j].zone = NULL;
+ zonelist->_zonerefs[j].zone_idx = 0;
}
/*
@@ -2117,27 +2128,26 @@ static int node_order[MAX_NUMNODES];
static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes)
{
- enum zone_type i;
int pos, j, node;
int zone_type; /* needs to be signed */
struct zone *z;
struct zonelist *zonelist;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- zonelist = pgdat->node_zonelists + i;
- pos = 0;
- for (zone_type = i; zone_type >= 0; zone_type--) {
- for (j = 0; j < nr_nodes; j++) {
- node = node_order[j];
- z = &NODE_DATA(node)->node_zones[zone_type];
- if (populated_zone(z)) {
- zonelist->zones[pos++] = z;
- check_highest_zone(zone_type);
- }
+ zonelist = &pgdat->node_zonelists[0];
+ pos = 0;
+ for (zone_type = MAX_NR_ZONES - 1; zone_type >= 0; zone_type--) {
+ for (j = 0; j < nr_nodes; j++) {
+ node = node_order[j];
+ z = &NODE_DATA(node)->node_zones[zone_type];
+ if (populated_zone(z)) {
+ zoneref_set_zone(z,
+ &zonelist->_zonerefs[pos++]);
+ check_highest_zone(zone_type);
}
}
- zonelist->zones[pos] = NULL;
}
+ zonelist->_zonerefs[pos].zone = NULL;
+ zonelist->_zonerefs[pos].zone_idx = 0;
}
static int default_zonelist_order(void)
@@ -2214,7 +2224,8 @@ static void build_zonelists(pg_data_t *pgdat)
/* initialize zonelists */
for (i = 0; i < MAX_ZONELISTS; i++) {
zonelist = pgdat->node_zonelists + i;
- zonelist->zones[0] = NULL;
+ zonelist->_zonerefs[0].zone = NULL;
+ zonelist->_zonerefs[0].zone_idx = 0;
}
/* NUMA-aware ordering of nodes */
@@ -2264,19 +2275,15 @@ static void build_zonelists(pg_data_t *pgdat)
/* Construct the zonelist performance cache - see further mmzone.h */
static void build_zonelist_cache(pg_data_t *pgdat)
{
- int i;
-
- for (i = 0; i < MAX_NR_ZONES; i++) {
- struct zonelist *zonelist;
- struct zonelist_cache *zlc;
- struct zone **z;
+ struct zonelist *zonelist;
+ struct zonelist_cache *zlc;
+ struct zoneref *z;
- zonelist = pgdat->node_zonelists + i;
- zonelist->zlcache_ptr = zlc = &zonelist->zlcache;
- bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST);
- for (z = zonelist->zones; *z; z++)
- zlc->z_to_n[z - zonelist->zones] = zone_to_nid(*z);
- }
+ zonelist = &pgdat->node_zonelists[0];
+ zonelist->zlcache_ptr = zlc = &zonelist->zlcache;
+ bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST);
+ for (z = zonelist->_zonerefs; z->zone; z++)
+ zlc->z_to_n[z - zonelist->_zonerefs] = zonelist_node_idx(z);
}
@@ -2290,45 +2297,44 @@ static void set_zonelist_order(void)
static void build_zonelists(pg_data_t *pgdat)
{
int node, local_node;
- enum zone_type i,j;
+ enum zone_type j;
+ struct zonelist *zonelist;
local_node = pgdat->node_id;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- struct zonelist *zonelist;
- zonelist = pgdat->node_zonelists + i;
+ zonelist = &pgdat->node_zonelists[0];
+ j = build_zonelists_node(pgdat, zonelist, 0, MAX_NR_ZONES - 1);
- j = build_zonelists_node(pgdat, zonelist, 0, i);
- /*
- * Now we build the zonelist so that it contains the zones
- * of all the other nodes.
- * We don't want to pressure a particular node, so when
- * building the zones for node N, we make sure that the
- * zones coming right after the local ones are those from
- * node N+1 (modulo N)
- */
- for (node = local_node + 1; node < MAX_NUMNODES; node++) {
- if (!node_online(node))
- continue;
- j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
- }
- for (node = 0; node < local_node; node++) {
- if (!node_online(node))
- continue;
- j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
- }
-
- zonelist->zones[j] = NULL;
+ /*
+ * Now we build the zonelist so that it contains the zones
+ * of all the other nodes.
+ * We don't want to pressure a particular node, so when
+ * building the zones for node N, we make sure that the
+ * zones coming right after the local ones are those from
+ * node N+1 (modulo N)
+ */
+ for (node = local_node + 1; node < MAX_NUMNODES; node++) {
+ if (!node_online(node))
+ continue;
+ j = build_zonelists_node(NODE_DATA(node), zonelist, j,
+ MAX_NR_ZONES - 1);
+ }
+ for (node = 0; node < local_node; node++) {
+ if (!node_online(node))
+ continue;
+ j = build_zonelists_node(NODE_DATA(node), zonelist, j,
+ MAX_NR_ZONES - 1);
}
+
+ zonelist->_zonerefs[j].zone = NULL;
+ zonelist->_zonerefs[j].zone_idx = 0;
}
/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */
static void build_zonelist_cache(pg_data_t *pgdat)
{
- int i;
-
- for (i = 0; i < MAX_NR_ZONES; i++)
- pgdat->node_zonelists[i].zlcache_ptr = NULL;
+ pgdat->node_zonelists[0].zlcache_ptr = NULL;
+ pgdat->node_zonelists[1].zlcache_ptr = NULL;
}
#endif /* CONFIG_NUMA */
@@ -4339,9 +4345,7 @@ void *__init alloc_large_system_hash(const char *tablename,
else if (hashdist)
table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
else {
- unsigned long order;
- for (order = 0; ((1UL << order) << PAGE_SHIFT) < size; order++)
- ;
+ unsigned long order = get_order(size);
table = (void*) __get_free_pages(GFP_ATOMIC, order);
/*
* If bucketsize is not a power-of-two, we may free
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 1cf1417ef8b7..0afd2387e507 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -9,11 +9,15 @@ static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
int err = 0;
pte = pte_offset_map(pmd, addr);
- do {
+ for (;;) {
err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private);
if (err)
break;
- } while (pte++, addr += PAGE_SIZE, addr != end);
+ addr += PAGE_SIZE;
+ if (addr == end)
+ break;
+ pte++;
+ }
pte_unmap(pte);
return err;
diff --git a/mm/rmap.c b/mm/rmap.c
index 997f06907b6d..bf0a5b7cfb8e 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -413,9 +413,6 @@ int page_referenced(struct page *page, int is_locked,
{
int referenced = 0;
- if (page_test_and_clear_young(page))
- referenced++;
-
if (TestClearPageReferenced(page))
referenced++;
@@ -433,6 +430,10 @@ int page_referenced(struct page *page, int is_locked,
unlock_page(page);
}
}
+
+ if (page_test_and_clear_young(page))
+ referenced++;
+
return referenced;
}
@@ -661,7 +662,6 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
printk (KERN_EMERG " page->mapping = %p\n", page->mapping);
print_symbol (KERN_EMERG " vma->vm_ops = %s\n", (unsigned long)vma->vm_ops);
if (vma->vm_ops) {
- print_symbol (KERN_EMERG " vma->vm_ops->nopage = %s\n", (unsigned long)vma->vm_ops->nopage);
print_symbol (KERN_EMERG " vma->vm_ops->fault = %s\n", (unsigned long)vma->vm_ops->fault);
}
if (vma->vm_file && vma->vm_file->f_op)
diff --git a/mm/shmem.c b/mm/shmem.c
index f514dd392cd9..e6d9298aa22a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1079,104 +1079,47 @@ redirty:
#ifdef CONFIG_NUMA
#ifdef CONFIG_TMPFS
-static int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes)
+static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
{
- char *nodelist = strchr(value, ':');
- int err = 1;
+ char buffer[64];
- if (nodelist) {
- /* NUL-terminate policy string */
- *nodelist++ = '\0';
- if (nodelist_parse(nodelist, *policy_nodes))
- goto out;
- if (!nodes_subset(*policy_nodes, node_states[N_HIGH_MEMORY]))
- goto out;
- }
- if (!strcmp(value, "default")) {
- *policy = MPOL_DEFAULT;
- /* Don't allow a nodelist */
- if (!nodelist)
- err = 0;
- } else if (!strcmp(value, "prefer")) {
- *policy = MPOL_PREFERRED;
- /* Insist on a nodelist of one node only */
- if (nodelist) {
- char *rest = nodelist;
- while (isdigit(*rest))
- rest++;
- if (!*rest)
- err = 0;
- }
- } else if (!strcmp(value, "bind")) {
- *policy = MPOL_BIND;
- /* Insist on a nodelist */
- if (nodelist)
- err = 0;
- } else if (!strcmp(value, "interleave")) {
- *policy = MPOL_INTERLEAVE;
- /*
- * Default to online nodes with memory if no nodelist
- */
- if (!nodelist)
- *policy_nodes = node_states[N_HIGH_MEMORY];
- err = 0;
- }
-out:
- /* Restore string for error message */
- if (nodelist)
- *--nodelist = ':';
- return err;
-}
-
-static void shmem_show_mpol(struct seq_file *seq, int policy,
- const nodemask_t policy_nodes)
-{
- char *policy_string;
+ if (!mpol || mpol->mode == MPOL_DEFAULT)
+ return; /* show nothing */
- switch (policy) {
- case MPOL_PREFERRED:
- policy_string = "prefer";
- break;
- case MPOL_BIND:
- policy_string = "bind";
- break;
- case MPOL_INTERLEAVE:
- policy_string = "interleave";
- break;
- default:
- /* MPOL_DEFAULT */
- return;
- }
+ mpol_to_str(buffer, sizeof(buffer), mpol, 1);
- seq_printf(seq, ",mpol=%s", policy_string);
-
- if (policy != MPOL_INTERLEAVE ||
- !nodes_equal(policy_nodes, node_states[N_HIGH_MEMORY])) {
- char buffer[64];
- int len;
+ seq_printf(seq, ",mpol=%s", buffer);
+}
- len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes);
- if (len < sizeof(buffer))
- seq_printf(seq, ":%s", buffer);
- else
- seq_printf(seq, ":?");
+static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
+{
+ struct mempolicy *mpol = NULL;
+ if (sbinfo->mpol) {
+ spin_lock(&sbinfo->stat_lock); /* prevent replace/use races */
+ mpol = sbinfo->mpol;
+ mpol_get(mpol);
+ spin_unlock(&sbinfo->stat_lock);
}
+ return mpol;
}
#endif /* CONFIG_TMPFS */
static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
struct shmem_inode_info *info, unsigned long idx)
{
+ struct mempolicy mpol, *spol;
struct vm_area_struct pvma;
struct page *page;
+ spol = mpol_cond_copy(&mpol,
+ mpol_shared_policy_lookup(&info->policy, idx));
+
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
pvma.vm_pgoff = idx;
pvma.vm_ops = NULL;
- pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
+ pvma.vm_policy = spol;
page = swapin_readahead(entry, gfp, &pvma, 0);
- mpol_free(pvma.vm_policy);
return page;
}
@@ -1184,27 +1127,21 @@ static struct page *shmem_alloc_page(gfp_t gfp,
struct shmem_inode_info *info, unsigned long idx)
{
struct vm_area_struct pvma;
- struct page *page;
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
pvma.vm_pgoff = idx;
pvma.vm_ops = NULL;
pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
- page = alloc_page_vma(gfp, &pvma, 0);
- mpol_free(pvma.vm_policy);
- return page;
+
+ /*
+ * alloc_page_vma() will drop the shared policy reference
+ */
+ return alloc_page_vma(gfp, &pvma, 0);
}
#else /* !CONFIG_NUMA */
#ifdef CONFIG_TMPFS
-static inline int shmem_parse_mpol(char *value, int *policy,
- nodemask_t *policy_nodes)
-{
- return 1;
-}
-
-static inline void shmem_show_mpol(struct seq_file *seq, int policy,
- const nodemask_t policy_nodes)
+static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *p)
{
}
#endif /* CONFIG_TMPFS */
@@ -1222,6 +1159,13 @@ static inline struct page *shmem_alloc_page(gfp_t gfp,
}
#endif /* CONFIG_NUMA */
+#if !defined(CONFIG_NUMA) || !defined(CONFIG_TMPFS)
+static inline struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
+{
+ return NULL;
+}
+#endif
+
/*
* shmem_getpage - either get the page from swap or allocate a new one
*
@@ -1576,8 +1520,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
case S_IFREG:
inode->i_op = &shmem_inode_operations;
inode->i_fop = &shmem_file_operations;
- mpol_shared_policy_init(&info->policy, sbinfo->policy,
- &sbinfo->policy_nodes);
+ mpol_shared_policy_init(&info->policy,
+ shmem_get_sbmpol(sbinfo));
break;
case S_IFDIR:
inc_nlink(inode);
@@ -1591,8 +1535,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
* Must not load anything in the rbtree,
* mpol_free_shared_policy will not be called.
*/
- mpol_shared_policy_init(&info->policy, MPOL_DEFAULT,
- NULL);
+ mpol_shared_policy_init(&info->policy, NULL);
break;
}
} else
@@ -2207,8 +2150,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"mpol")) {
- if (shmem_parse_mpol(value, &sbinfo->policy,
- &sbinfo->policy_nodes))
+ if (mpol_parse_str(value, &sbinfo->mpol, 1))
goto bad_val;
} else {
printk(KERN_ERR "tmpfs: Bad mount option %s\n",
@@ -2259,8 +2201,9 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
sbinfo->free_blocks = config.max_blocks - blocks;
sbinfo->max_inodes = config.max_inodes;
sbinfo->free_inodes = config.max_inodes - inodes;
- sbinfo->policy = config.policy;
- sbinfo->policy_nodes = config.policy_nodes;
+
+ mpol_put(sbinfo->mpol);
+ sbinfo->mpol = config.mpol; /* transfers initial ref */
out:
spin_unlock(&sbinfo->stat_lock);
return error;
@@ -2281,7 +2224,7 @@ static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_printf(seq, ",uid=%u", sbinfo->uid);
if (sbinfo->gid != 0)
seq_printf(seq, ",gid=%u", sbinfo->gid);
- shmem_show_mpol(seq, sbinfo->policy, sbinfo->policy_nodes);
+ shmem_show_mpol(seq, sbinfo->mpol);
return 0;
}
#endif /* CONFIG_TMPFS */
@@ -2311,8 +2254,7 @@ static int shmem_fill_super(struct super_block *sb,
sbinfo->mode = S_IRWXUGO | S_ISVTX;
sbinfo->uid = current->fsuid;
sbinfo->gid = current->fsgid;
- sbinfo->policy = MPOL_DEFAULT;
- sbinfo->policy_nodes = node_states[N_HIGH_MEMORY];
+ sbinfo->mpol = NULL;
sb->s_fs_info = sbinfo;
#ifdef CONFIG_TMPFS
diff --git a/mm/slab.c b/mm/slab.c
index 03927cb5ec9e..39d20f8a0791 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -139,10 +139,6 @@
#define BYTES_PER_WORD sizeof(void *)
#define REDZONE_ALIGN max(BYTES_PER_WORD, __alignof__(unsigned long long))
-#ifndef cache_line_size
-#define cache_line_size() L1_CACHE_BYTES
-#endif
-
#ifndef ARCH_KMALLOC_MINALIGN
/*
* Enforce a minimum alignment for the kmalloc caches.
@@ -3242,15 +3238,16 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
{
struct zonelist *zonelist;
gfp_t local_flags;
- struct zone **z;
+ struct zoneref *z;
+ struct zone *zone;
+ enum zone_type high_zoneidx = gfp_zone(flags);
void *obj = NULL;
int nid;
if (flags & __GFP_THISNODE)
return NULL;
- zonelist = &NODE_DATA(slab_node(current->mempolicy))
- ->node_zonelists[gfp_zone(flags)];
+ zonelist = node_zonelist(slab_node(current->mempolicy), flags);
local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
retry:
@@ -3258,10 +3255,10 @@ retry:
* Look through allowed nodes for objects available
* from existing per node queues.
*/
- for (z = zonelist->zones; *z && !obj; z++) {
- nid = zone_to_nid(*z);
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
+ nid = zone_to_nid(zone);
- if (cpuset_zone_allowed_hardwall(*z, flags) &&
+ if (cpuset_zone_allowed_hardwall(zone, flags) &&
cache->nodelists[nid] &&
cache->nodelists[nid]->free_objects)
obj = ____cache_alloc_node(cache,
diff --git a/mm/slob.c b/mm/slob.c
index e2c3c0ec5463..6038cbadf796 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -533,7 +533,8 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
{
struct kmem_cache *c;
- c = slob_alloc(sizeof(struct kmem_cache), flags, 0, -1);
+ c = slob_alloc(sizeof(struct kmem_cache),
+ flags, ARCH_KMALLOC_MINALIGN, -1);
if (c) {
c->name = name;
diff --git a/mm/slub.c b/mm/slub.c
index 39592b5ce68a..992ecd4f0d39 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -149,25 +149,6 @@ static inline void ClearSlabDebug(struct page *page)
/* Enable to test recovery from slab corruption on boot */
#undef SLUB_RESILIENCY_TEST
-#if PAGE_SHIFT <= 12
-
-/*
- * Small page size. Make sure that we do not fragment memory
- */
-#define DEFAULT_MAX_ORDER 1
-#define DEFAULT_MIN_OBJECTS 4
-
-#else
-
-/*
- * Large page machines are customarily able to handle larger
- * page orders.
- */
-#define DEFAULT_MAX_ORDER 2
-#define DEFAULT_MIN_OBJECTS 8
-
-#endif
-
/*
* Mininum number of partial slabs. These will be left on the partial
* lists even if they are empty. kmem_cache_shrink may reclaim them.
@@ -204,13 +185,6 @@ static inline void ClearSlabDebug(struct page *page)
/* Internal SLUB flags */
#define __OBJECT_POISON 0x80000000 /* Poison object */
#define __SYSFS_ADD_DEFERRED 0x40000000 /* Not yet visible via sysfs */
-#define __KMALLOC_CACHE 0x20000000 /* objects freed using kfree */
-#define __PAGE_ALLOC_FALLBACK 0x10000000 /* Allow fallback to page alloc */
-
-/* Not all arches define cache_line_size */
-#ifndef cache_line_size
-#define cache_line_size() L1_CACHE_BYTES
-#endif
static int kmem_size = sizeof(struct kmem_cache);
@@ -301,7 +275,7 @@ static inline int check_valid_pointer(struct kmem_cache *s,
return 1;
base = page_address(page);
- if (object < base || object >= base + s->objects * s->size ||
+ if (object < base || object >= base + page->objects * s->size ||
(object - base) % s->size) {
return 0;
}
@@ -327,8 +301,8 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
}
/* Loop over all objects in a slab */
-#define for_each_object(__p, __s, __addr) \
- for (__p = (__addr); __p < (__addr) + (__s)->objects * (__s)->size;\
+#define for_each_object(__p, __s, __addr, __objects) \
+ for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\
__p += (__s)->size)
/* Scan freelist */
@@ -341,6 +315,26 @@ static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
return (p - addr) / s->size;
}
+static inline struct kmem_cache_order_objects oo_make(int order,
+ unsigned long size)
+{
+ struct kmem_cache_order_objects x = {
+ (order << 16) + (PAGE_SIZE << order) / size
+ };
+
+ return x;
+}
+
+static inline int oo_order(struct kmem_cache_order_objects x)
+{
+ return x.x >> 16;
+}
+
+static inline int oo_objects(struct kmem_cache_order_objects x)
+{
+ return x.x & ((1 << 16) - 1);
+}
+
#ifdef CONFIG_SLUB_DEBUG
/*
* Debug settings:
@@ -451,8 +445,8 @@ static void print_tracking(struct kmem_cache *s, void *object)
static void print_page_info(struct page *page)
{
- printk(KERN_ERR "INFO: Slab 0x%p used=%u fp=0x%p flags=0x%04lx\n",
- page, page->inuse, page->freelist, page->flags);
+ printk(KERN_ERR "INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n",
+ page, page->objects, page->inuse, page->freelist, page->flags);
}
@@ -652,6 +646,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
p + off, POISON_INUSE, s->size - off);
}
+/* Check the pad bytes at the end of a slab page */
static int slab_pad_check(struct kmem_cache *s, struct page *page)
{
u8 *start;
@@ -664,20 +659,20 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
return 1;
start = page_address(page);
- end = start + (PAGE_SIZE << s->order);
- length = s->objects * s->size;
- remainder = end - (start + length);
+ length = (PAGE_SIZE << compound_order(page));
+ end = start + length;
+ remainder = length % s->size;
if (!remainder)
return 1;
- fault = check_bytes(start + length, POISON_INUSE, remainder);
+ fault = check_bytes(end - remainder, POISON_INUSE, remainder);
if (!fault)
return 1;
while (end > fault && end[-1] == POISON_INUSE)
end--;
slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1);
- print_section("Padding", start, length);
+ print_section("Padding", end - remainder, remainder);
restore_bytes(s, "slab padding", POISON_INUSE, start, end);
return 0;
@@ -739,15 +734,24 @@ static int check_object(struct kmem_cache *s, struct page *page,
static int check_slab(struct kmem_cache *s, struct page *page)
{
+ int maxobj;
+
VM_BUG_ON(!irqs_disabled());
if (!PageSlab(page)) {
slab_err(s, page, "Not a valid slab page");
return 0;
}
- if (page->inuse > s->objects) {
+
+ maxobj = (PAGE_SIZE << compound_order(page)) / s->size;
+ if (page->objects > maxobj) {
+ slab_err(s, page, "objects %u > max %u",
+ s->name, page->objects, maxobj);
+ return 0;
+ }
+ if (page->inuse > page->objects) {
slab_err(s, page, "inuse %u > max %u",
- s->name, page->inuse, s->objects);
+ s->name, page->inuse, page->objects);
return 0;
}
/* Slab_pad_check fixes things up after itself */
@@ -764,8 +768,9 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
int nr = 0;
void *fp = page->freelist;
void *object = NULL;
+ unsigned long max_objects;
- while (fp && nr <= s->objects) {
+ while (fp && nr <= page->objects) {
if (fp == search)
return 1;
if (!check_valid_pointer(s, page, fp)) {
@@ -777,7 +782,7 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
} else {
slab_err(s, page, "Freepointer corrupt");
page->freelist = NULL;
- page->inuse = s->objects;
+ page->inuse = page->objects;
slab_fix(s, "Freelist cleared");
return 0;
}
@@ -788,10 +793,20 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
nr++;
}
- if (page->inuse != s->objects - nr) {
+ max_objects = (PAGE_SIZE << compound_order(page)) / s->size;
+ if (max_objects > 65535)
+ max_objects = 65535;
+
+ if (page->objects != max_objects) {
+ slab_err(s, page, "Wrong number of objects. Found %d but "
+ "should be %d", page->objects, max_objects);
+ page->objects = max_objects;
+ slab_fix(s, "Number of objects adjusted.");
+ }
+ if (page->inuse != page->objects - nr) {
slab_err(s, page, "Wrong object count. Counter is %d but "
- "counted were %d", page->inuse, s->objects - nr);
- page->inuse = s->objects - nr;
+ "counted were %d", page->inuse, page->objects - nr);
+ page->inuse = page->objects - nr;
slab_fix(s, "Object count adjusted.");
}
return search == NULL;
@@ -845,7 +860,7 @@ static inline unsigned long slabs_node(struct kmem_cache *s, int node)
return atomic_long_read(&n->nr_slabs);
}
-static inline void inc_slabs_node(struct kmem_cache *s, int node)
+static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
{
struct kmem_cache_node *n = get_node(s, node);
@@ -855,14 +870,17 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node)
* dilemma by deferring the increment of the count during
* bootstrap (see early_kmem_cache_node_alloc).
*/
- if (!NUMA_BUILD || n)
+ if (!NUMA_BUILD || n) {
atomic_long_inc(&n->nr_slabs);
+ atomic_long_add(objects, &n->total_objects);
+ }
}
-static inline void dec_slabs_node(struct kmem_cache *s, int node)
+static inline void dec_slabs_node(struct kmem_cache *s, int node, int objects)
{
struct kmem_cache_node *n = get_node(s, node);
atomic_long_dec(&n->nr_slabs);
+ atomic_long_sub(objects, &n->total_objects);
}
/* Object debug checks for alloc/free paths */
@@ -910,7 +928,7 @@ bad:
* as used avoids touching the remaining objects.
*/
slab_fix(s, "Marking all objects used");
- page->inuse = s->objects;
+ page->inuse = page->objects;
page->freelist = NULL;
}
return 0;
@@ -1060,31 +1078,52 @@ static inline unsigned long kmem_cache_flags(unsigned long objsize,
static inline unsigned long slabs_node(struct kmem_cache *s, int node)
{ return 0; }
-static inline void inc_slabs_node(struct kmem_cache *s, int node) {}
-static inline void dec_slabs_node(struct kmem_cache *s, int node) {}
+static inline void inc_slabs_node(struct kmem_cache *s, int node,
+ int objects) {}
+static inline void dec_slabs_node(struct kmem_cache *s, int node,
+ int objects) {}
#endif
+
/*
* Slab allocation and freeing
*/
+static inline struct page *alloc_slab_page(gfp_t flags, int node,
+ struct kmem_cache_order_objects oo)
+{
+ int order = oo_order(oo);
+
+ if (node == -1)
+ return alloc_pages(flags, order);
+ else
+ return alloc_pages_node(node, flags, order);
+}
+
static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
- int pages = 1 << s->order;
+ struct kmem_cache_order_objects oo = s->oo;
flags |= s->allocflags;
- if (node == -1)
- page = alloc_pages(flags, s->order);
- else
- page = alloc_pages_node(node, flags, s->order);
-
- if (!page)
- return NULL;
+ page = alloc_slab_page(flags | __GFP_NOWARN | __GFP_NORETRY, node,
+ oo);
+ if (unlikely(!page)) {
+ oo = s->min;
+ /*
+ * Allocation may have failed due to fragmentation.
+ * Try a lower order alloc if possible
+ */
+ page = alloc_slab_page(flags, node, oo);
+ if (!page)
+ return NULL;
+ stat(get_cpu_slab(s, raw_smp_processor_id()), ORDER_FALLBACK);
+ }
+ page->objects = oo_objects(oo);
mod_zone_page_state(page_zone(page),
(s->flags & SLAB_RECLAIM_ACCOUNT) ?
NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
- pages);
+ 1 << oo_order(oo));
return page;
}
@@ -1111,7 +1150,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
if (!page)
goto out;
- inc_slabs_node(s, page_to_nid(page));
+ inc_slabs_node(s, page_to_nid(page), page->objects);
page->slab = s;
page->flags |= 1 << PG_slab;
if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
@@ -1121,10 +1160,10 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
start = page_address(page);
if (unlikely(s->flags & SLAB_POISON))
- memset(start, POISON_INUSE, PAGE_SIZE << s->order);
+ memset(start, POISON_INUSE, PAGE_SIZE << compound_order(page));
last = start;
- for_each_object(p, s, start) {
+ for_each_object(p, s, start, page->objects) {
setup_object(s, page, last);
set_freepointer(s, last, p);
last = p;
@@ -1140,13 +1179,15 @@ out:
static void __free_slab(struct kmem_cache *s, struct page *page)
{
- int pages = 1 << s->order;
+ int order = compound_order(page);
+ int pages = 1 << order;
if (unlikely(SlabDebug(page))) {
void *p;
slab_pad_check(s, page);
- for_each_object(p, s, page_address(page))
+ for_each_object(p, s, page_address(page),
+ page->objects)
check_object(s, page, p, 0);
ClearSlabDebug(page);
}
@@ -1158,7 +1199,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
__ClearPageSlab(page);
reset_page_mapcount(page);
- __free_pages(page, s->order);
+ __free_pages(page, order);
}
static void rcu_free_slab(struct rcu_head *h)
@@ -1184,7 +1225,7 @@ static void free_slab(struct kmem_cache *s, struct page *page)
static void discard_slab(struct kmem_cache *s, struct page *page)
{
- dec_slabs_node(s, page_to_nid(page));
+ dec_slabs_node(s, page_to_nid(page), page->objects);
free_slab(s, page);
}
@@ -1284,7 +1325,9 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
{
#ifdef CONFIG_NUMA
struct zonelist *zonelist;
- struct zone **z;
+ struct zoneref *z;
+ struct zone *zone;
+ enum zone_type high_zoneidx = gfp_zone(flags);
struct page *page;
/*
@@ -1309,14 +1352,13 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
get_cycles() % 1024 > s->remote_node_defrag_ratio)
return NULL;
- zonelist = &NODE_DATA(
- slab_node(current->mempolicy))->node_zonelists[gfp_zone(flags)];
- for (z = zonelist->zones; *z; z++) {
+ zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
struct kmem_cache_node *n;
- n = get_node(s, zone_to_nid(*z));
+ n = get_node(s, zone_to_nid(zone));
- if (n && cpuset_zone_allowed_hardwall(*z, flags) &&
+ if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
n->nr_partial > MIN_PARTIAL) {
page = get_partial_node(n);
if (page)
@@ -1519,7 +1561,7 @@ load_freelist:
goto debug;
c->freelist = object[c->offset];
- c->page->inuse = s->objects;
+ c->page->inuse = c->page->objects;
c->page->freelist = NULL;
c->node = page_to_nid(c->page);
unlock_out:
@@ -1556,27 +1598,6 @@ new_slab:
c->page = new;
goto load_freelist;
}
-
- /*
- * No memory available.
- *
- * If the slab uses higher order allocs but the object is
- * smaller than a page size then we can fallback in emergencies
- * to the page allocator via kmalloc_large. The page allocator may
- * have failed to obtain a higher order page and we can try to
- * allocate a single page if the object fits into a single page.
- * That is only possible if certain conditions are met that are being
- * checked when a slab is created.
- */
- if (!(gfpflags & __GFP_NORETRY) &&
- (s->flags & __PAGE_ALLOC_FALLBACK)) {
- if (gfpflags & __GFP_WAIT)
- local_irq_enable();
- object = kmalloc_large(s->objsize, gfpflags);
- if (gfpflags & __GFP_WAIT)
- local_irq_disable();
- return object;
- }
return NULL;
debug:
if (!alloc_debug_processing(s, c->page, object, addr))
@@ -1777,8 +1798,8 @@ static struct page *get_object_page(const void *x)
* take the list_lock.
*/
static int slub_min_order;
-static int slub_max_order = DEFAULT_MAX_ORDER;
-static int slub_min_objects = DEFAULT_MIN_OBJECTS;
+static int slub_max_order = PAGE_ALLOC_COSTLY_ORDER;
+static int slub_min_objects;
/*
* Merge control. If this is set then no merging of slab caches will occur.
@@ -1793,7 +1814,7 @@ static int slub_nomerge;
* system components. Generally order 0 allocations should be preferred since
* order 0 does not cause fragmentation in the page allocator. Larger objects
* be problematic to put into order 0 slabs because there may be too much
- * unused space left. We go to a higher order if more than 1/8th of the slab
+ * unused space left. We go to a higher order if more than 1/16th of the slab
* would be wasted.
*
* In order to reach satisfactory performance we must ensure that a minimum
@@ -1818,6 +1839,9 @@ static inline int slab_order(int size, int min_objects,
int rem;
int min_order = slub_min_order;
+ if ((PAGE_SIZE << min_order) / size > 65535)
+ return get_order(size * 65535) - 1;
+
for (order = max(min_order,
fls(min_objects * size - 1) - PAGE_SHIFT);
order <= max_order; order++) {
@@ -1852,8 +1876,10 @@ static inline int calculate_order(int size)
* we reduce the minimum objects required in a slab.
*/
min_objects = slub_min_objects;
+ if (!min_objects)
+ min_objects = 4 * (fls(nr_cpu_ids) + 1);
while (min_objects > 1) {
- fraction = 8;
+ fraction = 16;
while (fraction >= 4) {
order = slab_order(size, min_objects,
slub_max_order, fraction);
@@ -2095,7 +2121,7 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags,
init_tracking(kmalloc_caches, n);
#endif
init_kmem_cache_node(n);
- inc_slabs_node(kmalloc_caches, node);
+ inc_slabs_node(kmalloc_caches, node, page->objects);
/*
* lockdep requires consistent irq usage for each lock
@@ -2171,11 +2197,12 @@ static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
* calculate_sizes() determines the order and the distribution of data within
* a slab object.
*/
-static int calculate_sizes(struct kmem_cache *s)
+static int calculate_sizes(struct kmem_cache *s, int forced_order)
{
unsigned long flags = s->flags;
unsigned long size = s->objsize;
unsigned long align = s->align;
+ int order;
/*
* Round up object size to the next word boundary. We can only
@@ -2259,26 +2286,16 @@ static int calculate_sizes(struct kmem_cache *s)
*/
size = ALIGN(size, align);
s->size = size;
+ if (forced_order >= 0)
+ order = forced_order;
+ else
+ order = calculate_order(size);
- if ((flags & __KMALLOC_CACHE) &&
- PAGE_SIZE / size < slub_min_objects) {
- /*
- * Kmalloc cache that would not have enough objects in
- * an order 0 page. Kmalloc slabs can fallback to
- * page allocator order 0 allocs so take a reasonably large
- * order that will allows us a good number of objects.
- */
- s->order = max(slub_max_order, PAGE_ALLOC_COSTLY_ORDER);
- s->flags |= __PAGE_ALLOC_FALLBACK;
- s->allocflags |= __GFP_NOWARN;
- } else
- s->order = calculate_order(size);
-
- if (s->order < 0)
+ if (order < 0)
return 0;
s->allocflags = 0;
- if (s->order)
+ if (order)
s->allocflags |= __GFP_COMP;
if (s->flags & SLAB_CACHE_DMA)
@@ -2290,9 +2307,12 @@ static int calculate_sizes(struct kmem_cache *s)
/*
* Determine the number of objects per slab
*/
- s->objects = (PAGE_SIZE << s->order) / size;
+ s->oo = oo_make(order, size);
+ s->min = oo_make(get_order(size), size);
+ if (oo_objects(s->oo) > oo_objects(s->max))
+ s->max = s->oo;
- return !!s->objects;
+ return !!oo_objects(s->oo);
}
@@ -2308,7 +2328,7 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
s->align = align;
s->flags = kmem_cache_flags(size, flags, name, ctor);
- if (!calculate_sizes(s))
+ if (!calculate_sizes(s, -1))
goto error;
s->refcount = 1;
@@ -2325,7 +2345,7 @@ error:
if (flags & SLAB_PANIC)
panic("Cannot create slab %s size=%lu realsize=%u "
"order=%u offset=%u flags=%lx\n",
- s->name, (unsigned long)size, s->size, s->order,
+ s->name, (unsigned long)size, s->size, oo_order(s->oo),
s->offset, flags);
return 0;
}
@@ -2371,26 +2391,52 @@ const char *kmem_cache_name(struct kmem_cache *s)
}
EXPORT_SYMBOL(kmem_cache_name);
+static void list_slab_objects(struct kmem_cache *s, struct page *page,
+ const char *text)
+{
+#ifdef CONFIG_SLUB_DEBUG
+ void *addr = page_address(page);
+ void *p;
+ DECLARE_BITMAP(map, page->objects);
+
+ bitmap_zero(map, page->objects);
+ slab_err(s, page, "%s", text);
+ slab_lock(page);
+ for_each_free_object(p, s, page->freelist)
+ set_bit(slab_index(p, s, addr), map);
+
+ for_each_object(p, s, addr, page->objects) {
+
+ if (!test_bit(slab_index(p, s, addr), map)) {
+ printk(KERN_ERR "INFO: Object 0x%p @offset=%tu\n",
+ p, p - addr);
+ print_tracking(s, p);
+ }
+ }
+ slab_unlock(page);
+#endif
+}
+
/*
- * Attempt to free all slabs on a node. Return the number of slabs we
- * were unable to free.
+ * Attempt to free all partial slabs on a node.
*/
-static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
- struct list_head *list)
+static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
{
- int slabs_inuse = 0;
unsigned long flags;
struct page *page, *h;
spin_lock_irqsave(&n->list_lock, flags);
- list_for_each_entry_safe(page, h, list, lru)
+ list_for_each_entry_safe(page, h, &n->partial, lru) {
if (!page->inuse) {
list_del(&page->lru);
discard_slab(s, page);
- } else
- slabs_inuse++;
+ n->nr_partial--;
+ } else {
+ list_slab_objects(s, page,
+ "Objects remaining on kmem_cache_close()");
+ }
+ }
spin_unlock_irqrestore(&n->list_lock, flags);
- return slabs_inuse;
}
/*
@@ -2407,8 +2453,8 @@ static inline int kmem_cache_close(struct kmem_cache *s)
for_each_node_state(node, N_NORMAL_MEMORY) {
struct kmem_cache_node *n = get_node(s, node);
- n->nr_partial -= free_list(s, n, &n->partial);
- if (slabs_node(s, node))
+ free_partial(s, n);
+ if (n->nr_partial || slabs_node(s, node))
return 1;
}
free_kmem_cache_nodes(s);
@@ -2426,8 +2472,11 @@ void kmem_cache_destroy(struct kmem_cache *s)
if (!s->refcount) {
list_del(&s->list);
up_write(&slub_lock);
- if (kmem_cache_close(s))
- WARN_ON(1);
+ if (kmem_cache_close(s)) {
+ printk(KERN_ERR "SLUB %s: %s called for cache that "
+ "still has objects.\n", s->name, __func__);
+ dump_stack();
+ }
sysfs_slab_remove(s);
} else
up_write(&slub_lock);
@@ -2486,7 +2535,7 @@ static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s,
down_write(&slub_lock);
if (!kmem_cache_open(s, gfp_flags, name, size, ARCH_KMALLOC_MINALIGN,
- flags | __KMALLOC_CACHE, NULL))
+ flags, NULL))
goto panic;
list_add(&s->list, &slab_caches);
@@ -2734,8 +2783,9 @@ int kmem_cache_shrink(struct kmem_cache *s)
struct kmem_cache_node *n;
struct page *page;
struct page *t;
+ int objects = oo_objects(s->max);
struct list_head *slabs_by_inuse =
- kmalloc(sizeof(struct list_head) * s->objects, GFP_KERNEL);
+ kmalloc(sizeof(struct list_head) * objects, GFP_KERNEL);
unsigned long flags;
if (!slabs_by_inuse)
@@ -2748,7 +2798,7 @@ int kmem_cache_shrink(struct kmem_cache *s)
if (!n->nr_partial)
continue;
- for (i = 0; i < s->objects; i++)
+ for (i = 0; i < objects; i++)
INIT_LIST_HEAD(slabs_by_inuse + i);
spin_lock_irqsave(&n->list_lock, flags);
@@ -2780,7 +2830,7 @@ int kmem_cache_shrink(struct kmem_cache *s)
* Rebuild the partial list with the slabs filled up most
* first and the least used slabs at the end.
*/
- for (i = s->objects - 1; i >= 0; i--)
+ for (i = objects - 1; i >= 0; i--)
list_splice(slabs_by_inuse + i, n->partial.prev);
spin_unlock_irqrestore(&n->list_lock, flags);
@@ -3001,9 +3051,6 @@ static int slab_unmergeable(struct kmem_cache *s)
if (slub_nomerge || (s->flags & SLUB_NEVER_MERGE))
return 1;
- if ((s->flags & __PAGE_ALLOC_FALLBACK))
- return 1;
-
if (s->ctor)
return 1;
@@ -3196,7 +3243,8 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
}
#if (defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)) || defined(CONFIG_SLABINFO)
-static unsigned long count_partial(struct kmem_cache_node *n)
+static unsigned long count_partial(struct kmem_cache_node *n,
+ int (*get_count)(struct page *))
{
unsigned long flags;
unsigned long x = 0;
@@ -3204,10 +3252,25 @@ static unsigned long count_partial(struct kmem_cache_node *n)
spin_lock_irqsave(&n->list_lock, flags);
list_for_each_entry(page, &n->partial, lru)
- x += page->inuse;
+ x += get_count(page);
spin_unlock_irqrestore(&n->list_lock, flags);
return x;
}
+
+static int count_inuse(struct page *page)
+{
+ return page->inuse;
+}
+
+static int count_total(struct page *page)
+{
+ return page->objects;
+}
+
+static int count_free(struct page *page)
+{
+ return page->objects - page->inuse;
+}
#endif
#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
@@ -3222,7 +3285,7 @@ static int validate_slab(struct kmem_cache *s, struct page *page,
return 0;
/* Now we know that a valid freelist exists */
- bitmap_zero(map, s->objects);
+ bitmap_zero(map, page->objects);
for_each_free_object(p, s, page->freelist) {
set_bit(slab_index(p, s, addr), map);
@@ -3230,7 +3293,7 @@ static int validate_slab(struct kmem_cache *s, struct page *page,
return 0;
}
- for_each_object(p, s, addr)
+ for_each_object(p, s, addr, page->objects)
if (!test_bit(slab_index(p, s, addr), map))
if (!check_object(s, page, p, 1))
return 0;
@@ -3296,7 +3359,7 @@ static long validate_slab_cache(struct kmem_cache *s)
{
int node;
unsigned long count = 0;
- unsigned long *map = kmalloc(BITS_TO_LONGS(s->objects) *
+ unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) *
sizeof(unsigned long), GFP_KERNEL);
if (!map)
@@ -3499,14 +3562,14 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,
struct page *page, enum track_item alloc)
{
void *addr = page_address(page);
- DECLARE_BITMAP(map, s->objects);
+ DECLARE_BITMAP(map, page->objects);
void *p;
- bitmap_zero(map, s->objects);
+ bitmap_zero(map, page->objects);
for_each_free_object(p, s, page->freelist)
set_bit(slab_index(p, s, addr), map);
- for_each_object(p, s, addr)
+ for_each_object(p, s, addr, page->objects)
if (!test_bit(slab_index(p, s, addr), map))
add_location(t, s, get_track(s, p, alloc));
}
@@ -3596,22 +3659,23 @@ static int list_locations(struct kmem_cache *s, char *buf,
}
enum slab_stat_type {
- SL_FULL,
- SL_PARTIAL,
- SL_CPU,
- SL_OBJECTS
+ SL_ALL, /* All slabs */
+ SL_PARTIAL, /* Only partially allocated slabs */
+ SL_CPU, /* Only slabs used for cpu caches */
+ SL_OBJECTS, /* Determine allocated objects not slabs */
+ SL_TOTAL /* Determine object capacity not slabs */
};
-#define SO_FULL (1 << SL_FULL)
+#define SO_ALL (1 << SL_ALL)
#define SO_PARTIAL (1 << SL_PARTIAL)
#define SO_CPU (1 << SL_CPU)
#define SO_OBJECTS (1 << SL_OBJECTS)
+#define SO_TOTAL (1 << SL_TOTAL)
static ssize_t show_slab_objects(struct kmem_cache *s,
char *buf, unsigned long flags)
{
unsigned long total = 0;
- int cpu;
int node;
int x;
unsigned long *nodes;
@@ -3622,56 +3686,60 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
return -ENOMEM;
per_cpu = nodes + nr_node_ids;
- for_each_possible_cpu(cpu) {
- struct page *page;
- struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ if (flags & SO_CPU) {
+ int cpu;
- if (!c)
- continue;
+ for_each_possible_cpu(cpu) {
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
- page = c->page;
- node = c->node;
- if (node < 0)
- continue;
- if (page) {
- if (flags & SO_CPU) {
- if (flags & SO_OBJECTS)
- x = page->inuse;
+ if (!c || c->node < 0)
+ continue;
+
+ if (c->page) {
+ if (flags & SO_TOTAL)
+ x = c->page->objects;
+ else if (flags & SO_OBJECTS)
+ x = c->page->inuse;
else
x = 1;
+
total += x;
- nodes[node] += x;
+ nodes[c->node] += x;
}
- per_cpu[node]++;
+ per_cpu[c->node]++;
}
}
- for_each_node_state(node, N_NORMAL_MEMORY) {
- struct kmem_cache_node *n = get_node(s, node);
+ if (flags & SO_ALL) {
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n = get_node(s, node);
+
+ if (flags & SO_TOTAL)
+ x = atomic_long_read(&n->total_objects);
+ else if (flags & SO_OBJECTS)
+ x = atomic_long_read(&n->total_objects) -
+ count_partial(n, count_free);
- if (flags & SO_PARTIAL) {
- if (flags & SO_OBJECTS)
- x = count_partial(n);
else
- x = n->nr_partial;
+ x = atomic_long_read(&n->nr_slabs);
total += x;
nodes[node] += x;
}
- if (flags & SO_FULL) {
- int full_slabs = atomic_long_read(&n->nr_slabs)
- - per_cpu[node]
- - n->nr_partial;
+ } else if (flags & SO_PARTIAL) {
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n = get_node(s, node);
- if (flags & SO_OBJECTS)
- x = full_slabs * s->objects;
+ if (flags & SO_TOTAL)
+ x = count_partial(n, count_total);
+ else if (flags & SO_OBJECTS)
+ x = count_partial(n, count_inuse);
else
- x = full_slabs;
+ x = n->nr_partial;
total += x;
nodes[node] += x;
}
}
-
x = sprintf(buf, "%lu", total);
#ifdef CONFIG_NUMA
for_each_node_state(node, N_NORMAL_MEMORY)
@@ -3686,14 +3754,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
static int any_slab_objects(struct kmem_cache *s)
{
int node;
- int cpu;
-
- for_each_possible_cpu(cpu) {
- struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
-
- if (c && c->page)
- return 1;
- }
for_each_online_node(node) {
struct kmem_cache_node *n = get_node(s, node);
@@ -3701,7 +3761,7 @@ static int any_slab_objects(struct kmem_cache *s)
if (!n)
continue;
- if (n->nr_partial || atomic_long_read(&n->nr_slabs))
+ if (atomic_read(&n->total_objects))
return 1;
}
return 0;
@@ -3743,15 +3803,27 @@ SLAB_ATTR_RO(object_size);
static ssize_t objs_per_slab_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", s->objects);
+ return sprintf(buf, "%d\n", oo_objects(s->oo));
}
SLAB_ATTR_RO(objs_per_slab);
+static ssize_t order_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ int order = simple_strtoul(buf, NULL, 10);
+
+ if (order > slub_max_order || order < slub_min_order)
+ return -EINVAL;
+
+ calculate_sizes(s, order);
+ return length;
+}
+
static ssize_t order_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", s->order);
+ return sprintf(buf, "%d\n", oo_order(s->oo));
}
-SLAB_ATTR_RO(order);
+SLAB_ATTR(order);
static ssize_t ctor_show(struct kmem_cache *s, char *buf)
{
@@ -3772,7 +3844,7 @@ SLAB_ATTR_RO(aliases);
static ssize_t slabs_show(struct kmem_cache *s, char *buf)
{
- return show_slab_objects(s, buf, SO_FULL|SO_PARTIAL|SO_CPU);
+ return show_slab_objects(s, buf, SO_ALL);
}
SLAB_ATTR_RO(slabs);
@@ -3790,10 +3862,22 @@ SLAB_ATTR_RO(cpu_slabs);
static ssize_t objects_show(struct kmem_cache *s, char *buf)
{
- return show_slab_objects(s, buf, SO_FULL|SO_PARTIAL|SO_CPU|SO_OBJECTS);
+ return show_slab_objects(s, buf, SO_ALL|SO_OBJECTS);
}
SLAB_ATTR_RO(objects);
+static ssize_t objects_partial_show(struct kmem_cache *s, char *buf)
+{
+ return show_slab_objects(s, buf, SO_PARTIAL|SO_OBJECTS);
+}
+SLAB_ATTR_RO(objects_partial);
+
+static ssize_t total_objects_show(struct kmem_cache *s, char *buf)
+{
+ return show_slab_objects(s, buf, SO_ALL|SO_TOTAL);
+}
+SLAB_ATTR_RO(total_objects);
+
static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf)
{
return sprintf(buf, "%d\n", !!(s->flags & SLAB_DEBUG_FREE));
@@ -3873,7 +3957,7 @@ static ssize_t red_zone_store(struct kmem_cache *s,
s->flags &= ~SLAB_RED_ZONE;
if (buf[0] == '1')
s->flags |= SLAB_RED_ZONE;
- calculate_sizes(s);
+ calculate_sizes(s, -1);
return length;
}
SLAB_ATTR(red_zone);
@@ -3892,7 +3976,7 @@ static ssize_t poison_store(struct kmem_cache *s,
s->flags &= ~SLAB_POISON;
if (buf[0] == '1')
s->flags |= SLAB_POISON;
- calculate_sizes(s);
+ calculate_sizes(s, -1);
return length;
}
SLAB_ATTR(poison);
@@ -3911,7 +3995,7 @@ static ssize_t store_user_store(struct kmem_cache *s,
s->flags &= ~SLAB_STORE_USER;
if (buf[0] == '1')
s->flags |= SLAB_STORE_USER;
- calculate_sizes(s);
+ calculate_sizes(s, -1);
return length;
}
SLAB_ATTR(store_user);
@@ -4042,7 +4126,7 @@ STAT_ATTR(DEACTIVATE_EMPTY, deactivate_empty);
STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate_to_head);
STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail);
STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees);
-
+STAT_ATTR(ORDER_FALLBACK, order_fallback);
#endif
static struct attribute *slab_attrs[] = {
@@ -4051,6 +4135,8 @@ static struct attribute *slab_attrs[] = {
&objs_per_slab_attr.attr,
&order_attr.attr,
&objects_attr.attr,
+ &objects_partial_attr.attr,
+ &total_objects_attr.attr,
&slabs_attr.attr,
&partial_attr.attr,
&cpu_slabs_attr.attr,
@@ -4093,6 +4179,7 @@ static struct attribute *slab_attrs[] = {
&deactivate_to_head_attr.attr,
&deactivate_to_tail_attr.attr,
&deactivate_remote_frees_attr.attr,
+ &order_fallback_attr.attr,
#endif
NULL
};
@@ -4379,7 +4466,8 @@ static int s_show(struct seq_file *m, void *p)
unsigned long nr_partials = 0;
unsigned long nr_slabs = 0;
unsigned long nr_inuse = 0;
- unsigned long nr_objs;
+ unsigned long nr_objs = 0;
+ unsigned long nr_free = 0;
struct kmem_cache *s;
int node;
@@ -4393,14 +4481,15 @@ static int s_show(struct seq_file *m, void *p)
nr_partials += n->nr_partial;
nr_slabs += atomic_long_read(&n->nr_slabs);
- nr_inuse += count_partial(n);
+ nr_objs += atomic_long_read(&n->total_objects);
+ nr_free += count_partial(n, count_free);
}
- nr_objs = nr_slabs * s->objects;
- nr_inuse += (nr_slabs - nr_partials) * s->objects;
+ nr_inuse = nr_objs - nr_free;
seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", s->name, nr_inuse,
- nr_objs, s->size, s->objects, (1 << s->order));
+ nr_objs, s->size, oo_objects(s->oo),
+ (1 << oo_order(s->oo)));
seq_printf(m, " : tunables %4u %4u %4u", 0, 0, 0);
seq_printf(m, " : slabdata %6lu %6lu %6lu", nr_slabs, nr_slabs,
0UL);
diff --git a/mm/sparse.c b/mm/sparse.c
index 98d6b39c3472..dff71f173ae9 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
+#include "internal.h"
#include <asm/dma.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
@@ -208,12 +209,12 @@ static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long p
}
/*
- * We need this if we ever free the mem_maps. While not implemented yet,
- * this function is included for parity with its sibling.
+ * Decode mem_map from the coded memmap
*/
-static __attribute((unused))
struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum)
{
+ /* mask off the extra low bits of information */
+ coded_mem_map &= SECTION_MAP_MASK;
return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
}
@@ -232,7 +233,7 @@ static int __meminit sparse_init_one_section(struct mem_section *ms,
return 1;
}
-static unsigned long usemap_size(void)
+unsigned long usemap_size(void)
{
unsigned long size_bytes;
size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8;
@@ -249,11 +250,22 @@ static unsigned long *__kmalloc_section_usemap(void)
static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
{
- unsigned long *usemap;
+ unsigned long *usemap, section_nr;
struct mem_section *ms = __nr_to_section(pnum);
int nid = sparse_early_nid(ms);
+ struct pglist_data *pgdat = NODE_DATA(nid);
- usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size());
+ /*
+ * Usemap's page can't be freed until freeing other sections
+ * which use it. And, Pgdat has same feature.
+ * If section A has pgdat and section B has usemap for other
+ * sections (includes section A), both sections can't be removed,
+ * because there is the dependency each other.
+ * To solve above issue, this collects all usemap on the same section
+ * which has pgdat.
+ */
+ section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
+ usemap = alloc_bootmem_section(usemap_size(), section_nr);
if (usemap)
return usemap;
@@ -273,8 +285,8 @@ struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid)
if (map)
return map;
- map = alloc_bootmem_node(NODE_DATA(nid),
- sizeof(struct page) * PAGES_PER_SECTION);
+ map = alloc_bootmem_pages_node(NODE_DATA(nid),
+ PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION));
return map;
}
#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
@@ -295,6 +307,9 @@ struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
return NULL;
}
+void __attribute__((weak)) __meminit vmemmap_populate_print_last(void)
+{
+}
/*
* Allocate the accumulated non-linear sections, allocate a mem_map
* for each and record the physical to section mapping.
@@ -304,22 +319,50 @@ void __init sparse_init(void)
unsigned long pnum;
struct page *map;
unsigned long *usemap;
+ unsigned long **usemap_map;
+ int size;
+
+ /*
+ * map is using big page (aka 2M in x86 64 bit)
+ * usemap is less one page (aka 24 bytes)
+ * so alloc 2M (with 2M align) and 24 bytes in turn will
+ * make next 2M slip to one more 2M later.
+ * then in big system, the memory will have a lot of holes...
+ * here try to allocate 2M pages continously.
+ *
+ * powerpc need to call sparse_init_one_section right after each
+ * sparse_early_mem_map_alloc, so allocate usemap_map at first.
+ */
+ size = sizeof(unsigned long *) * NR_MEM_SECTIONS;
+ usemap_map = alloc_bootmem(size);
+ if (!usemap_map)
+ panic("can not allocate usemap_map\n");
for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
if (!present_section_nr(pnum))
continue;
+ usemap_map[pnum] = sparse_early_usemap_alloc(pnum);
+ }
- map = sparse_early_mem_map_alloc(pnum);
- if (!map)
+ for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
+ if (!present_section_nr(pnum))
continue;
- usemap = sparse_early_usemap_alloc(pnum);
+ usemap = usemap_map[pnum];
if (!usemap)
continue;
+ map = sparse_early_mem_map_alloc(pnum);
+ if (!map)
+ continue;
+
sparse_init_one_section(__nr_to_section(pnum), pnum, map,
usemap);
}
+
+ vmemmap_populate_print_last();
+
+ free_bootmem(__pa(usemap_map), size);
}
#ifdef CONFIG_MEMORY_HOTPLUG
@@ -334,6 +377,9 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
{
return; /* XXX: Not implemented yet */
}
+static void free_map_bootmem(struct page *page, unsigned long nr_pages)
+{
+}
#else
static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
{
@@ -371,8 +417,69 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
free_pages((unsigned long)memmap,
get_order(sizeof(struct page) * nr_pages));
}
+
+static void free_map_bootmem(struct page *page, unsigned long nr_pages)
+{
+ unsigned long maps_section_nr, removing_section_nr, i;
+ int magic;
+
+ for (i = 0; i < nr_pages; i++, page++) {
+ magic = atomic_read(&page->_mapcount);
+
+ BUG_ON(magic == NODE_INFO);
+
+ maps_section_nr = pfn_to_section_nr(page_to_pfn(page));
+ removing_section_nr = page->private;
+
+ /*
+ * When this function is called, the removing section is
+ * logical offlined state. This means all pages are isolated
+ * from page allocator. If removing section's memmap is placed
+ * on the same section, it must not be freed.
+ * If it is freed, page allocator may allocate it which will
+ * be removed physically soon.
+ */
+ if (maps_section_nr != removing_section_nr)
+ put_page_bootmem(page);
+ }
+}
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
+static void free_section_usemap(struct page *memmap, unsigned long *usemap)
+{
+ struct page *usemap_page;
+ unsigned long nr_pages;
+
+ if (!usemap)
+ return;
+
+ usemap_page = virt_to_page(usemap);
+ /*
+ * Check to see if allocation came from hot-plug-add
+ */
+ if (PageSlab(usemap_page)) {
+ kfree(usemap);
+ if (memmap)
+ __kfree_section_memmap(memmap, PAGES_PER_SECTION);
+ return;
+ }
+
+ /*
+ * The usemap came from bootmem. This is packed with other usemaps
+ * on the section which has pgdat at boot time. Just keep it as is now.
+ */
+
+ if (memmap) {
+ struct page *memmap_page;
+ memmap_page = virt_to_page(memmap);
+
+ nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
+ >> PAGE_SHIFT;
+
+ free_map_bootmem(memmap_page, nr_pages);
+ }
+}
+
/*
* returns the number of sections whose mem_maps were properly
* set. If this is <=0, then that means that the passed-in
@@ -425,4 +532,20 @@ out:
}
return ret;
}
+
+void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
+{
+ struct page *memmap = NULL;
+ unsigned long *usemap = NULL;
+
+ if (ms->section_mem_map) {
+ usemap = ms->pageblock_flags;
+ memmap = sparse_decode_mem_map(ms->section_mem_map,
+ __section_nr(ms));
+ ms->section_mem_map = 0;
+ ms->pageblock_flags = NULL;
+ }
+
+ free_section_usemap(memmap, usemap);
+}
#endif
diff --git a/mm/swap.c b/mm/swap.c
index aa1139ccf3a7..91e194445a5e 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -132,34 +132,21 @@ static void pagevec_move_tail(struct pagevec *pvec)
* Writeback is about to end against a page which has been marked for immediate
* reclaim. If it still appears to be reclaimable, move it to the tail of the
* inactive list.
- *
- * Returns zero if it cleared PG_writeback.
*/
-int rotate_reclaimable_page(struct page *page)
+void rotate_reclaimable_page(struct page *page)
{
- struct pagevec *pvec;
- unsigned long flags;
-
- if (PageLocked(page))
- return 1;
- if (PageDirty(page))
- return 1;
- if (PageActive(page))
- return 1;
- if (!PageLRU(page))
- return 1;
-
- page_cache_get(page);
- local_irq_save(flags);
- pvec = &__get_cpu_var(lru_rotate_pvecs);
- if (!pagevec_add(pvec, page))
- pagevec_move_tail(pvec);
- local_irq_restore(flags);
-
- if (!test_clear_page_writeback(page))
- BUG();
+ if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) &&
+ PageLRU(page)) {
+ struct pagevec *pvec;
+ unsigned long flags;
- return 0;
+ page_cache_get(page);
+ local_irq_save(flags);
+ pvec = &__get_cpu_var(lru_rotate_pvecs);
+ if (!pagevec_add(pvec, page))
+ pagevec_move_tail(pvec);
+ local_irq_restore(flags);
+ }
}
/*
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 2da149cfc9ac..67051be7083a 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1582,6 +1582,14 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
error = -EINVAL;
goto bad_swap;
case 2:
+ /* swap partition endianess hack... */
+ if (swab32(swap_header->info.version) == 1) {
+ swab32s(&swap_header->info.version);
+ swab32s(&swap_header->info.last_page);
+ swab32s(&swap_header->info.nr_badpages);
+ for (i = 0; i < swap_header->info.nr_badpages; i++)
+ swab32s(&swap_header->info.badpages[i]);
+ }
/* Check the swap header's sub-version and the size of
the swap file and bad block lists */
if (swap_header->info.version != 1) {
diff --git a/mm/truncate.c b/mm/truncate.c
index 7d20ce41ecf5..b8961cb63414 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -391,6 +391,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
pgoff_t next;
int i;
int ret = 0;
+ int ret2 = 0;
int did_range_unmap = 0;
int wrapped = 0;
@@ -438,9 +439,13 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
}
}
BUG_ON(page_mapped(page));
- ret = do_launder_page(mapping, page);
- if (ret == 0 && !invalidate_complete_page2(mapping, page))
- ret = -EIO;
+ ret2 = do_launder_page(mapping, page);
+ if (ret2 == 0) {
+ if (!invalidate_complete_page2(mapping, page))
+ ret2 = -EIO;
+ }
+ if (ret2 < 0)
+ ret = ret2;
unlock_page(page);
}
pagevec_release(&pvec);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ecf91f8034bf..e33e0ae69ad1 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -14,8 +14,9 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
-
+#include <linux/seq_file.h>
#include <linux/vmalloc.h>
+#include <linux/kallsyms.h>
#include <asm/uaccess.h>
#include <asm/tlbflush.h>
@@ -25,7 +26,7 @@ DEFINE_RWLOCK(vmlist_lock);
struct vm_struct *vmlist;
static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
- int node);
+ int node, void *caller);
static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
{
@@ -204,9 +205,9 @@ unsigned long vmalloc_to_pfn(const void *vmalloc_addr)
}
EXPORT_SYMBOL(vmalloc_to_pfn);
-static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
- unsigned long start, unsigned long end,
- int node, gfp_t gfp_mask)
+static struct vm_struct *
+__get_vm_area_node(unsigned long size, unsigned long flags, unsigned long start,
+ unsigned long end, int node, gfp_t gfp_mask, void *caller)
{
struct vm_struct **p, *tmp, *area;
unsigned long align = 1;
@@ -269,6 +270,7 @@ found:
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
+ area->caller = caller;
write_unlock(&vmlist_lock);
return area;
@@ -284,7 +286,8 @@ out:
struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end)
{
- return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL);
+ return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL_GPL(__get_vm_area);
@@ -299,14 +302,22 @@ EXPORT_SYMBOL_GPL(__get_vm_area);
*/
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
{
- return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
+ return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END,
+ -1, GFP_KERNEL, __builtin_return_address(0));
+}
+
+struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
+ void *caller)
+{
+ return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END,
+ -1, GFP_KERNEL, caller);
}
struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags,
int node, gfp_t gfp_mask)
{
return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node,
- gfp_mask);
+ gfp_mask, __builtin_return_address(0));
}
/* Caller must hold vmlist_lock */
@@ -455,9 +466,11 @@ void *vmap(struct page **pages, unsigned int count,
if (count > num_physpages)
return NULL;
- area = get_vm_area((count << PAGE_SHIFT), flags);
+ area = get_vm_area_caller((count << PAGE_SHIFT), flags,
+ __builtin_return_address(0));
if (!area)
return NULL;
+
if (map_vm_area(area, prot, &pages)) {
vunmap(area->addr);
return NULL;
@@ -468,7 +481,7 @@ void *vmap(struct page **pages, unsigned int count,
EXPORT_SYMBOL(vmap);
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
- pgprot_t prot, int node)
+ pgprot_t prot, int node, void *caller)
{
struct page **pages;
unsigned int nr_pages, array_size, i;
@@ -480,7 +493,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
/* Please note that the recursion is strictly bounded. */
if (array_size > PAGE_SIZE) {
pages = __vmalloc_node(array_size, gfp_mask | __GFP_ZERO,
- PAGE_KERNEL, node);
+ PAGE_KERNEL, node, caller);
area->flags |= VM_VPAGES;
} else {
pages = kmalloc_node(array_size,
@@ -488,6 +501,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
node);
}
area->pages = pages;
+ area->caller = caller;
if (!area->pages) {
remove_vm_area(area->addr);
kfree(area);
@@ -521,7 +535,8 @@ fail:
void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
{
- return __vmalloc_area_node(area, gfp_mask, prot, -1);
+ return __vmalloc_area_node(area, gfp_mask, prot, -1,
+ __builtin_return_address(0));
}
/**
@@ -536,7 +551,7 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
* kernel virtual space, using a pagetable protection of @prot.
*/
static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
- int node)
+ int node, void *caller)
{
struct vm_struct *area;
@@ -544,16 +559,19 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
if (!size || (size >> PAGE_SHIFT) > num_physpages)
return NULL;
- area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask);
+ area = __get_vm_area_node(size, VM_ALLOC, VMALLOC_START, VMALLOC_END,
+ node, gfp_mask, caller);
+
if (!area)
return NULL;
- return __vmalloc_area_node(area, gfp_mask, prot, node);
+ return __vmalloc_area_node(area, gfp_mask, prot, node, caller);
}
void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
{
- return __vmalloc_node(size, gfp_mask, prot, -1);
+ return __vmalloc_node(size, gfp_mask, prot, -1,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(__vmalloc);
@@ -568,7 +586,8 @@ EXPORT_SYMBOL(__vmalloc);
*/
void *vmalloc(unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+ return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
+ -1, __builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc);
@@ -608,7 +627,8 @@ EXPORT_SYMBOL(vmalloc_user);
*/
void *vmalloc_node(unsigned long size, int node)
{
- return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node);
+ return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
+ node, __builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc_node);
@@ -843,7 +863,8 @@ struct vm_struct *alloc_vm_area(size_t size)
{
struct vm_struct *area;
- area = get_vm_area(size, VM_IOREMAP);
+ area = get_vm_area_caller(size, VM_IOREMAP,
+ __builtin_return_address(0));
if (area == NULL)
return NULL;
@@ -873,3 +894,85 @@ void free_vm_area(struct vm_struct *area)
kfree(area);
}
EXPORT_SYMBOL_GPL(free_vm_area);
+
+
+#ifdef CONFIG_PROC_FS
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+ loff_t n = *pos;
+ struct vm_struct *v;
+
+ read_lock(&vmlist_lock);
+ v = vmlist;
+ while (n > 0 && v) {
+ n--;
+ v = v->next;
+ }
+ if (!n)
+ return v;
+
+ return NULL;
+
+}
+
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+{
+ struct vm_struct *v = p;
+
+ ++*pos;
+ return v->next;
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+ read_unlock(&vmlist_lock);
+}
+
+static int s_show(struct seq_file *m, void *p)
+{
+ struct vm_struct *v = p;
+
+ seq_printf(m, "0x%p-0x%p %7ld",
+ v->addr, v->addr + v->size, v->size);
+
+ if (v->caller) {
+ char buff[2 * KSYM_NAME_LEN];
+
+ seq_putc(m, ' ');
+ sprint_symbol(buff, (unsigned long)v->caller);
+ seq_puts(m, buff);
+ }
+
+ if (v->nr_pages)
+ seq_printf(m, " pages=%d", v->nr_pages);
+
+ if (v->phys_addr)
+ seq_printf(m, " phys=%lx", v->phys_addr);
+
+ if (v->flags & VM_IOREMAP)
+ seq_printf(m, " ioremap");
+
+ if (v->flags & VM_ALLOC)
+ seq_printf(m, " vmalloc");
+
+ if (v->flags & VM_MAP)
+ seq_printf(m, " vmap");
+
+ if (v->flags & VM_USERMAP)
+ seq_printf(m, " user");
+
+ if (v->flags & VM_VPAGES)
+ seq_printf(m, " vpages");
+
+ seq_putc(m, '\n');
+ return 0;
+}
+
+const struct seq_operations vmalloc_op = {
+ .start = s_start,
+ .next = s_next,
+ .stop = s_stop,
+ .show = s_show,
+};
+#endif
+
diff --git a/mm/vmscan.c b/mm/vmscan.c
index f80a5b7c057f..eceac9f9032f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1246,17 +1246,16 @@ static unsigned long shrink_zone(int priority, struct zone *zone,
* If a zone is deemed to be full of pinned pages then just give it a light
* scan then give up on it.
*/
-static unsigned long shrink_zones(int priority, struct zone **zones,
+static unsigned long shrink_zones(int priority, struct zonelist *zonelist,
struct scan_control *sc)
{
+ enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask);
unsigned long nr_reclaimed = 0;
- int i;
-
+ struct zoneref *z;
+ struct zone *zone;
sc->all_unreclaimable = 1;
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *zone = zones[i];
-
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
if (!populated_zone(zone))
continue;
/*
@@ -1301,8 +1300,8 @@ static unsigned long shrink_zones(int priority, struct zone **zones,
* holds filesystem locks which prevent writeout this might not work, and the
* allocation attempt will fail.
*/
-static unsigned long do_try_to_free_pages(struct zone **zones, gfp_t gfp_mask,
- struct scan_control *sc)
+static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
+ struct scan_control *sc)
{
int priority;
int ret = 0;
@@ -1310,7 +1309,9 @@ static unsigned long do_try_to_free_pages(struct zone **zones, gfp_t gfp_mask,
unsigned long nr_reclaimed = 0;
struct reclaim_state *reclaim_state = current->reclaim_state;
unsigned long lru_pages = 0;
- int i;
+ struct zoneref *z;
+ struct zone *zone;
+ enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask);
if (scan_global_lru(sc))
count_vm_event(ALLOCSTALL);
@@ -1318,8 +1319,7 @@ static unsigned long do_try_to_free_pages(struct zone **zones, gfp_t gfp_mask,
* mem_cgroup will not do shrink_slab.
*/
if (scan_global_lru(sc)) {
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *zone = zones[i];
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
@@ -1333,13 +1333,13 @@ static unsigned long do_try_to_free_pages(struct zone **zones, gfp_t gfp_mask,
sc->nr_scanned = 0;
if (!priority)
disable_swap_token();
- nr_reclaimed += shrink_zones(priority, zones, sc);
+ nr_reclaimed += shrink_zones(priority, zonelist, sc);
/*
* Don't shrink slabs when reclaiming memory from
* over limit cgroups
*/
if (scan_global_lru(sc)) {
- shrink_slab(sc->nr_scanned, gfp_mask, lru_pages);
+ shrink_slab(sc->nr_scanned, sc->gfp_mask, lru_pages);
if (reclaim_state) {
nr_reclaimed += reclaim_state->reclaimed_slab;
reclaim_state->reclaimed_slab = 0;
@@ -1383,8 +1383,7 @@ out:
priority = 0;
if (scan_global_lru(sc)) {
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *zone = zones[i];
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
@@ -1397,7 +1396,8 @@ out:
return ret;
}
-unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
+unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
+ gfp_t gfp_mask)
{
struct scan_control sc = {
.gfp_mask = gfp_mask,
@@ -1410,7 +1410,7 @@ unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
.isolate_pages = isolate_pages_global,
};
- return do_try_to_free_pages(zones, gfp_mask, &sc);
+ return do_try_to_free_pages(zonelist, &sc);
}
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
@@ -1419,7 +1419,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
gfp_t gfp_mask)
{
struct scan_control sc = {
- .gfp_mask = gfp_mask,
.may_writepage = !laptop_mode,
.may_swap = 1,
.swap_cluster_max = SWAP_CLUSTER_MAX,
@@ -1428,13 +1427,12 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
.mem_cgroup = mem_cont,
.isolate_pages = mem_cgroup_isolate_pages,
};
- struct zone **zones;
- int target_zone = gfp_zone(GFP_HIGHUSER_MOVABLE);
+ struct zonelist *zonelist;
- zones = NODE_DATA(numa_node_id())->node_zonelists[target_zone].zones;
- if (do_try_to_free_pages(zones, sc.gfp_mask, &sc))
- return 1;
- return 0;
+ sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
+ (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
+ zonelist = NODE_DATA(numa_node_id())->node_zonelists;
+ return do_try_to_free_pages(zonelist, &sc);
}
#endif
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 7c7286e9506d..ec6035eda933 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -322,6 +322,7 @@ void refresh_cpu_vm_stats(int cpu)
p->expire = 3;
#endif
}
+ cond_resched();
#ifdef CONFIG_NUMA
/*
* Deal with draining the remote pageset of this
@@ -364,13 +365,13 @@ void refresh_cpu_vm_stats(int cpu)
*
* Must be called with interrupts disabled.
*/
-void zone_statistics(struct zonelist *zonelist, struct zone *z)
+void zone_statistics(struct zone *preferred_zone, struct zone *z)
{
- if (z->zone_pgdat == zonelist->zones[0]->zone_pgdat) {
+ if (z->zone_pgdat == preferred_zone->zone_pgdat) {
__inc_zone_state(z, NUMA_HIT);
} else {
__inc_zone_state(z, NUMA_MISS);
- __inc_zone_state(zonelist->zones[0], NUMA_FOREIGN);
+ __inc_zone_state(preferred_zone, NUMA_FOREIGN);
}
if (z->node == numa_node_id())
__inc_zone_state(z, NUMA_LOCAL);
@@ -645,6 +646,10 @@ static const char * const vmstat_text[] = {
"allocstall",
"pgrotated",
+#ifdef CONFIG_HUGETLB_PAGE
+ "htlb_buddy_alloc_success",
+ "htlb_buddy_alloc_fail",
+#endif
#endif
};
diff --git a/net/can/raw.c b/net/can/raw.c
index ead50c7c0d40..69877b8e7e9c 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -435,15 +435,13 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (!filter)
return -ENOMEM;
- err = copy_from_user(filter, optval, optlen);
- if (err) {
+ if (copy_from_user(filter, optval, optlen)) {
kfree(filter);
- return err;
+ return -EFAULT;
}
} else if (count == 1) {
- err = copy_from_user(&sfilter, optval, optlen);
- if (err)
- return err;
+ if (copy_from_user(&sfilter, optval, optlen))
+ return -EFAULT;
}
lock_sock(sk);
@@ -493,9 +491,8 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(err_mask))
return -EINVAL;
- err = copy_from_user(&err_mask, optval, optlen);
- if (err)
- return err;
+ if (copy_from_user(&err_mask, optval, optlen))
+ return -EFAULT;
err_mask &= CAN_ERR_MASK;
@@ -531,7 +528,8 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(ro->loopback))
return -EINVAL;
- err = copy_from_user(&ro->loopback, optval, optlen);
+ if (copy_from_user(&ro->loopback, optval, optlen))
+ return -EFAULT;
break;
@@ -539,7 +537,8 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (optlen != sizeof(ro->recv_own_msgs))
return -EINVAL;
- err = copy_from_user(&ro->recv_own_msgs, optval, optlen);
+ if (copy_from_user(&ro->recv_own_msgs, optval, optlen))
+ return -EFAULT;
break;
@@ -573,7 +572,8 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
int fsize = ro->count * sizeof(struct can_filter);
if (len > fsize)
len = fsize;
- err = copy_to_user(optval, ro->filter, len);
+ if (copy_to_user(optval, ro->filter, len))
+ err = -EFAULT;
} else
len = 0;
release_sock(sk);
diff --git a/net/compat.c b/net/compat.c
index 80013fb69a61..01bf95d0832e 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -24,6 +24,8 @@
#include <net/scm.h>
#include <net/sock.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
#include <asm/uaccess.h>
#include <net/compat.h>
@@ -521,6 +523,121 @@ asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
}
return err;
}
+
+struct compat_group_req {
+ __u32 gr_interface;
+ struct __kernel_sockaddr_storage gr_group
+ __attribute__ ((aligned(4)));
+} __attribute__ ((packed));
+
+struct compat_group_source_req {
+ __u32 gsr_interface;
+ struct __kernel_sockaddr_storage gsr_group
+ __attribute__ ((aligned(4)));
+ struct __kernel_sockaddr_storage gsr_source
+ __attribute__ ((aligned(4)));
+} __attribute__ ((packed));
+
+struct compat_group_filter {
+ __u32 gf_interface;
+ struct __kernel_sockaddr_storage gf_group
+ __attribute__ ((aligned(4)));
+ __u32 gf_fmode;
+ __u32 gf_numsrc;
+ struct __kernel_sockaddr_storage gf_slist[1]
+ __attribute__ ((aligned(4)));
+} __attribute__ ((packed));
+
+
+int compat_mc_setsockopt(struct sock *sock, int level, int optname,
+ char __user *optval, int optlen,
+ int (*setsockopt)(struct sock *,int,int,char __user *,int))
+{
+ char __user *koptval = optval;
+ int koptlen = optlen;
+
+ switch (optname) {
+ case MCAST_JOIN_GROUP:
+ case MCAST_LEAVE_GROUP:
+ {
+ struct compat_group_req __user *gr32 = (void *)optval;
+ struct group_req __user *kgr =
+ compat_alloc_user_space(sizeof(struct group_req));
+ u32 interface;
+
+ if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) ||
+ !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) ||
+ __get_user(interface, &gr32->gr_interface) ||
+ __put_user(interface, &kgr->gr_interface) ||
+ copy_in_user(&kgr->gr_group, &gr32->gr_group,
+ sizeof(kgr->gr_group)))
+ return -EFAULT;
+ koptval = (char __user *)kgr;
+ koptlen = sizeof(struct group_req);
+ break;
+ }
+ case MCAST_JOIN_SOURCE_GROUP:
+ case MCAST_LEAVE_SOURCE_GROUP:
+ case MCAST_BLOCK_SOURCE:
+ case MCAST_UNBLOCK_SOURCE:
+ {
+ struct compat_group_source_req __user *gsr32 = (void *)optval;
+ struct group_source_req *kgsr = compat_alloc_user_space(
+ sizeof(struct group_source_req));
+ u32 interface;
+
+ if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) ||
+ !access_ok(VERIFY_WRITE, kgsr,
+ sizeof(struct group_source_req)) ||
+ __get_user(interface, &gsr32->gsr_interface) ||
+ __put_user(interface, &kgsr->gsr_interface) ||
+ copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group,
+ sizeof(kgsr->gsr_group)) ||
+ copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source,
+ sizeof(kgsr->gsr_source)))
+ return -EFAULT;
+ koptval = (char __user *)kgsr;
+ koptlen = sizeof(struct group_source_req);
+ break;
+ }
+ case MCAST_MSFILTER:
+ {
+ struct compat_group_filter __user *gf32 = (void *)optval;
+ struct group_filter *kgf;
+ u32 interface, fmode, numsrc;
+
+ if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
+ __get_user(interface, &gf32->gf_interface) ||
+ __get_user(fmode, &gf32->gf_fmode) ||
+ __get_user(numsrc, &gf32->gf_numsrc))
+ return -EFAULT;
+ koptlen = optlen + sizeof(struct group_filter) -
+ sizeof(struct compat_group_filter);
+ if (koptlen < GROUP_FILTER_SIZE(numsrc))
+ return -EINVAL;
+ kgf = compat_alloc_user_space(koptlen);
+ if (!access_ok(VERIFY_WRITE, kgf, koptlen) ||
+ __put_user(interface, &kgf->gf_interface) ||
+ __put_user(fmode, &kgf->gf_fmode) ||
+ __put_user(numsrc, &kgf->gf_numsrc) ||
+ copy_in_user(&kgf->gf_group, &gf32->gf_group,
+ sizeof(kgf->gf_group)) ||
+ (numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist,
+ numsrc * sizeof(kgf->gf_slist[0]))))
+ return -EFAULT;
+ koptval = (char __user *)kgf;
+ break;
+ }
+
+ default:
+ break;
+ }
+ return setsockopt(sock, level, optname, koptval, koptlen);
+}
+
+EXPORT_SYMBOL(compat_mc_setsockopt);
+
+
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index a29b43d0b450..0133b5ebd545 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -323,6 +323,11 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
bytes_remaining -= eeprom.len;
}
+ eeprom.len = userbuf - (useraddr + sizeof(eeprom));
+ eeprom.offset -= eeprom.len;
+ if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
+ ret = -EFAULT;
+
kfree(data);
return ret;
}
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 6e1df62bd7c9..0bcdc9250279 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -140,7 +140,7 @@ static ssize_t dccpprobe_read(struct file *file, char __user *buf,
goto out_free;
cnt = kfifo_get(dccpw.fifo, tbuf, len);
- error = copy_to_user(buf, tbuf, cnt);
+ error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0;
out_free:
vfree(tbuf);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index d8adfd4972e2..4d8d95404f45 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -36,6 +36,7 @@
#include <linux/mroute.h>
#include <net/route.h>
#include <net/xfrm.h>
+#include <net/compat.h>
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/transp_v6.h>
#endif
@@ -923,6 +924,10 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
if (level != SOL_IP)
return -ENOPROTOOPT;
+ if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
+ return compat_mc_setsockopt(sk, level, optname, optval, optlen,
+ ip_setsockopt);
+
err = do_ip_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ac9b8482f702..0298f80681f2 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4925,8 +4925,7 @@ step5:
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
- if (tcp_defer_accept_check(sk))
- return -1;
+ tcp_defer_accept_check(sk);
return 0;
csum_error:
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 1c509592574a..5ff0ce6e9d39 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -190,19 +190,18 @@ static ssize_t tcpprobe_read(struct file *file, char __user *buf,
width = tcpprobe_sprint(tbuf, sizeof(tbuf));
- if (width < len)
+ if (cnt + width < len)
tcp_probe.tail = (tcp_probe.tail + 1) % bufsize;
spin_unlock_bh(&tcp_probe.lock);
/* if record greater than space available
return partial buffer (so far) */
- if (width >= len)
+ if (cnt + width >= len)
break;
- error = copy_to_user(buf + cnt, tbuf, width);
- if (error)
- break;
+ if (copy_to_user(buf + cnt, tbuf, width))
+ return -EFAULT;
cnt += width;
}
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index c8c6e33d1163..2de3c464fe75 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -358,7 +358,7 @@ static int pim6_rcv(struct sk_buff *skb)
if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
(pim->flags & PIM_NULL_REGISTER) ||
(ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
- (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))))
+ csum_fold(skb_checksum(skb, 0, skb->len, 0))))
goto drop;
/* check if the inner packet is destined to mcast group */
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 06de9d0e1f6b..db6fdc1498aa 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -52,6 +52,7 @@
#include <net/udp.h>
#include <net/udplite.h>
#include <net/xfrm.h>
+#include <net/compat.h>
#include <asm/uaccess.h>
@@ -779,6 +780,10 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (level != SOL_IPV6)
return -ENOPROTOOPT;
+ if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
+ return compat_mc_setsockopt(sk, level, optname, optval, optlen,
+ ipv6_setsockopt);
+
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 6193b124cbc7..396f0ea11090 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -971,6 +971,19 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case IPV6_CHECKSUM:
+ if (inet_sk(sk)->num == IPPROTO_ICMPV6 &&
+ level == IPPROTO_IPV6) {
+ /*
+ * RFC3542 tells that IPV6_CHECKSUM socket
+ * option in the IPPROTO_IPV6 level is not
+ * allowed on ICMPv6 sockets.
+ * If you want to set it, use IPPROTO_RAW
+ * level IPV6_CHECKSUM socket option
+ * (Linux extension).
+ */
+ return -EINVAL;
+ }
+
/* You may get strange result with a positive odd offset;
RFC2292bis agrees with me. */
if (val > 0 && (val&1))
@@ -1046,6 +1059,11 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case IPV6_CHECKSUM:
+ /*
+ * We allow getsockopt() for IPPROTO_IPV6-level
+ * IPV6_CHECKSUM socket option on ICMPv6 sockets
+ * since RFC3542 is silent about it.
+ */
if (rp->checksum == 0)
val = -1;
else
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 81a8e5297ad1..2403a31fe0f6 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2356,7 +2356,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
struct xfrm_selector sel;
struct km_event c;
struct sadb_x_sec_ctx *sec_ctx;
- struct xfrm_sec_ctx *pol_ctx;
+ struct xfrm_sec_ctx *pol_ctx = NULL;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -2396,8 +2396,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
kfree(uctx);
if (err)
return err;
- } else
- pol_ctx = NULL;
+ }
xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN,
pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 520a5180a4f6..a24b459dd45a 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -73,7 +73,9 @@ config MAC80211_MESH
config MAC80211_LEDS
bool "Enable LED triggers"
- depends on MAC80211 && LEDS_TRIGGERS
+ depends on MAC80211
+ select NEW_LEDS
+ select LEDS_TRIGGERS
---help---
This option enables a few LED triggers for different
packet receive/transmit events.
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 742003d3a841..9ee3affab346 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/jhash.h>
+#include <asm/unaligned.h>
#include "ieee80211_i.h"
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 02de8f1522a3..3df809222d1c 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -7,7 +7,6 @@
* published by the Free Software Foundation.
*/
-#include <asm/unaligned.h>
#include "mesh.h"
#define TEST_FRAME_LEN 8192
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 75d748eee0eb..e1770f7ba0b3 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -445,7 +445,7 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
/**
* xprt_wait_for_buffer_space - wait for transport output buffer to clear
* @task: task to be put to sleep
- *
+ * @action: function pointer to be executed after wait
*/
void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action)
{
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 6ad070d87702..ad487e8abcc2 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -70,10 +70,9 @@ static inline void msg_set_bits(struct tipc_msg *m, u32 w,
u32 pos, u32 mask, u32 val)
{
val = (val & mask) << pos;
- val = htonl(val);
- mask = htonl(mask << pos);
- m->hdr[w] &= ~mask;
- m->hdr[w] |= val;
+ mask = mask << pos;
+ m->hdr[w] &= ~htonl(mask);
+ m->hdr[w] |= htonl(val);
}
/*
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 05853159536a..230f9ca2ad6b 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1756,8 +1756,8 @@ static int getsockopt(struct socket *sock,
else if (len < sizeof(value)) {
res = -EINVAL;
}
- else if ((res = copy_to_user(ov, &value, sizeof(value)))) {
- /* couldn't return value */
+ else if (copy_to_user(ov, &value, sizeof(value))) {
+ res = -EFAULT;
}
else {
res = put_user(sizeof(value), ol);
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 8aa6440d689f..ac765dd9c7f5 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -129,8 +129,7 @@ static struct xfrm_algo_desc aead_list[] = {
static struct xfrm_algo_desc aalg_list[] = {
{
- .name = "hmac(digest_null)",
- .compat = "digest_null",
+ .name = "digest_null",
.uinfo = {
.auth = {
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 5dcc10b93c86..fac27ce770d5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2112,7 +2112,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
iph6 = ipv6_hdr(skb);
audit_log_format(audit_buf,
" src=" NIP6_FMT " dst=" NIP6_FMT
- " flowlbl=0x%x%x%x",
+ " flowlbl=0x%x%02x%02x",
NIP6(iph6->saddr),
NIP6(iph6->daddr),
iph6->flow_lbl[0] & 0x0f,
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 67fb4530a6ff..277cfe0b7100 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -27,12 +27,12 @@ ccflags-y :=
cppflags-y :=
ldflags-y :=
-# Read .config if it exist, otherwise ignore
+# Read auto.conf if it exists, otherwise ignore
-include include/config/auto.conf
include scripts/Kbuild.include
-# For backward compatibility check that these variables does not change
+# For backward compatibility check that these variables do not change
save-cflags := $(CFLAGS)
# The filename Kbuild has precedence over Makefile
@@ -55,7 +55,7 @@ hostprogs-y += $(host-progs)
endif
endif
-# Do not include host rules unles needed
+# Do not include host rules unless needed
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host
endif
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index 2c647107c9cc..6f89fbb56256 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -37,7 +37,7 @@ subdir-ymn := $(sort $(subdir-ym) $(subdir-n) $(subdir-))
subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
-# build a list of files to remove, usually releative to the current
+# build a list of files to remove, usually relative to the current
# directory
__clean-files := $(extra-y) $(always) \
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 6943a7a5bb98..1ac414fd5030 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -3,9 +3,9 @@
# Binaries are used during the compilation of the kernel, for example
# to preprocess a data file.
#
-# Both C and C++ is supported, but preferred language is C for such utilities.
+# Both C and C++ are supported, but preferred language is C for such utilities.
#
-# Samle syntax (see Documentation/kbuild/makefile.txt for reference)
+# Sample syntax (see Documentation/kbuild/makefiles.txt for reference)
# hostprogs-y := bin2hex
# Will compile bin2hex.c and create an executable named bin2hex
#
@@ -23,10 +23,10 @@
# hostprogs-y := conf
# conf-objs := conf.o libkconfig.so
# libkconfig-objs := expr.o type.o
-# Will create a shared library named libkconfig.so that consist of
-# expr.o and type.o (they are both compiled as C code and the object file
+# Will create a shared library named libkconfig.so that consists of
+# expr.o and type.o (they are both compiled as C code and the object files
# are made as position independent code).
-# conf.c is compiled as a c program, and conf.o is linked together with
+# conf.c is compiled as a C program, and conf.o is linked together with
# libkconfig.so as the executable conf.
# Note: Shared libraries consisting of C++ files are not supported
@@ -61,7 +61,7 @@ host-cobjs := $(filter-out %.so,$(host-cobjs))
host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
# output directory for programs/.o files
-# hostprogs-y := tools/build may have been specified. Retreive directory
+# hostprogs-y := tools/build may have been specified. Retrieve directory
host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
# directory of .o files from prog-objs notation
host-objdirs += $(foreach f,$(host-cmulti), \
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 2d20640854b7..a098a0454dc8 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -42,6 +42,13 @@ _modpost: __modpost
include include/config/auto.conf
include scripts/Kbuild.include
+
+ifneq ($(KBUILD_EXTMOD),)
+# Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS
+include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \
+ $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile)
+endif
+
include scripts/Makefile.lib
kernelsymfile := $(objtree)/Module.symvers
@@ -69,6 +76,7 @@ modpost = scripts/mod/modpost \
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
+ $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(EXTRA_SYMBOLS))) \
$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
$(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \
$(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 58a94947d655..64ec4b8a51b5 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1889,6 +1889,13 @@ sub process {
WARN("kfree(NULL) is safe this check is probabally not required\n" . $hereprev);
}
}
+# check for needless usb_free_urb() checks
+ if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+ my $expr = $1;
+ if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+ WARN("usb_free_urb(NULL) is safe this check is probabally not required\n" . $hereprev);
+ }
+ }
# warn about #ifdefs in C files
# if ($line =~ /^.#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 684fb9cdc055..5f3415f28736 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -135,7 +135,7 @@ parse() {
str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
;;
"slink")
- local target=`field 11 $(LC_ALL=C ls -l "${location}")`
+ local target=`readlink "${location}"`
str="${ftype} ${name} ${target} ${str}"
;;
*)
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 32e8c5a227c3..fa1a7d565903 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -36,10 +36,10 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
--output $(obj)/config.pot
$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
$(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
- $(Q)(for i in `ls arch/`; \
+ $(Q)(for i in `ls arch/*/Kconfig`; \
do \
echo " GEN $$i"; \
- $(obj)/kxgettext arch/$$i/Kconfig \
+ $(obj)/kxgettext $$i \
>> $(obj)/config.pot; \
done )
$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped
index bed0f4e2d2f7..6a61cee4a32c 100644
--- a/scripts/kconfig/lex.zconf.c_shipped
+++ b/scripts/kconfig/lex.zconf.c_shipped
@@ -5,25 +5,6 @@
/* A lexical scanner generated by flex */
-#define yy_create_buffer zconf_create_buffer
-#define yy_delete_buffer zconf_delete_buffer
-#define yy_flex_debug zconf_flex_debug
-#define yy_init_buffer zconf_init_buffer
-#define yy_flush_buffer zconf_flush_buffer
-#define yy_load_buffer_state zconf_load_buffer_state
-#define yy_switch_to_buffer zconf_switch_to_buffer
-#define yyin zconfin
-#define yyleng zconfleng
-#define yylex zconflex
-#define yylineno zconflineno
-#define yyout zconfout
-#define yyrestart zconfrestart
-#define yytext zconftext
-#define yywrap zconfwrap
-#define yyalloc zconfalloc
-#define yyrealloc zconfrealloc
-#define yyfree zconffree
-
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
@@ -354,7 +335,7 @@ void zconffree (void * );
/* Begin user sect3 */
-#define zconfwrap(n) 1
+#define zconfwrap() 1
#define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR;
@@ -1535,7 +1516,7 @@ static int yy_get_next_buffer (void)
/* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- (yy_n_chars), num_to_read );
+ (yy_n_chars), (size_t) num_to_read );
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
@@ -2007,7 +1988,7 @@ YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
/** Setup the input buffer state to scan a string. The next call to zconflex() will
* scan from a @e copy of @a str.
- * @param str a NUL-terminated string to scan
+ * @param yystr a NUL-terminated string to scan
*
* @return the newly allocated buffer state object.
* @note If you want to scan bytes that may contain NUL values, then use
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 4d09f6ddefe3..8e69461313d1 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -21,7 +21,7 @@ P(menu_get_help,const char *,(struct menu *menu));
/* symbol.c */
P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
-P(sym_lookup,struct symbol *,(const char *name, int isconst));
+P(sym_lookup,struct symbol *,(const char *name, int flags));
P(sym_find,struct symbol *,(const char *name));
P(sym_re_search,struct symbol **,(const char *pattern));
P(sym_type_name,const char *,(enum symbol_type type));
diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
index 4946bd02b46d..616c60138183 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -89,7 +89,7 @@ do_resize:
box_y = y + 2;
box_x = (width - box_width) / 2;
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
- dlg.border.atr, dlg.dialog.atr);
+ dlg.dialog.atr, dlg.border.atr);
print_buttons(dialog, height, width, 0);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 606ceb9e746e..07ff8d105c9d 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -235,18 +235,22 @@ void menu_finalize(struct menu *parent)
sym = parent->sym;
if (parent->list) {
if (sym && sym_is_choice(sym)) {
- /* find the first choice value and find out choice type */
- for (menu = parent->list; menu; menu = menu->next) {
- if (menu->sym) {
- current_entry = parent;
- if (sym->type == S_UNKNOWN)
+ if (sym->type == S_UNKNOWN) {
+ /* find the first choice value to find out choice type */
+ current_entry = parent;
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (menu->sym && menu->sym->type != S_UNKNOWN) {
menu_set_type(menu->sym->type);
- current_entry = menu;
- if (menu->sym->type == S_UNKNOWN)
- menu_set_type(sym->type);
- break;
+ break;
+ }
}
}
+ /* set the type of the remaining choice values */
+ for (menu = parent->list; menu; menu = menu->next) {
+ current_entry = menu;
+ if (menu->sym && menu->sym->type == S_UNKNOWN)
+ menu_set_type(sym->type);
+ }
parentdep = expr_alloc_symbol(sym);
} else if (parent->prompt)
parentdep = parent->prompt->visible.expr;
@@ -313,50 +317,36 @@ void menu_finalize(struct menu *parent)
}
}
for (menu = parent->list; menu; menu = menu->next) {
- if (sym && sym_is_choice(sym) && menu->sym) {
+ if (sym && sym_is_choice(sym) &&
+ menu->sym && !sym_is_choice_value(menu->sym)) {
+ current_entry = menu;
menu->sym->flags |= SYMBOL_CHOICEVAL;
if (!menu->prompt)
menu_warn(menu, "choice value must have a prompt");
for (prop = menu->sym->prop; prop; prop = prop->next) {
- if (prop->type == P_PROMPT && prop->menu != menu) {
- prop_warn(prop, "choice values "
- "currently only support a "
- "single prompt");
- }
if (prop->type == P_DEFAULT)
prop_warn(prop, "defaults for choice "
- "values not supported");
+ "values not supported");
+ if (prop->menu == menu)
+ continue;
+ if (prop->type == P_PROMPT &&
+ prop->menu->parent->sym != sym)
+ prop_warn(prop, "choice value used outside its choice group");
}
- current_entry = menu;
- if (menu->sym->type == S_UNKNOWN)
- menu_set_type(sym->type);
/* Non-tristate choice values of tristate choices must
* depend on the choice being set to Y. The choice
* values' dependencies were propagated to their
* properties above, so the change here must be re-
- * propagated. */
+ * propagated.
+ */
if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
- basedep = expr_alloc_and(basedep, menu->dep);
- basedep = expr_eliminate_dups(basedep);
- menu->dep = basedep;
+ menu->dep = expr_alloc_and(basedep, menu->dep);
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
- dep = expr_alloc_and(expr_copy(basedep),
- prop->visible.expr);
- dep = expr_eliminate_dups(dep);
- dep = expr_trans_bool(dep);
- prop->visible.expr = dep;
- if (prop->type == P_SELECT) {
- struct symbol *es = prop_get_symbol(prop);
- dep2 = expr_alloc_symbol(menu->sym);
- dep = expr_alloc_and(dep2,
- expr_copy(dep));
- dep = expr_alloc_or(es->rev_dep.expr, dep);
- dep = expr_eliminate_dups(dep);
- es->rev_dep.expr = dep;
- }
+ prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+ prop->visible.expr);
}
}
menu_add_symbol(P_CHOICE, sym, NULL);
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 4a03191ad176..18f3e5c33634 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -40,7 +40,7 @@ void sym_add_default(struct symbol *sym, const char *def)
{
struct property *prop = prop_alloc(P_DEFAULT, sym);
- prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+ prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
}
void sym_init(void)
@@ -350,9 +350,6 @@ void sym_calc_value(struct symbol *sym)
;
}
- if (sym->flags & SYMBOL_AUTO)
- sym->flags &= ~SYMBOL_WRITE;
-
sym->curr = newval;
if (sym_is_choice(sym) && newval.tri == yes)
sym->curr.val = sym_calc_choice(sym);
@@ -377,6 +374,9 @@ void sym_calc_value(struct symbol *sym)
sym_set_changed(choice_sym);
}
}
+
+ if (sym->flags & SYMBOL_AUTO)
+ sym->flags &= ~SYMBOL_WRITE;
}
void sym_clear_all_valid(void)
@@ -651,7 +651,7 @@ bool sym_is_changable(struct symbol *sym)
return sym->visible > sym->rev_dep.tri;
}
-struct symbol *sym_lookup(const char *name, int isconst)
+struct symbol *sym_lookup(const char *name, int flags)
{
struct symbol *symbol;
const char *ptr;
@@ -671,11 +671,10 @@ struct symbol *sym_lookup(const char *name, int isconst)
hash &= 0xff;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (!strcmp(symbol->name, name)) {
- if ((isconst && symbol->flags & SYMBOL_CONST) ||
- (!isconst && !(symbol->flags & SYMBOL_CONST)))
- return symbol;
- }
+ if (!strcmp(symbol->name, name) &&
+ (flags ? symbol->flags & flags
+ : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+ return symbol;
}
new_name = strdup(name);
} else {
@@ -687,8 +686,7 @@ struct symbol *sym_lookup(const char *name, int isconst)
memset(symbol, 0, sizeof(*symbol));
symbol->name = new_name;
symbol->type = S_UNKNOWN;
- if (isconst)
- symbol->flags |= SYMBOL_CONST;
+ symbol->flags |= flags;
symbol->next = symbol_hash[hash];
symbol_hash[hash] = symbol;
@@ -762,8 +760,6 @@ struct symbol **sym_re_search(const char *pattern)
}
-struct symbol *sym_check_deps(struct symbol *sym);
-
static struct symbol *sym_check_expr_deps(struct expr *e)
{
struct symbol *sym;
@@ -795,40 +791,100 @@ static struct symbol *sym_check_expr_deps(struct expr *e)
}
/* return NULL when dependencies are OK */
-struct symbol *sym_check_deps(struct symbol *sym)
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
- if (sym->flags & SYMBOL_CHECK) {
- fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
- sym->prop->file->name, sym->prop->lineno, sym->name);
- return sym;
- }
- if (sym->flags & SYMBOL_CHECKED)
- return NULL;
-
- sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
if (sym2)
- goto out;
+ return sym2;
for (prop = sym->prop; prop; prop = prop->next) {
if (prop->type == P_CHOICE || prop->type == P_SELECT)
continue;
sym2 = sym_check_expr_deps(prop->visible.expr);
if (sym2)
- goto out;
+ break;
if (prop->type != P_DEFAULT || sym_is_choice(sym))
continue;
sym2 = sym_check_expr_deps(prop->expr);
if (sym2)
- goto out;
+ break;
}
-out:
+
+ return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(choice);
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+ choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(choice);
+ choice->flags &= ~SYMBOL_CHECK;
if (sym2)
- fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": "");
- sym->flags &= ~SYMBOL_CHECK;
+ goto out;
+
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ sym2 = sym_check_sym_deps(sym);
+ if (sym2) {
+ fprintf(stderr, " -> %s", sym->name);
+ break;
+ }
+ }
+out:
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags &= ~SYMBOL_CHECK;
+
+ if (sym2 && sym_is_choice_value(sym2) &&
+ prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+ sym2 = choice;
+
+ return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+
+ if (sym->flags & SYMBOL_CHECK) {
+ fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
+ sym->prop->file->name, sym->prop->lineno,
+ sym->name ? sym->name : "<choice>");
+ return sym;
+ }
+ if (sym->flags & SYMBOL_CHECKED)
+ return NULL;
+
+ if (sym_is_choice_value(sym)) {
+ /* for choice groups start the check with main choice symbol */
+ prop = sym_get_choice_prop(sym);
+ sym2 = sym_check_deps(prop_get_symbol(prop));
+ } else if (sym_is_choice(sym)) {
+ sym2 = sym_check_choice_deps(sym);
+ } else {
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(sym);
+ sym->flags &= ~SYMBOL_CHECK;
+ }
+
+ if (sym2) {
+ fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
+ if (sym2 == sym) {
+ fprintf(stderr, "\n");
+ zconfnerrs++;
+ sym2 = NULL;
+ }
+ }
+
return sym2;
}
@@ -904,7 +960,7 @@ void prop_add_env(const char *env)
}
prop = prop_alloc(P_ENV, sym);
- prop->expr = expr_alloc_symbol(sym_lookup(env, 1));
+ prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
sym_env_list->right.sym = sym;
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index d22d92496f25..95df833b5a9d 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -446,16 +446,16 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 3
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 258
+#define YYLAST 259
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 35
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 45
+#define YYNNTS 46
/* YYNRULES -- Number of rules. */
-#define YYNRULES 108
+#define YYNRULES 110
/* YYNRULES -- Number of states. */
-#define YYNSTATES 178
+#define YYNSTATES 180
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
@@ -507,13 +507,14 @@ static const yytype_uint16 yyprhs[] =
28, 33, 37, 39, 41, 43, 45, 47, 49, 51,
53, 55, 57, 59, 61, 63, 67, 70, 74, 77,
81, 84, 85, 88, 91, 94, 97, 100, 103, 107,
- 112, 117, 122, 128, 132, 133, 137, 138, 141, 144,
- 147, 149, 153, 154, 157, 160, 163, 166, 169, 174,
- 178, 181, 186, 187, 190, 194, 196, 200, 201, 204,
- 207, 210, 214, 217, 219, 223, 224, 227, 230, 233,
- 237, 241, 244, 247, 250, 251, 254, 257, 260, 265,
- 266, 269, 271, 273, 276, 279, 282, 284, 287, 288,
- 291, 293, 297, 301, 305, 308, 312, 316, 318
+ 112, 117, 122, 128, 132, 133, 137, 138, 141, 145,
+ 148, 150, 154, 155, 158, 161, 164, 167, 170, 175,
+ 179, 182, 187, 188, 191, 195, 197, 201, 202, 205,
+ 208, 211, 215, 218, 220, 224, 225, 228, 231, 234,
+ 238, 242, 245, 248, 251, 252, 255, 258, 261, 266,
+ 267, 270, 272, 274, 277, 280, 283, 285, 288, 289,
+ 292, 294, 298, 302, 306, 309, 313, 317, 319, 321,
+ 322
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
@@ -533,24 +534,25 @@ static const yytype_int8 yyrhs[] =
30, -1, 20, 78, 77, 30, -1, 21, 25, 77,
30, -1, 22, 79, 79, 77, 30, -1, 23, 48,
30, -1, -1, 48, 25, 49, -1, -1, 33, 74,
- -1, 7, 30, -1, 50, 54, -1, 75, -1, 51,
- 56, 52, -1, -1, 54, 55, -1, 54, 72, -1,
- 54, 70, -1, 54, 30, -1, 54, 40, -1, 18,
- 74, 77, 30, -1, 19, 73, 30, -1, 17, 30,
- -1, 20, 25, 77, 30, -1, -1, 56, 39, -1,
- 14, 78, 76, -1, 75, -1, 57, 60, 58, -1,
- -1, 60, 39, -1, 60, 64, -1, 60, 53, -1,
- 4, 74, 30, -1, 61, 71, -1, 75, -1, 62,
- 65, 63, -1, -1, 65, 39, -1, 65, 64, -1,
- 65, 53, -1, 6, 74, 30, -1, 9, 74, 30,
- -1, 67, 71, -1, 12, 30, -1, 69, 13, -1,
- -1, 71, 72, -1, 71, 30, -1, 71, 40, -1,
- 16, 24, 78, 30, -1, -1, 74, 77, -1, 25,
- -1, 26, -1, 5, 30, -1, 8, 30, -1, 15,
- 30, -1, 30, -1, 76, 30, -1, -1, 14, 78,
- -1, 79, -1, 79, 33, 79, -1, 79, 27, 79,
- -1, 29, 78, 28, -1, 34, 78, -1, 78, 31,
- 78, -1, 78, 32, 78, -1, 25, -1, 26, -1
+ -1, 7, 80, 30, -1, 50, 54, -1, 75, -1,
+ 51, 56, 52, -1, -1, 54, 55, -1, 54, 72,
+ -1, 54, 70, -1, 54, 30, -1, 54, 40, -1,
+ 18, 74, 77, 30, -1, 19, 73, 30, -1, 17,
+ 30, -1, 20, 25, 77, 30, -1, -1, 56, 39,
+ -1, 14, 78, 76, -1, 75, -1, 57, 60, 58,
+ -1, -1, 60, 39, -1, 60, 64, -1, 60, 53,
+ -1, 4, 74, 30, -1, 61, 71, -1, 75, -1,
+ 62, 65, 63, -1, -1, 65, 39, -1, 65, 64,
+ -1, 65, 53, -1, 6, 74, 30, -1, 9, 74,
+ 30, -1, 67, 71, -1, 12, 30, -1, 69, 13,
+ -1, -1, 71, 72, -1, 71, 30, -1, 71, 40,
+ -1, 16, 24, 78, 30, -1, -1, 74, 77, -1,
+ 25, -1, 26, -1, 5, 30, -1, 8, 30, -1,
+ 15, 30, -1, 30, -1, 76, 30, -1, -1, 14,
+ 78, -1, 79, -1, 79, 33, 79, -1, 79, 27,
+ 79, -1, 29, 78, 28, -1, 34, 78, -1, 78,
+ 31, 78, -1, 78, 32, 78, -1, 25, -1, 26,
+ -1, -1, 25, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
@@ -566,7 +568,8 @@ static const yytype_uint16 yyrline[] =
339, 344, 351, 356, 364, 367, 369, 370, 371, 374,
382, 389, 396, 402, 409, 411, 412, 413, 416, 424,
426, 431, 432, 435, 436, 437, 441, 442, 445, 446,
- 449, 450, 451, 452, 453, 454, 455, 458, 459
+ 449, 450, 451, 452, 453, 454, 455, 458, 459, 462,
+ 463
};
#endif
@@ -590,7 +593,8 @@ static const char *const yytname[] =
"if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry",
"menu_end", "menu_stmt", "menu_block", "source_stmt", "comment",
"comment_stmt", "help_start", "help", "depends_list", "depends",
- "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol", 0
+ "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol",
+ "word_opt", 0
};
#endif
@@ -619,7 +623,8 @@ static const yytype_uint8 yyr1[] =
60, 61, 62, 63, 64, 65, 65, 65, 65, 66,
67, 68, 69, 70, 71, 71, 71, 71, 72, 73,
73, 74, 74, 75, 75, 75, 76, 76, 77, 77,
- 78, 78, 78, 78, 78, 78, 78, 79, 79
+ 78, 78, 78, 78, 78, 78, 78, 79, 79, 80,
+ 80
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
@@ -629,13 +634,14 @@ static const yytype_uint8 yyr2[] =
4, 3, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 3, 2, 3, 2, 3,
2, 0, 2, 2, 2, 2, 2, 2, 3, 4,
- 4, 4, 5, 3, 0, 3, 0, 2, 2, 2,
+ 4, 4, 5, 3, 0, 3, 0, 2, 3, 2,
1, 3, 0, 2, 2, 2, 2, 2, 4, 3,
2, 4, 0, 2, 3, 1, 3, 0, 2, 2,
2, 3, 2, 1, 3, 0, 2, 2, 2, 3,
3, 2, 2, 2, 0, 2, 2, 2, 4, 0,
2, 1, 1, 2, 2, 2, 1, 2, 0, 2,
- 1, 3, 3, 3, 2, 3, 3, 1, 1
+ 1, 3, 3, 3, 2, 3, 3, 1, 1, 0,
+ 1
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -643,69 +649,69 @@ static const yytype_uint8 yyr2[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 3, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 1, 0, 0, 0, 0, 0, 109,
0, 0, 0, 0, 0, 0, 12, 16, 13, 14,
18, 15, 17, 0, 19, 0, 4, 31, 22, 31,
23, 52, 62, 5, 67, 20, 84, 75, 6, 24,
84, 21, 8, 11, 91, 92, 0, 0, 93, 0,
- 48, 94, 0, 0, 0, 107, 108, 0, 0, 0,
- 100, 95, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 96, 7, 71, 79, 80, 27, 29, 0,
- 104, 0, 0, 64, 0, 0, 9, 10, 0, 0,
- 0, 0, 89, 0, 0, 0, 44, 0, 37, 36,
- 32, 33, 0, 35, 34, 0, 0, 89, 0, 56,
- 57, 53, 55, 54, 63, 51, 50, 68, 70, 66,
- 69, 65, 86, 87, 85, 76, 78, 74, 77, 73,
- 97, 103, 105, 106, 102, 101, 26, 82, 0, 98,
- 0, 98, 98, 98, 0, 0, 0, 83, 60, 98,
- 0, 98, 0, 0, 0, 38, 90, 0, 0, 98,
- 46, 43, 25, 0, 59, 0, 88, 99, 39, 40,
- 41, 0, 0, 45, 58, 61, 42, 47
+ 110, 0, 94, 0, 0, 0, 107, 108, 0, 0,
+ 0, 100, 95, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 96, 7, 71, 79, 48, 80, 27,
+ 29, 0, 104, 0, 0, 64, 0, 0, 9, 10,
+ 0, 0, 0, 0, 89, 0, 0, 0, 44, 0,
+ 37, 36, 32, 33, 0, 35, 34, 0, 0, 89,
+ 0, 56, 57, 53, 55, 54, 63, 51, 50, 68,
+ 70, 66, 69, 65, 86, 87, 85, 76, 78, 74,
+ 77, 73, 97, 103, 105, 106, 102, 101, 26, 82,
+ 0, 98, 0, 98, 98, 98, 0, 0, 0, 83,
+ 60, 98, 0, 98, 0, 0, 0, 38, 90, 0,
+ 0, 98, 46, 43, 25, 0, 59, 0, 88, 99,
+ 39, 40, 41, 0, 0, 45, 58, 61, 42, 47
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 2, 25, 26, 99, 27, 28, 29, 30,
- 64, 100, 101, 145, 173, 31, 32, 115, 33, 66,
- 111, 67, 34, 119, 35, 68, 36, 37, 127, 38,
- 70, 39, 40, 41, 102, 103, 69, 104, 140, 141,
- 42, 73, 154, 59, 60
+ -1, 1, 2, 25, 26, 101, 27, 28, 29, 30,
+ 65, 102, 103, 147, 175, 31, 32, 117, 33, 67,
+ 113, 68, 34, 121, 35, 69, 36, 37, 129, 38,
+ 71, 39, 40, 41, 104, 105, 70, 106, 142, 143,
+ 42, 74, 156, 60, 61, 51
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -78
+#define YYPACT_NINF -80
static const yytype_int16 yypact[] =
{
- -78, 33, 130, -78, -28, 73, 73, 7, 73, 36,
- 41, 73, 26, 52, -4, 58, -78, -78, -78, -78,
- -78, -78, -78, 90, -78, 94, -78, -78, -78, -78,
- -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
- -78, -78, -78, -78, -78, -78, 74, 85, -78, 96,
- -78, -78, 131, 134, 147, -78, -78, -4, -4, 193,
- -10, -78, 162, 164, 38, 102, 64, 148, 5, 192,
- 5, 165, -78, 174, -78, -78, -78, -78, -78, 65,
- -78, -4, -4, 174, 103, 103, -78, -78, 175, 185,
- 197, 73, 73, -4, 194, 103, -78, 231, -78, -78,
- -78, -78, 220, -78, -78, 204, 73, 73, 210, -78,
- -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
- -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
- -78, -78, 205, -78, -78, -78, -78, -78, -4, 222,
- 208, 222, 195, 222, 103, 2, 209, -78, -78, 222,
- 211, 222, 199, -4, 212, -78, -78, 213, 214, 222,
- 207, -78, -78, 215, -78, 216, -78, 111, -78, -78,
- -78, 217, 73, -78, -78, -78, -78, -78
+ -80, 2, 132, -80, -13, -1, -1, -2, -1, 9,
+ 33, -1, 27, 40, -3, 38, -80, -80, -80, -80,
+ -80, -80, -80, 71, -80, 77, -80, -80, -80, -80,
+ -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
+ -80, -80, -80, -80, -80, -80, 57, 61, -80, 63,
+ -80, 76, -80, 87, 101, 133, -80, -80, -3, -3,
+ 195, -6, -80, 136, 149, 39, 104, 65, 150, 5,
+ 194, 5, 167, -80, 176, -80, -80, -80, -80, -80,
+ -80, 68, -80, -3, -3, 176, 72, 72, -80, -80,
+ 177, 187, 78, -1, -1, -3, 196, 72, -80, 222,
+ -80, -80, -80, -80, 221, -80, -80, 205, -1, -1,
+ 211, -80, -80, -80, -80, -80, -80, -80, -80, -80,
+ -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
+ -80, -80, -80, -80, 206, -80, -80, -80, -80, -80,
+ -3, 223, 209, 223, 197, 223, 72, 7, 210, -80,
+ -80, 223, 212, 223, 201, -3, 213, -80, -80, 214,
+ 215, 223, 208, -80, -80, 216, -80, 217, -80, 113,
+ -80, -80, -80, 218, -1, -80, -80, -80, -80, -80
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -78, -78, -78, -78, 121, -35, -78, -78, -78, -78,
- 219, -78, -78, -78, -78, -78, -78, -78, -44, -78,
- -78, -78, -78, -78, -78, -78, -78, -78, -78, -6,
- -78, -78, -78, -78, -78, 183, 218, 21, 143, -5,
- 146, 196, 69, -53, -77
+ -80, -80, -80, -80, 122, -34, -80, -80, -80, -80,
+ 220, -80, -80, -80, -80, -80, -80, -80, 59, -80,
+ -80, -80, -80, -80, -80, -80, -80, -80, -80, 125,
+ -80, -80, -80, -80, -80, 183, 219, 22, 142, -5,
+ 147, 192, 69, -54, -79, -80
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
@@ -715,62 +721,62 @@ static const yytype_int16 yypgoto[] =
#define YYTABLE_NINF -82
static const yytype_int16 yytable[] =
{
- 46, 47, 43, 49, 79, 80, 52, 134, 135, 6,
- 7, 8, 9, 10, 11, 12, 13, 84, 144, 14,
- 15, 55, 56, 85, 118, 57, 126, 160, 132, 133,
- 58, 110, 161, 3, 123, 24, 123, 48, -28, 88,
- 142, -28, -28, -28, -28, -28, -28, -28, -28, -28,
- 89, 53, -28, -28, 90, -28, 91, 92, 93, 94,
- 95, 96, 120, 97, 128, 88, 50, 159, 98, -49,
- -49, 51, -49, -49, -49, -49, 89, 54, -49, -49,
- 90, 105, 106, 107, 108, 152, 139, 113, 61, 97,
- 124, 62, 124, 131, 109, 63, 81, 82, 44, 45,
- 167, 149, -30, 88, 72, -30, -30, -30, -30, -30,
- -30, -30, -30, -30, 89, 74, -30, -30, 90, -30,
- 91, 92, 93, 94, 95, 96, 75, 97, 55, 56,
- -2, 4, 98, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 81, 82, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 7, 8, 23, 10, 11, 12, 13,
- 24, 76, 14, 15, 77, -81, 88, 177, -81, -81,
- -81, -81, -81, -81, -81, -81, -81, 78, 24, -81,
- -81, 90, -81, -81, -81, -81, -81, -81, 114, 117,
- 97, 125, 86, 88, 87, 122, -72, -72, -72, -72,
- -72, -72, -72, -72, 130, 136, -72, -72, 90, 153,
- 156, 157, 158, 116, 121, 137, 129, 97, 163, 143,
- 165, 138, 122, 72, 81, 82, 81, 82, 171, 166,
- 81, 82, 146, 147, 148, 151, 153, 82, 155, 162,
- 172, 164, 168, 169, 170, 174, 175, 176, 65, 112,
- 150, 0, 0, 0, 0, 83, 0, 0, 71
+ 46, 47, 3, 49, 81, 82, 53, 136, 137, 6,
+ 7, 8, 9, 10, 11, 12, 13, 43, 146, 14,
+ 15, 86, 56, 57, 44, 45, 58, 87, 48, 134,
+ 135, 59, 162, 112, 50, 24, 125, 163, 125, -28,
+ 90, 144, -28, -28, -28, -28, -28, -28, -28, -28,
+ -28, 91, 54, -28, -28, 92, -28, 93, 94, 95,
+ 96, 97, 98, 52, 99, 55, 90, 161, 62, 100,
+ -49, -49, 63, -49, -49, -49, -49, 91, 64, -49,
+ -49, 92, 107, 108, 109, 110, 154, 73, 141, 115,
+ 99, 75, 126, 76, 126, 111, 133, 56, 57, 83,
+ 84, 169, 140, 151, -30, 90, 77, -30, -30, -30,
+ -30, -30, -30, -30, -30, -30, 91, 78, -30, -30,
+ 92, -30, 93, 94, 95, 96, 97, 98, 120, 99,
+ 128, 79, -2, 4, 100, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 83, 84, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 7, 8, 23, 10, 11,
+ 12, 13, 24, 80, 14, 15, 88, -81, 90, 179,
+ -81, -81, -81, -81, -81, -81, -81, -81, -81, 89,
+ 24, -81, -81, 92, -81, -81, -81, -81, -81, -81,
+ 116, 119, 99, 127, 122, 90, 130, 124, -72, -72,
+ -72, -72, -72, -72, -72, -72, 132, 138, -72, -72,
+ 92, 155, 158, 159, 160, 118, 123, 139, 131, 99,
+ 165, 145, 167, 148, 124, 73, 83, 84, 83, 84,
+ 173, 168, 83, 84, 149, 150, 153, 155, 84, 157,
+ 164, 174, 166, 170, 171, 172, 176, 177, 178, 66,
+ 114, 152, 85, 0, 0, 0, 0, 0, 0, 72
};
static const yytype_int16 yycheck[] =
{
- 5, 6, 30, 8, 57, 58, 11, 84, 85, 4,
- 5, 6, 7, 8, 9, 10, 11, 27, 95, 14,
- 15, 25, 26, 33, 68, 29, 70, 25, 81, 82,
- 34, 66, 30, 0, 69, 30, 71, 30, 0, 1,
- 93, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 25, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 68, 25, 70, 1, 30, 144, 30, 5,
- 6, 30, 8, 9, 10, 11, 12, 25, 14, 15,
- 16, 17, 18, 19, 20, 138, 91, 66, 30, 25,
- 69, 1, 71, 28, 30, 1, 31, 32, 25, 26,
- 153, 106, 0, 1, 30, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 30, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 30, 25, 25, 26,
- 0, 1, 30, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 31, 32, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 5, 6, 25, 8, 9, 10, 11,
- 30, 30, 14, 15, 30, 0, 1, 172, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 30, 30, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 67, 68,
- 25, 70, 30, 1, 30, 30, 4, 5, 6, 7,
- 8, 9, 10, 11, 30, 30, 14, 15, 16, 14,
- 141, 142, 143, 67, 68, 30, 70, 25, 149, 25,
- 151, 24, 30, 30, 31, 32, 31, 32, 159, 30,
- 31, 32, 1, 13, 30, 25, 14, 32, 30, 30,
- 33, 30, 30, 30, 30, 30, 30, 30, 29, 66,
- 107, -1, -1, -1, -1, 59, -1, -1, 40
+ 5, 6, 0, 8, 58, 59, 11, 86, 87, 4,
+ 5, 6, 7, 8, 9, 10, 11, 30, 97, 14,
+ 15, 27, 25, 26, 25, 26, 29, 33, 30, 83,
+ 84, 34, 25, 67, 25, 30, 70, 30, 72, 0,
+ 1, 95, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 25, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 30, 25, 25, 1, 146, 30, 30,
+ 5, 6, 1, 8, 9, 10, 11, 12, 1, 14,
+ 15, 16, 17, 18, 19, 20, 140, 30, 93, 67,
+ 25, 30, 70, 30, 72, 30, 28, 25, 26, 31,
+ 32, 155, 24, 108, 0, 1, 30, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 30, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 69, 25,
+ 71, 30, 0, 1, 30, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 31, 32, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 5, 6, 25, 8, 9,
+ 10, 11, 30, 30, 14, 15, 30, 0, 1, 174,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 30,
+ 30, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 68, 69, 25, 71, 69, 1, 71, 30, 4, 5,
+ 6, 7, 8, 9, 10, 11, 30, 30, 14, 15,
+ 16, 14, 143, 144, 145, 68, 69, 30, 71, 25,
+ 151, 25, 153, 1, 30, 30, 31, 32, 31, 32,
+ 161, 30, 31, 32, 13, 30, 25, 14, 32, 30,
+ 30, 33, 30, 30, 30, 30, 30, 30, 30, 29,
+ 67, 109, 60, -1, -1, -1, -1, -1, -1, 40
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -782,19 +788,19 @@ static const yytype_uint8 yystos[] =
20, 21, 22, 25, 30, 38, 39, 41, 42, 43,
44, 50, 51, 53, 57, 59, 61, 62, 64, 66,
67, 68, 75, 30, 25, 26, 74, 74, 30, 74,
- 30, 30, 74, 25, 25, 25, 26, 29, 34, 78,
- 79, 30, 1, 1, 45, 45, 54, 56, 60, 71,
- 65, 71, 30, 76, 30, 30, 30, 30, 30, 78,
- 78, 31, 32, 76, 27, 33, 30, 30, 1, 12,
- 16, 18, 19, 20, 21, 22, 23, 25, 30, 40,
- 46, 47, 69, 70, 72, 17, 18, 19, 20, 30,
- 40, 55, 70, 72, 39, 52, 75, 39, 53, 58,
- 64, 75, 30, 40, 72, 39, 53, 63, 64, 75,
- 30, 28, 78, 78, 79, 79, 30, 30, 24, 74,
- 73, 74, 78, 25, 79, 48, 1, 13, 30, 74,
- 73, 25, 78, 14, 77, 30, 77, 77, 77, 79,
- 25, 30, 30, 77, 30, 77, 30, 78, 30, 30,
- 30, 77, 33, 49, 30, 30, 30, 74
+ 25, 80, 30, 74, 25, 25, 25, 26, 29, 34,
+ 78, 79, 30, 1, 1, 45, 45, 54, 56, 60,
+ 71, 65, 71, 30, 76, 30, 30, 30, 30, 30,
+ 30, 78, 78, 31, 32, 76, 27, 33, 30, 30,
+ 1, 12, 16, 18, 19, 20, 21, 22, 23, 25,
+ 30, 40, 46, 47, 69, 70, 72, 17, 18, 19,
+ 20, 30, 40, 55, 70, 72, 39, 52, 75, 39,
+ 53, 58, 64, 75, 30, 40, 72, 39, 53, 63,
+ 64, 75, 30, 28, 78, 78, 79, 79, 30, 30,
+ 24, 74, 73, 74, 78, 25, 79, 48, 1, 13,
+ 30, 74, 73, 25, 78, 14, 77, 30, 77, 77,
+ 77, 79, 25, 30, 30, 77, 30, 77, 30, 78,
+ 30, 30, 30, 77, 33, 49, 30, 30, 30, 74
};
#define yyerrok (yyerrstatus = 0)
@@ -1781,8 +1787,8 @@ yyreduce:
case 48:
{
- struct symbol *sym = sym_lookup(NULL, 0);
- sym->flags |= SYMBOL_CHOICE;
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
menu_add_entry(sym);
menu_add_expr(P_CHOICE, NULL, NULL);
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
@@ -2014,7 +2020,12 @@ yyreduce:
case 108:
- { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 1); free((yyvsp[(1) - (1)].string)); ;}
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+ break;
+
+ case 109:
+
+ { (yyval.string) = NULL; ;}
break;
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index d9b96ba8e38c..9710b82466f2 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -91,7 +91,7 @@ static struct menu *current_menu, *current_entry;
%type <id> end
%type <id> option_name
%type <menu> if_entry menu_entry choice_entry
-%type <string> symbol_option_arg
+%type <string> symbol_option_arg word_opt
%destructor {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
@@ -239,10 +239,10 @@ symbol_option_arg:
/* choice entry */
-choice: T_CHOICE T_EOL
+choice: T_CHOICE word_opt T_EOL
{
- struct symbol *sym = sym_lookup(NULL, 0);
- sym->flags |= SYMBOL_CHOICE;
+ struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
menu_add_entry(sym);
menu_add_expr(P_CHOICE, NULL, NULL);
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
@@ -456,9 +456,12 @@ expr: symbol { $$ = expr_alloc_symbol($1); }
;
symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
- | T_WORD_QUOTE { $$ = sym_lookup($1, 1); free($1); }
+ | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
;
+word_opt: /* empty */ { $$ = NULL; }
+ | T_WORD
+
%%
void conf_parse(const char *name)
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 263d04ab2d94..83cee18a02e9 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -5,7 +5,7 @@ use strict;
## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
## Copyright (C) 2001 Simon Huggins ##
-## Copyright (C) 2005-2007 Randy Dunlap ##
+## Copyright (C) 2005-2008 Randy Dunlap ##
## ##
## #define enhancements by Armin Kuster <akuster@mvista.com> ##
## Copyright (c) 2000 MontaVista Software, Inc. ##
@@ -366,6 +366,7 @@ foreach my $pattern (keys %highlights) {
# dumps section contents to arrays/hashes intended for that purpose.
#
sub dump_section {
+ my $file = shift;
my $name = shift;
my $contents = join "\n", @_;
@@ -379,6 +380,10 @@ sub dump_section {
$parameterdescs{$name} = $contents;
} else {
# print STDERR "other section '$name' = '$contents'\n";
+ if (defined($sections{$name}) && ($sections{$name} ne "")) {
+ print STDERR "Error(${file}:$.): duplicate section name '$name'\n";
+ ++$errors;
+ }
$sections{$name} = $contents;
push @sectionlist, $name;
}
@@ -388,6 +393,7 @@ sub dump_section {
# dump DOC: section after checking that it should go out
#
sub dump_doc_section {
+ my $file = shift;
my $name = shift;
my $contents = join "\n", @_;
@@ -399,7 +405,7 @@ sub dump_doc_section {
( $function_only == 1 && defined($function_table{$name})) ||
( $function_only == 2 && !defined($function_table{$name})))
{
- dump_section $name, $contents;
+ dump_section($file, $name, $contents);
output_blockhead({'sectionlist' => \@sectionlist,
'sections' => \%sections,
'module' => $modulename,
@@ -1923,7 +1929,7 @@ sub process_file($) {
print STDERR "Warning(${file}:$.): contents before sections\n";
++$warnings;
}
- dump_section($section, xml_escape($contents));
+ dump_section($file, $section, xml_escape($contents));
$section = $section_default;
}
@@ -1940,10 +1946,15 @@ sub process_file($) {
} elsif (/$doc_end/) {
if ($contents ne "") {
- dump_section($section, xml_escape($contents));
+ dump_section($file, $section, xml_escape($contents));
$section = $section_default;
$contents = "";
}
+ # look for doc_com + <text> + doc_end:
+ if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') {
+ print STDERR "Warning(${file}:$.): suspicious ending line: $_";
+ ++$warnings;
+ }
$prototype = "";
$state = 3;
@@ -1954,7 +1965,7 @@ sub process_file($) {
# @parameter line to signify start of description
if ($1 eq "" &&
($section =~ m/^@/ || $section eq $section_context)) {
- dump_section($section, xml_escape($contents));
+ dump_section($file, $section, xml_escape($contents));
$section = $section_default;
$contents = "";
} else {
@@ -1974,7 +1985,7 @@ sub process_file($) {
} elsif ($state == 4) {
# Documentation block
if (/$doc_block/) {
- dump_doc_section($section, xml_escape($contents));
+ dump_doc_section($file, $section, xml_escape($contents));
$contents = "";
$function = "";
%constants = ();
@@ -1992,7 +2003,7 @@ sub process_file($) {
}
elsif (/$doc_end/)
{
- dump_doc_section($section, xml_escape($contents));
+ dump_doc_section($file, $section, xml_escape($contents));
$contents = "";
$function = "";
%constants = ();
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 110cf243fa4e..757294b4f322 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1552,6 +1552,10 @@ static void read_symbols(char *modname)
}
license = get_modinfo(info.modinfo, info.modinfo_len, "license");
+ if (info.modinfo && !license && !is_vmlinux(modname))
+ warn("modpost: missing MODULE_LICENSE() in %s\n"
+ "see include/linux/module.h for "
+ "more information\n", modname);
while (license) {
if (license_is_gpl_compatible(license))
mod->gpl_compatible = 1;
@@ -2015,6 +2019,11 @@ static void write_markers(const char *fname)
write_if_changed(&buf, fname);
}
+struct ext_sym_list {
+ struct ext_sym_list *next;
+ const char *file;
+};
+
int main(int argc, char **argv)
{
struct module *mod;
@@ -2025,8 +2034,10 @@ int main(int argc, char **argv)
char *markers_write = NULL;
int opt;
int err;
+ struct ext_sym_list *extsym_iter;
+ struct ext_sym_list *extsym_start = NULL;
- while ((opt = getopt(argc, argv, "i:I:cmsSo:awM:K:")) != -1) {
+ while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) {
switch (opt) {
case 'i':
kernel_read = optarg;
@@ -2038,6 +2049,14 @@ int main(int argc, char **argv)
case 'c':
cross_build = 1;
break;
+ case 'e':
+ external_module = 1;
+ extsym_iter =
+ NOFAIL(malloc(sizeof(*extsym_iter)));
+ extsym_iter->next = extsym_start;
+ extsym_iter->file = optarg;
+ extsym_start = extsym_iter;
+ break;
case 'm':
modversions = 1;
break;
@@ -2071,6 +2090,12 @@ int main(int argc, char **argv)
read_dump(kernel_read, 1);
if (module_read)
read_dump(module_read, 0);
+ while (extsym_start) {
+ read_dump(extsym_start->file, 0);
+ extsym_iter = extsym_start->next;
+ free(extsym_start);
+ extsym_start = extsym_iter;
+ }
while (optind < argc)
read_symbols(argv[optind++]);
diff --git a/security/capability.c b/security/capability.c
index 2c6e06d18fab..38ac54e3aed1 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -44,6 +44,7 @@ static struct security_operations capability_ops = {
.task_setioprio = cap_task_setioprio,
.task_setnice = cap_task_setnice,
.task_post_setuid = cap_task_post_setuid,
+ .task_prctl = cap_task_prctl,
.task_reparent_to_init = cap_task_reparent_to_init,
.syslog = cap_syslog,
diff --git a/security/commoncap.c b/security/commoncap.c
index 852905789caf..e8c3f5e46705 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -24,11 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>
-
-/* Global security state */
-
-unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
-EXPORT_SYMBOL(securebits);
+#include <linux/prctl.h>
+#include <linux/securebits.h>
int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
{
@@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
/* AUD: Audit candidate if current->cap_effective is set */
- current->keep_capabilities = 0;
+ current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
}
int cap_bprm_secureexec (struct linux_binprm *bprm)
@@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
{
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
(current->uid != 0 && current->euid != 0 && current->suid != 0) &&
- !current->keep_capabilities) {
+ !issecure(SECURE_KEEP_CAPS)) {
cap_clear (current->cap_permitted);
cap_clear (current->cap_effective);
}
@@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice)
* this task could get inconsistent info. There can be no
* racing writer bc a task can only change its own caps.
*/
-long cap_prctl_drop(unsigned long cap)
+static long cap_prctl_drop(unsigned long cap)
{
if (!capable(CAP_SETPCAP))
return -EPERM;
@@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap)
cap_lower(current->cap_bset, cap);
return 0;
}
+
#else
int cap_task_setscheduler (struct task_struct *p, int policy,
struct sched_param *lp)
@@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice)
}
#endif
+int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5, long *rc_p)
+{
+ long error = 0;
+
+ switch (option) {
+ case PR_CAPBSET_READ:
+ if (!cap_valid(arg2))
+ error = -EINVAL;
+ else
+ error = !!cap_raised(current->cap_bset, arg2);
+ break;
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+ case PR_CAPBSET_DROP:
+ error = cap_prctl_drop(arg2);
+ break;
+
+ /*
+ * The next four prctl's remain to assist with transitioning a
+ * system from legacy UID=0 based privilege (when filesystem
+ * capabilities are not in use) to a system using filesystem
+ * capabilities only - as the POSIX.1e draft intended.
+ *
+ * Note:
+ *
+ * PR_SET_SECUREBITS =
+ * issecure_mask(SECURE_KEEP_CAPS_LOCKED)
+ * | issecure_mask(SECURE_NOROOT)
+ * | issecure_mask(SECURE_NOROOT_LOCKED)
+ * | issecure_mask(SECURE_NO_SETUID_FIXUP)
+ * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)
+ *
+ * will ensure that the current process and all of its
+ * children will be locked into a pure
+ * capability-based-privilege environment.
+ */
+ case PR_SET_SECUREBITS:
+ if ((((current->securebits & SECURE_ALL_LOCKS) >> 1)
+ & (current->securebits ^ arg2)) /*[1]*/
+ || ((current->securebits & SECURE_ALL_LOCKS
+ & ~arg2)) /*[2]*/
+ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
+ || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/
+ /*
+ * [1] no changing of bits that are locked
+ * [2] no unlocking of locks
+ * [3] no setting of unsupported bits
+ * [4] doing anything requires privilege (go read about
+ * the "sendmail capabilities bug")
+ */
+ error = -EPERM; /* cannot change a locked bit */
+ } else {
+ current->securebits = arg2;
+ }
+ break;
+ case PR_GET_SECUREBITS:
+ error = current->securebits;
+ break;
+
+#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
+
+ case PR_GET_KEEPCAPS:
+ if (issecure(SECURE_KEEP_CAPS))
+ error = 1;
+ break;
+ case PR_SET_KEEPCAPS:
+ if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
+ error = -EINVAL;
+ else if (issecure(SECURE_KEEP_CAPS_LOCKED))
+ error = -EPERM;
+ else if (arg2)
+ current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
+ else
+ current->securebits &=
+ ~issecure_mask(SECURE_KEEP_CAPS);
+ break;
+
+ default:
+ /* No functionality available - continue with default */
+ return 0;
+ }
+
+ /* Functionality provided */
+ *rc_p = error;
+ return 1;
+}
+
void cap_task_reparent_to_init (struct task_struct *p)
{
cap_set_init_eff(p->cap_effective);
cap_clear(p->cap_inheritable);
cap_set_full(p->cap_permitted);
- p->keep_capabilities = 0;
+ p->securebits = SECUREBITS_DEFAULT;
return;
}
diff --git a/security/dummy.c b/security/dummy.c
index b0232bbf427b..58d4dd1af5c7 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -604,7 +604,7 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info,
}
static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5)
+ unsigned long arg4, unsigned long arg5, long *rc_p)
{
return 0;
}
diff --git a/security/root_plug.c b/security/root_plug.c
index 6112d1404c81..a41cf42a4fa0 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -86,6 +86,7 @@ static struct security_operations rootplug_security_ops = {
.task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init,
+ .task_prctl = cap_task_prctl,
.bprm_check_security = rootplug_bprm_check_security,
};
diff --git a/security/security.c b/security/security.c
index 8a285c7b9962..d5cb5898d967 100644
--- a/security/security.c
+++ b/security/security.c
@@ -733,9 +733,9 @@ int security_task_wait(struct task_struct *p)
}
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5)
+ unsigned long arg4, unsigned long arg5, long *rc_p)
{
- return security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
+ return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
}
void security_task_reparent_to_init(struct task_struct *p)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 308e2cf17d75..04acb5af8317 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3303,12 +3303,13 @@ static int selinux_task_prctl(int option,
unsigned long arg2,
unsigned long arg3,
unsigned long arg4,
- unsigned long arg5)
+ unsigned long arg5,
+ long *rc_p)
{
/* The current prctl operations do not appear to require
any SELinux controls since they merely observe or modify
the state of the current process. */
- return 0;
+ return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
}
static int selinux_task_wait(struct task_struct *p)
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
index ff869e8b6f4a..c0d314d9f8e1 100644
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -10,22 +10,19 @@
int avc_ss_reset(u32 seqno);
-struct av_perm_to_string
-{
+struct av_perm_to_string {
u16 tclass;
u32 value;
const char *name;
};
-struct av_inherit
-{
+struct av_inherit {
u16 tclass;
const char **common_pts;
u32 common_base;
};
-struct selinux_class_perm
-{
+struct selinux_class_perm {
const struct av_perm_to_string *av_perm_to_string;
u32 av_pts_len;
const char **class_to_string;
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 9a9e7cd9a379..487a7d81fe20 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -64,7 +64,7 @@ static inline void selinux_netlbl_cache_invalidate(void)
}
static inline void selinux_netlbl_sk_security_reset(
- struct sk_security_struct *ssec,
+ struct sk_security_struct *ssec,
int family)
{
return;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 300b61bad7b3..032c2357dad1 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -4,16 +4,16 @@
* This file contains the SELinux security data structures for kernel objects.
*
* Author(s): Stephen Smalley, <sds@epoch.ncsc.mil>
- * Chris Vance, <cvance@nai.com>
- * Wayne Salamon, <wsalamon@nai.com>
- * James Morris <jmorris@redhat.com>
+ * Chris Vance, <cvance@nai.com>
+ * Wayne Salamon, <wsalamon@nai.com>
+ * James Morris <jmorris@redhat.com>
*
* Copyright (C) 2001,2002 Networks Associates Technology, Inc.
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.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.
+ * as published by the Free Software Foundation.
*/
#ifndef _SELINUX_OBJSEC_H_
#define _SELINUX_OBJSEC_H_
@@ -28,58 +28,58 @@
#include "avc.h"
struct task_security_struct {
- u32 osid; /* SID prior to last execve */
- u32 sid; /* current SID */
- u32 exec_sid; /* exec SID */
- u32 create_sid; /* fscreate SID */
- u32 keycreate_sid; /* keycreate SID */
- u32 sockcreate_sid; /* fscreate SID */
+ u32 osid; /* SID prior to last execve */
+ u32 sid; /* current SID */
+ u32 exec_sid; /* exec SID */
+ u32 create_sid; /* fscreate SID */
+ u32 keycreate_sid; /* keycreate SID */
+ u32 sockcreate_sid; /* fscreate SID */
};
struct inode_security_struct {
- struct inode *inode; /* back pointer to inode object */
- struct list_head list; /* list of inode_security_struct */
- u32 task_sid; /* SID of creating task */
- u32 sid; /* SID of this object */
- u16 sclass; /* security class of this object */
- unsigned char initialized; /* initialization flag */
+ struct inode *inode; /* back pointer to inode object */
+ struct list_head list; /* list of inode_security_struct */
+ u32 task_sid; /* SID of creating task */
+ u32 sid; /* SID of this object */
+ u16 sclass; /* security class of this object */
+ unsigned char initialized; /* initialization flag */
struct mutex lock;
- unsigned char inherit; /* inherit SID from parent entry */
+ unsigned char inherit; /* inherit SID from parent entry */
};
struct file_security_struct {
- u32 sid; /* SID of open file description */
- u32 fown_sid; /* SID of file owner (for SIGIO) */
- u32 isid; /* SID of inode at the time of file open */
- u32 pseqno; /* Policy seqno at the time of file open */
+ u32 sid; /* SID of open file description */
+ u32 fown_sid; /* SID of file owner (for SIGIO) */
+ u32 isid; /* SID of inode at the time of file open */
+ u32 pseqno; /* Policy seqno at the time of file open */
};
struct superblock_security_struct {
- struct super_block *sb; /* back pointer to sb object */
- struct list_head list; /* list of superblock_security_struct */
+ struct super_block *sb; /* back pointer to sb object */
+ struct list_head list; /* list of superblock_security_struct */
u32 sid; /* SID of file system superblock */
u32 def_sid; /* default SID for labeling */
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
- unsigned int behavior; /* labeling behavior */
- unsigned char initialized; /* initialization flag */
+ unsigned int behavior; /* labeling behavior */
+ unsigned char initialized; /* initialization flag */
unsigned char flags; /* which mount options were specified */
- unsigned char proc; /* proc fs */
+ unsigned char proc; /* proc fs */
struct mutex lock;
struct list_head isec_head;
spinlock_t isec_lock;
};
struct msg_security_struct {
- u32 sid; /* SID of message */
+ u32 sid; /* SID of message */
};
struct ipc_security_struct {
u16 sclass; /* security class of this object */
- u32 sid; /* SID of IPC resource */
+ u32 sid; /* SID of IPC resource */
};
struct bprm_security_struct {
- u32 sid; /* SID for transformed process */
+ u32 sid; /* SID for transformed process */
unsigned char set;
/*
@@ -123,7 +123,7 @@ struct sk_security_struct {
};
struct key_security_struct {
- u32 sid; /* SID of key */
+ u32 sid; /* SID of key */
};
extern unsigned int selinux_checkreqprot;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 1904c462a605..6445b6440648 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -62,7 +62,7 @@ enum {
extern int selinux_policycap_netpeer;
extern int selinux_policycap_openperm;
-int security_load_policy(void * data, size_t len);
+int security_load_policy(void *data, size_t len);
int security_policycap_supported(unsigned int req_cap);
@@ -110,7 +110,7 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
u32 *out_sid);
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
- u16 tclass);
+ u16 tclass);
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 2edc4c5e0c61..b6ccd09379f1 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -40,11 +40,17 @@
#include <net/ipv6.h>
#include <asm/bug.h>
+#include "netnode.h"
#include "objsec.h"
#define SEL_NETNODE_HASH_SIZE 256
#define SEL_NETNODE_HASH_BKT_LIMIT 16
+struct sel_netnode_bkt {
+ unsigned int size;
+ struct list_head list;
+};
+
struct sel_netnode {
struct netnode_security_struct nsec;
@@ -60,7 +66,7 @@ struct sel_netnode {
static LIST_HEAD(sel_netnode_list);
static DEFINE_SPINLOCK(sel_netnode_lock);
-static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
+static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
/**
* sel_netnode_free - Frees a node entry
@@ -87,7 +93,7 @@ static void sel_netnode_free(struct rcu_head *p)
* the bucket number for the given IP address.
*
*/
-static u32 sel_netnode_hashfn_ipv4(__be32 addr)
+static unsigned int sel_netnode_hashfn_ipv4(__be32 addr)
{
/* at some point we should determine if the mismatch in byte order
* affects the hash function dramatically */
@@ -103,7 +109,7 @@ static u32 sel_netnode_hashfn_ipv4(__be32 addr)
* the bucket number for the given IP address.
*
*/
-static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
+static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
{
/* just hash the least significant 32 bits to keep things fast (they
* are the most likely to be different anyway), we can revisit this
@@ -123,7 +129,7 @@ static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
*/
static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
{
- u32 idx;
+ unsigned int idx;
struct sel_netnode *node;
switch (family) {
@@ -137,7 +143,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
BUG();
}
- list_for_each_entry_rcu(node, &sel_netnode_hash[idx], list)
+ list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
if (node->nsec.family == family)
switch (family) {
case PF_INET:
@@ -159,15 +165,12 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
* @node: the new node record
*
* Description:
- * Add a new node record to the network address hash table. Returns zero on
- * success, negative values on failure.
+ * Add a new node record to the network address hash table.
*
*/
-static int sel_netnode_insert(struct sel_netnode *node)
+static void sel_netnode_insert(struct sel_netnode *node)
{
- u32 idx;
- u32 count = 0;
- struct sel_netnode *iter;
+ unsigned int idx;
switch (node->nsec.family) {
case PF_INET:
@@ -179,32 +182,21 @@ static int sel_netnode_insert(struct sel_netnode *node)
default:
BUG();
}
- list_add_rcu(&node->list, &sel_netnode_hash[idx]);
+
+ INIT_RCU_HEAD(&node->rcu);
/* we need to impose a limit on the growth of the hash table so check
* this bucket to make sure it is within the specified bounds */
- list_for_each_entry(iter, &sel_netnode_hash[idx], list)
- if (++count > SEL_NETNODE_HASH_BKT_LIMIT) {
- list_del_rcu(&iter->list);
- call_rcu(&iter->rcu, sel_netnode_free);
- break;
- }
-
- return 0;
-}
-
-/**
- * sel_netnode_destroy - Remove a node record from the table
- * @node: the existing node record
- *
- * Description:
- * Remove an existing node record from the network address table.
- *
- */
-static void sel_netnode_destroy(struct sel_netnode *node)
-{
- list_del_rcu(&node->list);
- call_rcu(&node->rcu, sel_netnode_free);
+ list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
+ if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
+ struct sel_netnode *tail;
+ tail = list_entry(
+ rcu_dereference(sel_netnode_hash[idx].list.prev),
+ struct sel_netnode, list);
+ list_del_rcu(&tail->list);
+ call_rcu(&tail->rcu, sel_netnode_free);
+ } else
+ sel_netnode_hash[idx].size++;
}
/**
@@ -222,7 +214,7 @@ static void sel_netnode_destroy(struct sel_netnode *node)
*/
static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
{
- int ret;
+ int ret = -ENOMEM;
struct sel_netnode *node;
struct sel_netnode *new = NULL;
@@ -230,25 +222,21 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
node = sel_netnode_find(addr, family);
if (node != NULL) {
*sid = node->nsec.sid;
- ret = 0;
- goto out;
+ spin_unlock_bh(&sel_netnode_lock);
+ return 0;
}
new = kzalloc(sizeof(*new), GFP_ATOMIC);
- if (new == NULL) {
- ret = -ENOMEM;
+ if (new == NULL)
goto out;
- }
switch (family) {
case PF_INET:
ret = security_node_sid(PF_INET,
- addr, sizeof(struct in_addr),
- &new->nsec.sid);
+ addr, sizeof(struct in_addr), sid);
new->nsec.addr.ipv4 = *(__be32 *)addr;
break;
case PF_INET6:
ret = security_node_sid(PF_INET6,
- addr, sizeof(struct in6_addr),
- &new->nsec.sid);
+ addr, sizeof(struct in6_addr), sid);
ipv6_addr_copy(&new->nsec.addr.ipv6, addr);
break;
default:
@@ -256,11 +244,10 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
}
if (ret != 0)
goto out;
+
new->nsec.family = family;
- ret = sel_netnode_insert(new);
- if (ret != 0)
- goto out;
- *sid = new->nsec.sid;
+ new->nsec.sid = *sid;
+ sel_netnode_insert(new);
out:
spin_unlock_bh(&sel_netnode_lock);
@@ -312,13 +299,18 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid)
*/
static void sel_netnode_flush(void)
{
- u32 idx;
- struct sel_netnode *node;
+ unsigned int idx;
+ struct sel_netnode *node, *node_tmp;
spin_lock_bh(&sel_netnode_lock);
- for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++)
- list_for_each_entry(node, &sel_netnode_hash[idx], list)
- sel_netnode_destroy(node);
+ for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) {
+ list_for_each_entry_safe(node, node_tmp,
+ &sel_netnode_hash[idx].list, list) {
+ list_del_rcu(&node->list);
+ call_rcu(&node->rcu, sel_netnode_free);
+ }
+ sel_netnode_hash[idx].size = 0;
+ }
spin_unlock_bh(&sel_netnode_lock);
}
@@ -340,8 +332,10 @@ static __init int sel_netnode_init(void)
if (!selinux_enabled)
return 0;
- for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++)
- INIT_LIST_HEAD(&sel_netnode_hash[iter]);
+ for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) {
+ INIT_LIST_HEAD(&sel_netnode_hash[iter].list);
+ sel_netnode_hash[iter].size = 0;
+ }
ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET,
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 68ede3c498ab..90b4cff7c350 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -114,8 +114,7 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
idx = sel_netport_hashfn(pnum);
list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
- if (port->psec.port == pnum &&
- port->psec.protocol == protocol)
+ if (port->psec.port == pnum && port->psec.protocol == protocol)
return port;
return NULL;
@@ -126,11 +125,10 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
* @port: the new port record
*
* Description:
- * Add a new port record to the network address hash table. Returns zero on
- * success, negative values on failure.
+ * Add a new port record to the network address hash table.
*
*/
-static int sel_netport_insert(struct sel_netport *port)
+static void sel_netport_insert(struct sel_netport *port)
{
unsigned int idx;
@@ -140,13 +138,13 @@ static int sel_netport_insert(struct sel_netport *port)
list_add_rcu(&port->list, &sel_netport_hash[idx].list);
if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
struct sel_netport *tail;
- tail = list_entry(port->list.prev, struct sel_netport, list);
- list_del_rcu(port->list.prev);
+ tail = list_entry(
+ rcu_dereference(sel_netport_hash[idx].list.prev),
+ struct sel_netport, list);
+ list_del_rcu(&tail->list);
call_rcu(&tail->rcu, sel_netport_free);
} else
sel_netport_hash[idx].size++;
-
- return 0;
}
/**
@@ -163,7 +161,7 @@ static int sel_netport_insert(struct sel_netport *port)
*/
static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
{
- int ret;
+ int ret = -ENOMEM;
struct sel_netport *port;
struct sel_netport *new = NULL;
@@ -171,23 +169,20 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
port = sel_netport_find(protocol, pnum);
if (port != NULL) {
*sid = port->psec.sid;
- ret = 0;
- goto out;
+ spin_unlock_bh(&sel_netport_lock);
+ return 0;
}
new = kzalloc(sizeof(*new), GFP_ATOMIC);
- if (new == NULL) {
- ret = -ENOMEM;
+ if (new == NULL)
goto out;
- }
- ret = security_port_sid(protocol, pnum, &new->psec.sid);
+ ret = security_port_sid(protocol, pnum, sid);
if (ret != 0)
goto out;
+
new->psec.port = pnum;
new->psec.protocol = protocol;
- ret = sel_netport_insert(new);
- if (ret != 0)
- goto out;
- *sid = new->psec.sid;
+ new->psec.sid = *sid;
+ sel_netport_insert(new);
out:
spin_unlock_bh(&sel_netport_lock);
@@ -239,11 +234,12 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
static void sel_netport_flush(void)
{
unsigned int idx;
- struct sel_netport *port;
+ struct sel_netport *port, *port_tmp;
spin_lock_bh(&sel_netport_lock);
for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
- list_for_each_entry(port, &sel_netport_hash[idx].list, list) {
+ list_for_each_entry_safe(port, port_tmp,
+ &sel_netport_hash[idx].list, list) {
list_del_rcu(&port->list);
call_rcu(&port->rcu, sel_netport_free);
}
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
index f3a1fc6e5d66..65b9f8366e9c 100644
--- a/security/selinux/ss/conditional.h
+++ b/security/selinux/ss/conditional.h
@@ -59,10 +59,10 @@ struct cond_node {
struct cond_node *next;
};
-int cond_policydb_init(struct policydb* p);
-void cond_policydb_destroy(struct policydb* p);
+int cond_policydb_init(struct policydb *p);
+void cond_policydb_destroy(struct policydb *p);
-int cond_init_bool_indexes(struct policydb* p);
+int cond_init_bool_indexes(struct policydb *p);
int cond_destroy_bool(void *key, void *datum, void *p);
int cond_index_bool(void *key, void *datum, void *datap);
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index 2eee0dab524d..b9a6f7fc62fc 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -84,9 +84,9 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2)
return 1;
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
- ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
+ ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
(c1->range.level[1].sens == c2->range.level[1].sens) &&
- ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat));
+ ebitmap_cmp(&c1->range.level[1].cat, &c2->range.level[1].cat));
}
static inline void mls_context_destroy(struct context *c)
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h
index 7e2ff3e3c6d2..953872cd84ab 100644
--- a/security/selinux/ss/hashtab.h
+++ b/security/selinux/ss/hashtab.h
@@ -40,8 +40,8 @@ struct hashtab_info {
* the new hash table otherwise.
*/
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
- int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
- u32 size);
+ int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
+ u32 size);
/*
* Inserts the specified (key, datum) pair into the specified hash table.
@@ -49,7 +49,7 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *
* Returns -ENOMEM on memory allocation error,
* -EEXIST if there is already an entry with the same key,
* -EINVAL for general errors or
- * 0 otherwise.
+ 0 otherwise.
*/
int hashtab_insert(struct hashtab *h, void *k, void *d);
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index ab53663d9f5f..0fdf6257ef64 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -13,7 +13,7 @@
/*
* Updated: Hewlett-Packard <paul.moore@hp.com>
*
- * Added support to import/export the MLS label from NetLabel
+ * Added support to import/export the MLS label from NetLabel
*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
@@ -31,7 +31,7 @@ int mls_range_isvalid(struct policydb *p, struct mls_range *r);
int mls_level_isvalid(struct policydb *p, struct mls_level *l);
int mls_context_to_sid(char oldc,
- char **scontext,
+ char **scontext,
struct context *context,
struct sidtab *s,
u32 def_sid);
@@ -49,7 +49,7 @@ int mls_compute_sid(struct context *scontext,
struct context *newcontext);
int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
- struct context *usercon);
+ struct context *usercon);
#ifdef CONFIG_NETLABEL
void mls_export_netlbl_lvl(struct context *context,
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h
index 0c692d58d489..b6e943a21061 100644
--- a/security/selinux/ss/mls_types.h
+++ b/security/selinux/ss/mls_types.h
@@ -31,7 +31,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
return 1;
return ((l1->sens == l2->sens) &&
- ebitmap_cmp(&l1->cat, &l2->cat));
+ ebitmap_cmp(&l1->cat, &l2->cat));
}
static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
@@ -40,7 +40,7 @@ static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
return 1;
return ((l1->sens >= l2->sens) &&
- ebitmap_contains(&l1->cat, &l2->cat));
+ ebitmap_contains(&l1->cat, &l2->cat));
}
#define mls_level_incomp(l1, l2) \
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index ba593a3da877..4253370fda6a 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -12,12 +12,12 @@
*
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
- * Added conditional policy language extensions
+ * Added conditional policy language extensions
*
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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
+ * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*/
@@ -221,7 +221,7 @@ struct policydb {
/* type enforcement conditional access vectors and transitions */
struct avtab te_cond_avtab;
/* linked list indexing te_cond_avtab by conditional */
- struct cond_node* cond_list;
+ struct cond_node *cond_list;
/* role allows */
struct role_allow *role_allow;
@@ -230,10 +230,10 @@ struct policydb {
TCP or UDP port numbers, network interfaces and nodes */
struct ocontext *ocontexts[OCON_NUM];
- /* security contexts for files in filesystems that cannot support
+ /* security contexts for files in filesystems that cannot support
a persistent label mapping or use another
fixed labeling behavior. */
- struct genfs *genfs;
+ struct genfs *genfs;
/* range transitions */
struct range_trans *range_tr;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 4215971434e6..77ec16a3b68b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1242,7 +1242,7 @@ static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap)
int rc;
int byte;
- if (catset == 0)
+ if (!catset)
return;
sap->flags |= NETLBL_SECATTR_MLS_CAT;
@@ -2495,6 +2495,7 @@ struct security_operations smack_ops = {
.task_wait = smack_task_wait,
.task_reparent_to_init = cap_task_reparent_to_init,
.task_to_inode = smack_task_to_inode,
+ .task_prctl = cap_task_prctl,
.ipc_permission = smack_ipc_permission,
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 6ba283783b70..a5da5a8cfe9b 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -317,7 +317,7 @@ static const struct file_operations smk_load_ops = {
/**
* smk_cipso_doi - initialize the CIPSO domain
*/
-void smk_cipso_doi(void)
+static void smk_cipso_doi(void)
{
int rc;
struct cipso_v4_doi *doip;
@@ -350,7 +350,7 @@ void smk_cipso_doi(void)
/**
* smk_unlbl_ambient - initialize the unlabeled domain
*/
-void smk_unlbl_ambient(char *oldambient)
+static void smk_unlbl_ambient(char *oldambient)
{
int rc;
struct netlbl_audit audit_info;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index b2e12893e3f4..c82cf15730a1 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -40,6 +40,7 @@
#include <linux/kvm_para.h>
#include <linux/pagemap.h>
#include <linux/mman.h>
+#include <linux/swap.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -59,7 +60,7 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
static __read_mostly struct preempt_ops kvm_preempt_ops;
-static struct dentry *debugfs_dir;
+struct dentry *kvm_debugfs_dir;
static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
unsigned long arg);
@@ -119,6 +120,29 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
smp_call_function_mask(cpus, ack_flush, NULL, 1);
}
+void kvm_reload_remote_mmus(struct kvm *kvm)
+{
+ int i, cpu;
+ cpumask_t cpus;
+ struct kvm_vcpu *vcpu;
+
+ cpus_clear(cpus);
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
+ continue;
+ cpu = vcpu->cpu;
+ if (cpu != -1 && cpu != raw_smp_processor_id())
+ cpu_set(cpu, cpus);
+ }
+ if (cpus_empty(cpus))
+ return;
+ smp_call_function_mask(cpus, ack_flush, NULL, 1);
+}
+
+
int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
{
struct page *page;
@@ -170,6 +194,7 @@ static struct kvm *kvm_create_vm(void)
mutex_init(&kvm->lock);
kvm_io_bus_init(&kvm->mmio_bus);
init_rwsem(&kvm->slots_lock);
+ atomic_set(&kvm->users_count, 1);
spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
@@ -189,9 +214,13 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
vfree(free->dirty_bitmap);
+ if (!dont || free->lpage_info != dont->lpage_info)
+ vfree(free->lpage_info);
+
free->npages = 0;
free->dirty_bitmap = NULL;
free->rmap = NULL;
+ free->lpage_info = NULL;
}
void kvm_free_physmem(struct kvm *kvm)
@@ -215,11 +244,25 @@ static void kvm_destroy_vm(struct kvm *kvm)
mmdrop(mm);
}
+void kvm_get_kvm(struct kvm *kvm)
+{
+ atomic_inc(&kvm->users_count);
+}
+EXPORT_SYMBOL_GPL(kvm_get_kvm);
+
+void kvm_put_kvm(struct kvm *kvm)
+{
+ if (atomic_dec_and_test(&kvm->users_count))
+ kvm_destroy_vm(kvm);
+}
+EXPORT_SYMBOL_GPL(kvm_put_kvm);
+
+
static int kvm_vm_release(struct inode *inode, struct file *filp)
{
struct kvm *kvm = filp->private_data;
- kvm_destroy_vm(kvm);
+ kvm_put_kvm(kvm);
return 0;
}
@@ -301,6 +344,25 @@ int __kvm_set_memory_region(struct kvm *kvm,
new.user_alloc = user_alloc;
new.userspace_addr = mem->userspace_addr;
}
+ if (npages && !new.lpage_info) {
+ int largepages = npages / KVM_PAGES_PER_HPAGE;
+ if (npages % KVM_PAGES_PER_HPAGE)
+ largepages++;
+ if (base_gfn % KVM_PAGES_PER_HPAGE)
+ largepages++;
+
+ new.lpage_info = vmalloc(largepages * sizeof(*new.lpage_info));
+
+ if (!new.lpage_info)
+ goto out_free;
+
+ memset(new.lpage_info, 0, largepages * sizeof(*new.lpage_info));
+
+ if (base_gfn % KVM_PAGES_PER_HPAGE)
+ new.lpage_info[0].write_count = 1;
+ if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE)
+ new.lpage_info[largepages-1].write_count = 1;
+ }
/* Allocate page dirty bitmap if needed */
if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
@@ -397,6 +459,12 @@ int is_error_page(struct page *page)
}
EXPORT_SYMBOL_GPL(is_error_page);
+int is_error_pfn(pfn_t pfn)
+{
+ return pfn == bad_pfn;
+}
+EXPORT_SYMBOL_GPL(is_error_pfn);
+
static inline unsigned long bad_hva(void)
{
return PAGE_OFFSET;
@@ -444,7 +512,7 @@ int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
}
EXPORT_SYMBOL_GPL(kvm_is_visible_gfn);
-static unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
+unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
{
struct kvm_memory_slot *slot;
@@ -458,7 +526,7 @@ static unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
/*
* Requires current->mm->mmap_sem to be held
*/
-struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
+pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
{
struct page *page[1];
unsigned long addr;
@@ -469,7 +537,7 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
addr = gfn_to_hva(kvm, gfn);
if (kvm_is_error_hva(addr)) {
get_page(bad_page);
- return bad_page;
+ return page_to_pfn(bad_page);
}
npages = get_user_pages(current, current->mm, addr, 1, 1, 1, page,
@@ -477,27 +545,71 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
if (npages != 1) {
get_page(bad_page);
- return bad_page;
+ return page_to_pfn(bad_page);
}
- return page[0];
+ return page_to_pfn(page[0]);
+}
+
+EXPORT_SYMBOL_GPL(gfn_to_pfn);
+
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
+{
+ return pfn_to_page(gfn_to_pfn(kvm, gfn));
}
EXPORT_SYMBOL_GPL(gfn_to_page);
void kvm_release_page_clean(struct page *page)
{
- put_page(page);
+ kvm_release_pfn_clean(page_to_pfn(page));
}
EXPORT_SYMBOL_GPL(kvm_release_page_clean);
+void kvm_release_pfn_clean(pfn_t pfn)
+{
+ put_page(pfn_to_page(pfn));
+}
+EXPORT_SYMBOL_GPL(kvm_release_pfn_clean);
+
void kvm_release_page_dirty(struct page *page)
{
+ kvm_release_pfn_dirty(page_to_pfn(page));
+}
+EXPORT_SYMBOL_GPL(kvm_release_page_dirty);
+
+void kvm_release_pfn_dirty(pfn_t pfn)
+{
+ kvm_set_pfn_dirty(pfn);
+ kvm_release_pfn_clean(pfn);
+}
+EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty);
+
+void kvm_set_page_dirty(struct page *page)
+{
+ kvm_set_pfn_dirty(page_to_pfn(page));
+}
+EXPORT_SYMBOL_GPL(kvm_set_page_dirty);
+
+void kvm_set_pfn_dirty(pfn_t pfn)
+{
+ struct page *page = pfn_to_page(pfn);
if (!PageReserved(page))
SetPageDirty(page);
- put_page(page);
}
-EXPORT_SYMBOL_GPL(kvm_release_page_dirty);
+EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty);
+
+void kvm_set_pfn_accessed(pfn_t pfn)
+{
+ mark_page_accessed(pfn_to_page(pfn));
+}
+EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed);
+
+void kvm_get_pfn(pfn_t pfn)
+{
+ get_page(pfn_to_page(pfn));
+}
+EXPORT_SYMBOL_GPL(kvm_get_pfn);
static int next_segment(unsigned long len, int offset)
{
@@ -554,7 +666,9 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
addr = gfn_to_hva(kvm, gfn);
if (kvm_is_error_hva(addr))
return -EFAULT;
+ pagefault_disable();
r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len);
+ pagefault_enable();
if (r)
return -EFAULT;
return 0;
@@ -651,6 +765,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
* We will block until either an interrupt or a signal wakes us up
*/
while (!kvm_cpu_has_interrupt(vcpu)
+ && !kvm_cpu_has_pending_timer(vcpu)
&& !signal_pending(current)
&& !kvm_arch_vcpu_runnable(vcpu)) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -678,8 +793,10 @@ static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (vmf->pgoff == 0)
page = virt_to_page(vcpu->run);
+#ifdef CONFIG_X86
else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET)
page = virt_to_page(vcpu->arch.pio_data);
+#endif
else
return VM_FAULT_SIGBUS;
get_page(page);
@@ -701,11 +818,11 @@ static int kvm_vcpu_release(struct inode *inode, struct file *filp)
{
struct kvm_vcpu *vcpu = filp->private_data;
- fput(vcpu->kvm->filp);
+ kvm_put_kvm(vcpu->kvm);
return 0;
}
-static struct file_operations kvm_vcpu_fops = {
+static const struct file_operations kvm_vcpu_fops = {
.release = kvm_vcpu_release,
.unlocked_ioctl = kvm_vcpu_ioctl,
.compat_ioctl = kvm_vcpu_ioctl,
@@ -723,9 +840,10 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu)
r = anon_inode_getfd(&fd, &inode, &file,
"kvm-vcpu", &kvm_vcpu_fops, vcpu);
- if (r)
+ if (r) {
+ kvm_put_kvm(vcpu->kvm);
return r;
- atomic_inc(&vcpu->kvm->filp->f_count);
+ }
return fd;
}
@@ -760,6 +878,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
mutex_unlock(&kvm->lock);
/* Now it's all set up, let userspace reach it */
+ kvm_get_kvm(kvm);
r = create_vcpu_fd(vcpu);
if (r < 0)
goto unlink;
@@ -802,28 +921,39 @@ static long kvm_vcpu_ioctl(struct file *filp,
r = kvm_arch_vcpu_ioctl_run(vcpu, vcpu->run);
break;
case KVM_GET_REGS: {
- struct kvm_regs kvm_regs;
+ struct kvm_regs *kvm_regs;
- memset(&kvm_regs, 0, sizeof kvm_regs);
- r = kvm_arch_vcpu_ioctl_get_regs(vcpu, &kvm_regs);
- if (r)
+ r = -ENOMEM;
+ kvm_regs = kzalloc(sizeof(struct kvm_regs), GFP_KERNEL);
+ if (!kvm_regs)
goto out;
+ r = kvm_arch_vcpu_ioctl_get_regs(vcpu, kvm_regs);
+ if (r)
+ goto out_free1;
r = -EFAULT;
- if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs))
- goto out;
+ if (copy_to_user(argp, kvm_regs, sizeof(struct kvm_regs)))
+ goto out_free1;
r = 0;
+out_free1:
+ kfree(kvm_regs);
break;
}
case KVM_SET_REGS: {
- struct kvm_regs kvm_regs;
+ struct kvm_regs *kvm_regs;
- r = -EFAULT;
- if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
+ r = -ENOMEM;
+ kvm_regs = kzalloc(sizeof(struct kvm_regs), GFP_KERNEL);
+ if (!kvm_regs)
goto out;
- r = kvm_arch_vcpu_ioctl_set_regs(vcpu, &kvm_regs);
+ r = -EFAULT;
+ if (copy_from_user(kvm_regs, argp, sizeof(struct kvm_regs)))
+ goto out_free2;
+ r = kvm_arch_vcpu_ioctl_set_regs(vcpu, kvm_regs);
if (r)
- goto out;
+ goto out_free2;
r = 0;
+out_free2:
+ kfree(kvm_regs);
break;
}
case KVM_GET_SREGS: {
@@ -851,6 +981,30 @@ static long kvm_vcpu_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_GET_MP_STATE: {
+ struct kvm_mp_state mp_state;
+
+ r = kvm_arch_vcpu_ioctl_get_mpstate(vcpu, &mp_state);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &mp_state, sizeof mp_state))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_MP_STATE: {
+ struct kvm_mp_state mp_state;
+
+ r = -EFAULT;
+ if (copy_from_user(&mp_state, argp, sizeof mp_state))
+ goto out;
+ r = kvm_arch_vcpu_ioctl_set_mpstate(vcpu, &mp_state);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
case KVM_TRANSLATE: {
struct kvm_translation tr;
@@ -1005,7 +1159,7 @@ static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations kvm_vm_fops = {
+static const struct file_operations kvm_vm_fops = {
.release = kvm_vm_release,
.unlocked_ioctl = kvm_vm_ioctl,
.compat_ioctl = kvm_vm_ioctl,
@@ -1024,12 +1178,10 @@ static int kvm_dev_ioctl_create_vm(void)
return PTR_ERR(kvm);
r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
if (r) {
- kvm_destroy_vm(kvm);
+ kvm_put_kvm(kvm);
return r;
}
- kvm->filp = file;
-
return fd;
}
@@ -1059,7 +1211,15 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EINVAL;
if (arg)
goto out;
- r = 2 * PAGE_SIZE;
+ r = PAGE_SIZE; /* struct kvm_run */
+#ifdef CONFIG_X86
+ r += PAGE_SIZE; /* pio data page */
+#endif
+ break;
+ case KVM_TRACE_ENABLE:
+ case KVM_TRACE_PAUSE:
+ case KVM_TRACE_DISABLE:
+ r = kvm_trace_ioctl(ioctl, arg);
break;
default:
return kvm_arch_dev_ioctl(filp, ioctl, arg);
@@ -1232,9 +1392,9 @@ static void kvm_init_debug(void)
{
struct kvm_stats_debugfs_item *p;
- debugfs_dir = debugfs_create_dir("kvm", NULL);
+ kvm_debugfs_dir = debugfs_create_dir("kvm", NULL);
for (p = debugfs_entries; p->name; ++p)
- p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir,
+ p->dentry = debugfs_create_file(p->name, 0444, kvm_debugfs_dir,
(void *)(long)p->offset,
stat_fops[p->kind]);
}
@@ -1245,7 +1405,7 @@ static void kvm_exit_debug(void)
for (p = debugfs_entries; p->name; ++p)
debugfs_remove(p->dentry);
- debugfs_remove(debugfs_dir);
+ debugfs_remove(kvm_debugfs_dir);
}
static int kvm_suspend(struct sys_device *dev, pm_message_t state)
@@ -1272,6 +1432,7 @@ static struct sys_device kvm_sysdev = {
};
struct page *bad_page;
+pfn_t bad_pfn;
static inline
struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
@@ -1313,6 +1474,8 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
goto out;
}
+ bad_pfn = page_to_pfn(bad_page);
+
r = kvm_arch_hardware_setup();
if (r < 0)
goto out_free_0;
@@ -1386,6 +1549,7 @@ EXPORT_SYMBOL_GPL(kvm_init);
void kvm_exit(void)
{
+ kvm_trace_cleanup();
misc_deregister(&kvm_dev);
kmem_cache_destroy(kvm_vcpu_cache);
sysdev_unregister(&kvm_sysdev);
diff --git a/virt/kvm/kvm_trace.c b/virt/kvm/kvm_trace.c
new file mode 100644
index 000000000000..0e495470788d
--- /dev/null
+++ b/virt/kvm/kvm_trace.c
@@ -0,0 +1,276 @@
+/*
+ * kvm trace
+ *
+ * It is designed to allow debugging traces of kvm to be generated
+ * on UP / SMP machines. Each trace entry can be timestamped so that
+ * it's possible to reconstruct a chronological record of trace events.
+ * The implementation refers to blktrace kernel support.
+ *
+ * Copyright (c) 2008 Intel Corporation
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
+ *
+ * Authors: Feng(Eric) Liu, eric.e.liu@intel.com
+ *
+ * Date: Feb 2008
+ */
+
+#include <linux/module.h>
+#include <linux/relay.h>
+#include <linux/debugfs.h>
+
+#include <linux/kvm_host.h>
+
+#define KVM_TRACE_STATE_RUNNING (1 << 0)
+#define KVM_TRACE_STATE_PAUSE (1 << 1)
+#define KVM_TRACE_STATE_CLEARUP (1 << 2)
+
+struct kvm_trace {
+ int trace_state;
+ struct rchan *rchan;
+ struct dentry *lost_file;
+ atomic_t lost_records;
+};
+static struct kvm_trace *kvm_trace;
+
+struct kvm_trace_probe {
+ const char *name;
+ const char *format;
+ u32 cycle_in;
+ marker_probe_func *probe_func;
+};
+
+static inline int calc_rec_size(int cycle, int extra)
+{
+ int rec_size = KVM_TRC_HEAD_SIZE;
+
+ rec_size += extra;
+ return cycle ? rec_size += KVM_TRC_CYCLE_SIZE : rec_size;
+}
+
+static void kvm_add_trace(void *probe_private, void *call_data,
+ const char *format, va_list *args)
+{
+ struct kvm_trace_probe *p = probe_private;
+ struct kvm_trace *kt = kvm_trace;
+ struct kvm_trace_rec rec;
+ struct kvm_vcpu *vcpu;
+ int i, extra, size;
+
+ if (unlikely(kt->trace_state != KVM_TRACE_STATE_RUNNING))
+ return;
+
+ rec.event = va_arg(*args, u32);
+ vcpu = va_arg(*args, struct kvm_vcpu *);
+ rec.pid = current->tgid;
+ rec.vcpu_id = vcpu->vcpu_id;
+
+ extra = va_arg(*args, u32);
+ WARN_ON(!(extra <= KVM_TRC_EXTRA_MAX));
+ extra = min_t(u32, extra, KVM_TRC_EXTRA_MAX);
+ rec.extra_u32 = extra;
+
+ rec.cycle_in = p->cycle_in;
+
+ if (rec.cycle_in) {
+ u64 cycle = 0;
+
+ cycle = get_cycles();
+ rec.u.cycle.cycle_lo = (u32)cycle;
+ rec.u.cycle.cycle_hi = (u32)(cycle >> 32);
+
+ for (i = 0; i < rec.extra_u32; i++)
+ rec.u.cycle.extra_u32[i] = va_arg(*args, u32);
+ } else {
+ for (i = 0; i < rec.extra_u32; i++)
+ rec.u.nocycle.extra_u32[i] = va_arg(*args, u32);
+ }
+
+ size = calc_rec_size(rec.cycle_in, rec.extra_u32 * sizeof(u32));
+ relay_write(kt->rchan, &rec, size);
+}
+
+static struct kvm_trace_probe kvm_trace_probes[] = {
+ { "kvm_trace_entryexit", "%u %p %u %u %u %u %u %u", 1, kvm_add_trace },
+ { "kvm_trace_handler", "%u %p %u %u %u %u %u %u", 0, kvm_add_trace },
+};
+
+static int lost_records_get(void *data, u64 *val)
+{
+ struct kvm_trace *kt = data;
+
+ *val = atomic_read(&kt->lost_records);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(kvm_trace_lost_ops, lost_records_get, NULL, "%llu\n");
+
+/*
+ * The relay channel is used in "no-overwrite" mode, it keeps trace of how
+ * many times we encountered a full subbuffer, to tell user space app the
+ * lost records there were.
+ */
+static int kvm_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
+ void *prev_subbuf, size_t prev_padding)
+{
+ struct kvm_trace *kt;
+
+ if (!relay_buf_full(buf))
+ return 1;
+
+ kt = buf->chan->private_data;
+ atomic_inc(&kt->lost_records);
+
+ return 0;
+}
+
+static struct dentry *kvm_create_buf_file_callack(const char *filename,
+ struct dentry *parent,
+ int mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ return debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+}
+
+static int kvm_remove_buf_file_callback(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+ return 0;
+}
+
+static struct rchan_callbacks kvm_relay_callbacks = {
+ .subbuf_start = kvm_subbuf_start_callback,
+ .create_buf_file = kvm_create_buf_file_callack,
+ .remove_buf_file = kvm_remove_buf_file_callback,
+};
+
+static int do_kvm_trace_enable(struct kvm_user_trace_setup *kuts)
+{
+ struct kvm_trace *kt;
+ int i, r = -ENOMEM;
+
+ if (!kuts->buf_size || !kuts->buf_nr)
+ return -EINVAL;
+
+ kt = kzalloc(sizeof(*kt), GFP_KERNEL);
+ if (!kt)
+ goto err;
+
+ r = -EIO;
+ atomic_set(&kt->lost_records, 0);
+ kt->lost_file = debugfs_create_file("lost_records", 0444, kvm_debugfs_dir,
+ kt, &kvm_trace_lost_ops);
+ if (!kt->lost_file)
+ goto err;
+
+ kt->rchan = relay_open("trace", kvm_debugfs_dir, kuts->buf_size,
+ kuts->buf_nr, &kvm_relay_callbacks, kt);
+ if (!kt->rchan)
+ goto err;
+
+ kvm_trace = kt;
+
+ for (i = 0; i < ARRAY_SIZE(kvm_trace_probes); i++) {
+ struct kvm_trace_probe *p = &kvm_trace_probes[i];
+
+ r = marker_probe_register(p->name, p->format, p->probe_func, p);
+ if (r)
+ printk(KERN_INFO "Unable to register probe %s\n",
+ p->name);
+ }
+
+ kvm_trace->trace_state = KVM_TRACE_STATE_RUNNING;
+
+ return 0;
+err:
+ if (kt) {
+ if (kt->lost_file)
+ debugfs_remove(kt->lost_file);
+ if (kt->rchan)
+ relay_close(kt->rchan);
+ kfree(kt);
+ }
+ return r;
+}
+
+static int kvm_trace_enable(char __user *arg)
+{
+ struct kvm_user_trace_setup kuts;
+ int ret;
+
+ ret = copy_from_user(&kuts, arg, sizeof(kuts));
+ if (ret)
+ return -EFAULT;
+
+ ret = do_kvm_trace_enable(&kuts);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int kvm_trace_pause(void)
+{
+ struct kvm_trace *kt = kvm_trace;
+ int r = -EINVAL;
+
+ if (kt == NULL)
+ return r;
+
+ if (kt->trace_state == KVM_TRACE_STATE_RUNNING) {
+ kt->trace_state = KVM_TRACE_STATE_PAUSE;
+ relay_flush(kt->rchan);
+ r = 0;
+ }
+
+ return r;
+}
+
+void kvm_trace_cleanup(void)
+{
+ struct kvm_trace *kt = kvm_trace;
+ int i;
+
+ if (kt == NULL)
+ return;
+
+ if (kt->trace_state == KVM_TRACE_STATE_RUNNING ||
+ kt->trace_state == KVM_TRACE_STATE_PAUSE) {
+
+ kt->trace_state = KVM_TRACE_STATE_CLEARUP;
+
+ for (i = 0; i < ARRAY_SIZE(kvm_trace_probes); i++) {
+ struct kvm_trace_probe *p = &kvm_trace_probes[i];
+ marker_probe_unregister(p->name, p->probe_func, p);
+ }
+
+ relay_close(kt->rchan);
+ debugfs_remove(kt->lost_file);
+ kfree(kt);
+ }
+}
+
+int kvm_trace_ioctl(unsigned int ioctl, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ long r = -EINVAL;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ switch (ioctl) {
+ case KVM_TRACE_ENABLE:
+ r = kvm_trace_enable(argp);
+ break;
+ case KVM_TRACE_PAUSE:
+ r = kvm_trace_pause();
+ break;
+ case KVM_TRACE_DISABLE:
+ r = 0;
+ kvm_trace_cleanup();
+ break;
+ }
+
+ return r;
+}